From 52d50581c613d84392f5ba44cfef5c3aa0cf284e Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 9 Feb 2017 22:33:42 +0000 Subject: [PATCH 001/153] hillslope_hydrology_n01_clm4_5_14_r223 first set of changes for hillslope hydrology global implementation --- src/biogeophys/BalanceCheckMod.F90 | 17 +- src/biogeophys/HydrologyDrainageMod.F90 | 50 +- src/biogeophys/HydrologyNoDrainageMod.F90 | 22 +- src/biogeophys/SoilHydrologyMod.F90 | 567 +++++++++++++++++++++- src/biogeophys/WaterStateType.F90 | 7 +- src/biogeophys/WaterfluxType.F90 | 20 + src/main/ColumnType.F90 | 29 +- src/main/GridcellType.F90 | 3 + src/main/LandunitType.F90 | 3 + src/main/clm_driver.F90 | 25 +- src/main/clm_initializeMod.F90 | 23 +- src/main/clm_varctl.F90 | 24 + src/main/clm_varsur.F90 | 4 + src/main/controlMod.F90 | 17 + src/main/decompInitMod.F90 | 1 + src/main/filterMod.F90 | 59 ++- src/main/histFileMod.F90 | 60 ++- src/main/initGridCellsMod.F90 | 25 +- src/main/initSubgridMod.F90 | 5 + src/main/initVerticalMod.F90 | 290 ++++++++++- src/main/subgridMod.F90 | 21 +- src/main/surfrdMod.F90 | 58 ++- 22 files changed, 1251 insertions(+), 79 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index c2c5b03ce1..f49885193e 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -152,7 +152,7 @@ subroutine BalanceCheck( bounds, & use clm_varcon , only : spval use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_perv, icol_road_imperv - use landunit_varcon , only : istdlak, istsoil,istcrop,istwet,istice,istice_mec + use landunit_varcon , only : istdlak, istsoil,istcrop,istwet use clm_varctl , only : create_glacier_mec_landunit use clm_time_manager , only : get_step_size, get_nstep use clm_initializeMod , only : surfalb_inst @@ -229,7 +229,8 @@ subroutine BalanceCheck( bounds, & snow_sinks => waterflux_inst%snow_sinks_col , & ! Output: [real(r8) (:) ] snow sinks (mm H2O /s) qflx_irrig => irrigation_inst%qflx_irrig_col , & ! Input: [real(r8) (:) ] irrigation flux (mm H2O /s) - + qflx_net_latflow => waterflux_inst%qflx_net_latflow_col , & ! Output: [real(r8) (:) ] net hillcol lateral flow (mm/s) + qflx_glcice_dyn_water_flux => glacier_smb_inst%qflx_glcice_dyn_water_flux_col, & ! Input: [real(r8) (:)] water flux needed for balance check due to glc_dyn_runoff_routing (mm H2O/s) (positive means addition of water to the system) eflx_lwrad_out => energyflux_inst%eflx_lwrad_out_patch , & ! Input: [real(r8) (:) ] emitted infrared (longwave) radiation (W/m**2) @@ -309,8 +310,9 @@ subroutine BalanceCheck( bounds, & - qflx_drain(c) & - qflx_drain_perched(c) & - qflx_ice_runoff_snwcp(c) & - - qflx_ice_runoff_xs(c)) * dtime - + - qflx_ice_runoff_xs(c) & +!scs - qflx_net_latflow(c)) * dtime + ) * dtime else errh2o(c) = 0.0_r8 @@ -384,6 +386,8 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'qflx_ice_runoff_snwcp = ',qflx_ice_runoff_snwcp(indexc)*dtime write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc)*dtime write(iulog,*)'qflx_glcice_dyn_water_flux = ', qflx_glcice_dyn_water_flux(indexc)*dtime + write(iulog,*)'cold/colu = ',col%cold(indexc),col%colu(indexc) + write(iulog,*)'clm model is stopping' call endrun(decomp_index=indexc, clmlevel=namec, msg=errmsg(sourcefile, __LINE__)) end if @@ -415,9 +419,8 @@ subroutine BalanceCheck( bounds, & + qflx_snow_drain(c) + qflx_sl_top_soil(c) endif - if (col%itype(c) == icol_road_perv .or. lun%itype(l) == istsoil .or. & - lun%itype(l) == istcrop .or. lun%itype(l) == istwet .or. & - lun%itype(l) == istice .or. lun%itype(l) == istice_mec) then + if (col%itype(c) == icol_road_perv .or. lun%itype(l) == istsoil .or. & + lun%itype(l) == istcrop .or. lun%itype(l) == istwet ) then snow_sources(c) = (qflx_snow_grnd_col(c) - qflx_snow_h2osfc(c) ) & + frac_sno_eff(c) * (qflx_rain_grnd_col(c) & + qflx_dew_snow(c) + qflx_dew_grnd(c) ) + qflx_h2osfc_to_ice(c) diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 2df9616781..9614b57724 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -19,7 +19,8 @@ module HydrologyDrainageMod use IrrigationMod , only : irrigation_type use GlacierSurfaceMassBalanceMod, only : glacier_smb_type use LandunitType , only : lun - use ColumnType , only : col + use ColumnType , only : col + ! ! !PUBLIC TYPES: implicit none @@ -32,7 +33,11 @@ module HydrologyDrainageMod contains !----------------------------------------------------------------------- +! JP changed inputs subroutine HydrologyDrainage(bounds, & + num_hilltop, filter_hilltopc, & + num_hillbottom, filter_hillbottomc, & + num_hillslope, filter_hillslopec, & num_nolakec, filter_nolakec, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc, & @@ -48,10 +53,10 @@ subroutine HydrologyDrainage(bounds, & use landunit_varcon , only : istice, istwet, istsoil, istice_mec, istcrop use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv, icol_sunwall, icol_shadewall use clm_varcon , only : denh2o, denice - use clm_varctl , only : use_vichydro + use clm_varctl , only : use_vichydro, use_hillslope use clm_varpar , only : nlevgrnd, nlevurb use clm_time_manager , only : get_step_size, get_nstep - use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, LateralFlowPowerLaw + use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, LateralFlowPowerLaw, LateralFlowHillslope use SoilWaterMovementMod , only : use_aquifer_layer ! ! !ARGUMENTS: @@ -62,8 +67,16 @@ subroutine HydrologyDrainage(bounds, & integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points integer , intent(in) :: num_urbanc ! number of column urban points in column filter integer , intent(in) :: filter_urbanc(:) ! column filter for urban points - integer , intent(in) :: num_do_smb_c ! number of columns in which SMB is calculated, in column filter - integer , intent(in) :: filter_do_smb_c(:) ! column filter for bare landwhere SMB is calculated + integer , intent(in) :: num_do_smb_c ! number of bareland columns in which SMB is calculated, in column filter + integer , intent(in) :: filter_do_smb_c(:) ! column filter for bare land SMB columns +! JP add + integer , intent(in) :: num_hilltop ! number of soil cols marked "upslope" + integer , intent(in) :: filter_hilltopc(:) ! column filter for designating "upslope" cols. + integer , intent(in) :: num_hillbottom ! number of soil cols marked "downslope" + integer , intent(in) :: filter_hillbottomc(:) ! column filter for designating "downslope" cols. + integer , intent(in) :: num_hillslope ! number of soil hill cols. + integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hill cols. +! JP end type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(glc2lnd_type) , intent(in) :: glc2lnd_inst type(temperature_type) , intent(in) :: temperature_inst @@ -77,12 +90,13 @@ subroutine HydrologyDrainage(bounds, & ! !LOCAL VARIABLES: integer :: g,l,c,j,fc ! indices real(r8) :: dtime ! land model time step (sec) + !----------------------------------------------------------------------- associate( & dz => col%dz , & ! Input: [real(r8) (:,:) ] layer thickness depth (m) ctype => col%itype , & ! Input: [integer (:) ] column type - + qflx_floodg => atm2lnd_inst%forc_flood_grc , & ! Input: [real(r8) (:) ] gridcell flux of flood water from RTM forc_rain => atm2lnd_inst%forc_rain_downscaled_col , & ! Input: [real(r8) (:) ] rain rate [mm/s] forc_snow => atm2lnd_inst%forc_snow_downscaled_col , & ! Input: [real(r8) (:) ] snow rate [mm/s] @@ -111,7 +125,7 @@ subroutine HydrologyDrainage(bounds, & qflx_runoff_u => waterflux_inst%qflx_runoff_u_col , & ! Output: [real(r8) (:) ] Urban total runoff (qflx_drain+qflx_surf) (mm H2O /s) qflx_runoff_r => waterflux_inst%qflx_runoff_r_col , & ! Output: [real(r8) (:) ] Rural total runoff (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) qflx_ice_runoff_snwcp => waterflux_inst%qflx_ice_runoff_snwcp_col, & ! Output: [real(r8) (:)] solid runoff from snow capping (mm H2O /s) - qflx_irrig => irrigation_inst%qflx_irrig_col & ! Input: [real(r8) (:) ] irrigation flux (mm H2O /s) + qflx_irrig => irrigation_inst%qflx_irrig_col & ! Input: [real(r8) (:) ] irrigation flux (mm H2O /s) ) ! Determine time step and step size @@ -135,11 +149,22 @@ subroutine HydrologyDrainage(bounds, & soilhydrology_inst, soilstate_inst, & waterstate_inst, waterflux_inst) - - call LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc,& - soilhydrology_inst, soilstate_inst, & - waterstate_inst, waterflux_inst) + if(use_hillslope) then + call LateralFlowHillslope(bounds, & + num_hilltop, filter_hilltopc, & + num_hillbottom, filter_hillbottomc, & + num_hillslope, filter_hillslopec, & + num_hydrologyc, filter_hydrologyc, & + num_urbanc, filter_urbanc,& + soilhydrology_inst, soilstate_inst, & + waterstate_inst, waterflux_inst) + else + call LateralFlowPowerLaw(bounds, num_hydrologyc, & + filter_hydrologyc, & + num_urbanc, filter_urbanc,& + soilhydrology_inst, soilstate_inst, & + waterstate_inst, waterflux_inst) + endif endif @@ -183,6 +208,7 @@ subroutine HydrologyDrainage(bounds, & ! Determine wetland and land ice hydrology (must be placed here ! since need snow updated from CombineSnowLayers) + do fc = 1,num_nolakec c = filter_nolakec(fc) l = col%landunit(c) diff --git a/src/biogeophys/HydrologyNoDrainageMod.F90 b/src/biogeophys/HydrologyNoDrainageMod.F90 index b95e6b069f..6ce53a1985 100644 --- a/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -23,7 +23,7 @@ Module HydrologyNoDrainageMod ! ! !PUBLIC TYPES: implicit none - save + save ! ! !PUBLIC MEMBER FUNCTIONS: public :: HydrologyNoDrainage ! Calculates soil/snow hydrology without drainage @@ -32,7 +32,9 @@ Module HydrologyNoDrainageMod contains !----------------------------------------------------------------------- +!scs subroutine HydrologyNoDrainage(bounds, & + num_hillslope, filter_hillslopec, & num_nolakec, filter_nolakec, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc, & @@ -72,6 +74,7 @@ subroutine HydrologyNoDrainage(bounds, & use SoilWaterMovementMod , only : SoilWater use SoilWaterRetentionCurveMod, only : soil_water_retention_curve_type use SoilWaterMovementMod , only : use_aquifer_layer + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -85,6 +88,10 @@ subroutine HydrologyNoDrainage(bounds, & integer , intent(inout) :: filter_snowc(:) ! column filter for snow points integer , intent(inout) :: num_nosnowc ! number of column non-snow points integer , intent(inout) :: filter_nosnowc(:) ! column filter for non-snow points +! JP add + integer , intent(in) :: num_hillslope ! number of hillslope soil cols + integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. +! JP end type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(soilstate_type) , intent(inout) :: soilstate_inst type(energyflux_type) , intent(in) :: energyflux_inst @@ -176,12 +183,15 @@ subroutine HydrologyNoDrainage(bounds, & soilhydrology_inst, waterstate_inst) end if - call SurfaceRunoff(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & + call SurfaceRunoff(bounds, & + num_hillslope, filter_hillslopec, & + num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & soilhydrology_inst, soilstate_inst, waterflux_inst, waterstate_inst) - call Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc,& - energyflux_inst, soilhydrology_inst, soilstate_inst, temperature_inst, & - waterflux_inst, waterstate_inst) + call Infiltration(bounds, & + num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc,& + energyflux_inst, soilhydrology_inst, soilstate_inst, & + temperature_inst, waterflux_inst, waterstate_inst) call SoilWater(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & soilhydrology_inst, soilstate_inst, waterflux_inst, waterstate_inst, temperature_inst, & @@ -212,7 +222,7 @@ subroutine HydrologyNoDrainage(bounds, & waterstate_inst, waterflux_inst) endif - + ! Snow capping call SnowCapping(bounds, num_nolakec, filter_nolakec, num_snowc, filter_snowc, & aerosol_inst, waterflux_inst, waterstate_inst) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 9105af75f8..a2bdf15471 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1,4 +1,11 @@ module SoilHydrologyMod +! JP NOTES: CHANGES +! 1: Rewrote in terms of volume fluxes +! 2: Hillslope defined by width function, and a hill length +! 3: Options for either power-law of numerically intergrated transmissivity +! 4: Option for turning off kinematic flow assumption + +! TODO: move constants to the proper clm_var* !----------------------------------------------------------------------- ! !DESCRIPTION: @@ -9,6 +16,7 @@ module SoilHydrologyMod use decompMod , only : bounds_type use clm_varctl , only : iulog, use_vichydro use clm_varcon , only : e_ice, denh2o, denice, rpi + use clm_varcon , only : ispval use EnergyFluxType , only : energyflux_type use SoilHydrologyType , only : soilhydrology_type use SoilStateType , only : soilstate_type @@ -34,6 +42,7 @@ module SoilHydrologyMod public :: PerchedLateralFlow ! Calculate lateral flow from perched saturated zone public :: ThetaBasedWaterTable ! Calculate water table from soil moisture state public :: LateralFlowPowerLaw ! Calculate lateral flow based on power law drainage function + public :: LateralFlowHillslope ! Calculate lateral in multi-column hillslope configuration public :: RenewCondensation ! Misc. corrections !----------------------------------------------------------------------- @@ -103,9 +112,13 @@ subroutine soilHydReadNML( NLFilename ) end subroutine soilhydReadNML !----------------------------------------------------------------------- - subroutine SurfaceRunoff (bounds, num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc, soilhydrology_inst, soilstate_inst, waterflux_inst, & - waterstate_inst) + + subroutine SurfaceRunoff (bounds, & + num_hillslope, filter_hillslopec, & + num_hydrologyc, filter_hydrologyc, & + num_urbanc, filter_urbanc, soilhydrology_inst, & + soilstate_inst, waterflux_inst, waterstate_inst) + ! ! !DESCRIPTION: ! Calculate surface runoff @@ -123,12 +136,17 @@ subroutine SurfaceRunoff (bounds, num_hydrologyc, filter_hydrologyc, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points +! JP add + integer , intent(in) :: num_hillslope ! number of hillslope columns + integer , intent(in) :: filter_hillslopec(:) ! column filter for hillslope columns + integer , intent(in) :: num_urbanc ! number of column urban points in column filter integer , intent(in) :: filter_urbanc(:) ! column filter for urban points type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(soilstate_type) , intent(in) :: soilstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst type(waterstate_type) , intent(inout) :: waterstate_inst + ! ! !LOCAL VARIABLES: integer :: c,j,fc,g,l,i !indices @@ -254,9 +272,14 @@ subroutine SurfaceRunoff (bounds, num_hydrologyc, filter_hydrologyc, & endif end do +!scs: only allow non-zero saturated areas in lowest hillslope column + do fc = 1, num_hillslope + c = filter_hillslopec(fc) + if (col%cold(c) /= ispval) fsat(c) = 0._r8 + enddo + do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - ! assume qinmax large relative to qflx_top_soil in control if (origflag == 1) then qflx_surf(c) = fcov(c) * qflx_top_soil(c) @@ -308,7 +331,8 @@ subroutine SurfaceRunoff (bounds, num_hydrologyc, filter_hydrologyc, & end subroutine SurfaceRunoff !----------------------------------------------------------------------- - subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & + subroutine Infiltration(bounds, & + num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & energyflux_inst, soilhydrology_inst, soilstate_inst, temperature_inst, & waterflux_inst, waterstate_inst) ! @@ -336,6 +360,7 @@ subroutine Infiltration(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, f type(temperature_type) , intent(in) :: temperature_inst type(waterstate_type) , intent(inout) :: waterstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst + ! ! !LOCAL VARIABLES: integer :: c,j,l,fc ! indices @@ -597,7 +622,6 @@ subroutine WaterTable(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, fil real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) - real(r8) :: rsub_bot(bounds%begc:bounds%endc) ! subsurface runoff - bottom drainage (mm/s) real(r8) :: rsub_top(bounds%begc:bounds%endc) ! subsurface runoff - topographic control (mm/s) real(r8) :: fff(bounds%begc:bounds%endc) ! decay factor (m-1) real(r8) :: xsi(bounds%begc:bounds%endc) ! excess soil water above saturation at layer i (mm) @@ -909,7 +933,6 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) - real(r8) :: rsub_bot(bounds%begc:bounds%endc) ! subsurface runoff - bottom drainage (mm/s) real(r8) :: rsub_top(bounds%begc:bounds%endc) ! subsurface runoff - topographic control (mm/s) real(r8) :: fff(bounds%begc:bounds%endc) ! decay factor (m-1) real(r8) :: xsi(bounds%begc:bounds%endc) ! excess soil water above saturation at layer i (mm) @@ -1024,7 +1047,6 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) qflx_drain(c) = 0._r8 - rsub_bot(c) = 0._r8 qflx_rsub_sat(c) = 0._r8 rsub_top(c) = 0._r8 fracice_rsub(c) = 0._r8 @@ -1848,6 +1870,9 @@ subroutine ThetaBasedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) :: sat_lev real(r8) :: s1,s2,m,b ! temporary variables used to interpolate theta integer :: sat_flag +! JP add + real(r8) :: tmph2omin +! JP end !----------------------------------------------------------------------- associate( & @@ -1914,7 +1939,6 @@ subroutine ThetaBasedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & end subroutine ThetaBasedWaterTable - !#6 !----------------------------------------------------------------------- subroutine LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & @@ -1945,13 +1969,12 @@ subroutine LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & type(waterflux_type) , intent(inout) :: waterflux_inst ! ! !LOCAL VARIABLES: - character(len=32) :: subname = 'Drainage' ! subroutine name + character(len=32) :: subname = 'LateralFlowPowerLaw' ! subroutine name integer :: c,j,fc,i ! indices real(r8) :: dtime ! land model time step (sec) real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) - real(r8) :: rsub_bot(bounds%begc:bounds%endc) ! subsurface runoff - bottom drainage (mm/s) real(r8) :: rsub_top(bounds%begc:bounds%endc) ! subsurface runoff - topographic control (mm/s) real(r8) :: fff(bounds%begc:bounds%endc) ! decay factor (m-1) real(r8) :: xsi(bounds%begc:bounds%endc) ! excess soil water above saturation at layer i (mm) @@ -2050,7 +2073,6 @@ subroutine LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) qflx_drain(c) = 0._r8 - rsub_bot(c) = 0._r8 qflx_rsub_sat(c) = 0._r8 rsub_top(c) = 0._r8 fracice_rsub(c) = 0._r8 @@ -2245,6 +2267,527 @@ subroutine LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & end subroutine LateralFlowPowerLaw +!#61 + !----------------------------------------------------------------------- + subroutine LateralFlowHillslope(bounds, & + num_hilltop, filter_hilltopc, & + num_hillbottom, filter_hillbottomc, & + num_hillslope, filter_hillslopec, & + num_hydrologyc, filter_hydrologyc, & + num_urbanc, filter_urbanc,soilhydrology_inst, soilstate_inst, & + waterstate_inst, waterflux_inst) + ! + ! !DESCRIPTION: + ! Calculate subsurface drainage + ! + ! !USES: + use clm_time_manager , only : get_step_size + use clm_varpar , only : nlevsoi, nlevgrnd, nlayer, nlayert + use clm_varcon , only : pondmx, watmin,rpi, secspday, nlvic + use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv + use abortutils , only : endrun + use GridcellType , only : grc + use landunit_varcon , only : istsoil, istcrop +! JP add + use clm_time_manager , only : get_nstep +! JP end + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter + integer , intent(in) :: num_urbanc ! number of column urban points in column filter + integer , intent(in) :: filter_urbanc(:) ! column filter for urban points + integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points + type(soilstate_type) , intent(in) :: soilstate_inst + type(soilhydrology_type) , intent(inout) :: soilhydrology_inst + type(waterstate_type) , intent(inout) :: waterstate_inst + type(waterflux_type) , intent(inout) :: waterflux_inst +! JP add + integer , intent(in) :: num_hillslope ! number of hillslope soil cols + integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. + integer , intent(in) :: num_hilltop ! number of hillslope soil cols + integer , intent(in) :: filter_hilltopc(:) ! column filter for designating all hillslope cols. + integer , intent(in) :: num_hillbottom ! number of hillslope soil cols + integer , intent(in) :: filter_hillbottomc(:) ! column filter for designating all hillslope cols. +! JP end + ! + ! !LOCAL VARIABLES: + character(len=32) :: subname = 'LateralFlowHillslope' ! subroutine name + integer :: c,j,fc,i ! indices + real(r8) :: dtime ! land model time step (sec) + real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) + real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) + integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) + real(r8) :: rsub_top(bounds%begc:bounds%endc) ! subsurface runoff - topographic control (mm/s) + real(r8) :: fff(bounds%begc:bounds%endc) ! decay factor (m-1) + real(r8) :: xsi(bounds%begc:bounds%endc) ! excess soil water above saturation at layer i (mm) + real(r8) :: xsia(bounds%begc:bounds%endc) ! available pore space at layer i (mm) + real(r8) :: xs1(bounds%begc:bounds%endc) ! excess soil water above saturation at layer 1 (mm) + real(r8) :: smpfz(1:nlevsoi) ! matric potential of layer right above water table (mm) + real(r8) :: wtsub ! summation of hk*dzmm for layers below water table (mm**2/s) + real(r8) :: dzsum ! summation of dzmm of layers below water table (mm) + real(r8) :: icefracsum ! summation of icefrac*dzmm of layers below water table (-) + real(r8) :: fracice_rsub(bounds%begc:bounds%endc) ! fractional impermeability of soil layers (-) + real(r8) :: available_h2osoi_liq ! available soil liquid water in a layer + real(r8) :: h2osoi_vol + real(r8) :: imped + real(r8) :: rsub_top_tot + real(r8) :: rsub_top_layer + real(r8) :: theta_unsat + real(r8) :: f_unsat + real(r8) :: s_y + integer :: k + real(r8) :: s1 + real(r8) :: s2 + real(r8) :: m + real(r8) :: b + real(r8) :: vol_ice + real(r8) :: dsmax_tmp(bounds%begc:bounds%endc) ! temporary variable for ARNO subsurface runoff calculation + real(r8) :: rsub_tmp ! temporary variable for ARNO subsurface runoff calculation + real(r8) :: frac ! temporary variable for ARNO subsurface runoff calculation + real(r8) :: rel_moist ! relative moisture, temporary variable + real(r8) :: wtsub_vic ! summation of hk*dzmm for layers in the third VIC layer + integer :: g + +!scs + character(len=32) :: transmissivity_method = 'layersum' + character(len=32) :: baseflow_method = 'kinematic' + integer :: c_down + real(r8) :: transmis + real(r8) :: dgrad + real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent + real(r8), parameter :: k_anisotropic = 50._r8 + real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) + real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) + integer :: c0, nstep + + !----------------------------------------------------------------------- + + associate( & + nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) + h2osno => waterstate_inst%h2osno_col , & ! Input: [real(r8) (:) ] surface water (mm) + z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) + zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) + dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) + snl => col%snl , & ! Input: [integer (:) ] number of snow layers + h2osfc => waterstate_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) + bsw => soilstate_inst%bsw_col , & ! Input: [real(r8) (:,:) ] Clapp and Hornberger "b" + hksat => soilstate_inst%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) + sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) + watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) + eff_porosity => soilstate_inst%eff_porosity_col , & ! Input: [real(r8) (:,:) ] effective porosity = porosity - vol_ice + hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) +! JP add + watfc => soilstate_inst%watfc_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at field capacity +! JP end + qflx_latflow_out => waterflux_inst%qflx_latflow_out_col , & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) + qflx_latflow_in => waterflux_inst%qflx_latflow_in_col , & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) + qflx_net_latflow_in => waterflux_inst%qflx_net_latflow_col , & ! Output: [real(r8) (:) ] net lateral saturated (mm/s) + + depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth + c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) + Dsmax => soilhydrology_inst%dsmax_col , & ! Input: [real(r8) (:) ] max. velocity of baseflow (mm/day) + max_moist => soilhydrology_inst%max_moist_col , & ! Input: [real(r8) (:,:) ] maximum soil moisture (ice + liq) + moist => soilhydrology_inst%moist_col , & ! Input: [real(r8) (:,:) ] soil layer moisture (mm) + Ds => soilhydrology_inst%ds_col , & ! Input: [real(r8) (:) ] fracton of Dsmax where non-linear baseflow begins + Wsvic => soilhydrology_inst%Wsvic_col , & ! Input: [real(r8) (:) ] fraction of maximum soil moisutre where non-liear base flow occurs + icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] fraction of ice in layer + hkdepth => soilhydrology_inst%hkdepth_col , & ! Input: [real(r8) (:) ] decay factor (m) + frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) + zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) + wa => soilhydrology_inst%wa_col , & ! Input: [real(r8) (:) ] water in the unconfined aquifer (mm) + ice => soilhydrology_inst%ice_col , & ! Input: [real(r8) (:,:) ] soil layer moisture (mm) + qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) + origflag => soilhydrology_inst%origflag , & ! Input: logical + h2osfcflag => soilhydrology_inst%h2osfcflag , & ! Input: logical + + qflx_snwcp_liq => waterflux_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] + qflx_ice_runoff_xs => waterflux_inst%qflx_ice_runoff_xs_col , & ! Output: [real(r8) (:) ] solid runoff from excess ice in soil (mm H2O /s) [+] + qflx_dew_grnd => waterflux_inst%qflx_dew_grnd_col , & ! Output: [real(r8) (:) ] ground surface dew formation (mm H2O /s) [+] + qflx_dew_snow => waterflux_inst%qflx_dew_snow_col , & ! Output: [real(r8) (:) ] surface dew added to snow pack (mm H2O /s) [+] + qflx_sub_snow => waterflux_inst%qflx_sub_snow_col , & ! Output: [real(r8) (:) ] sublimation rate from snow pack (mm H2O /s) [+] + qflx_drain => waterflux_inst%qflx_drain_col , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) + qflx_qrgwl => waterflux_inst%qflx_qrgwl_col , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes (mm H2O /s) + qflx_rsub_sat => waterflux_inst%qflx_rsub_sat_col , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] + h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) + h2osoi_ice => waterstate_inst%h2osoi_ice_col & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) + ) + + ! Get time step + + dtime = get_step_size() + nstep = get_nstep() +!!$ if ( nstep > 800) then +!!$ c0=101298 +!!$ else +!!$ c0=-1000 +!!$ endif + + ! Convert layer thicknesses from m to mm + + do j = 1,nlevsoi + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + dzmm(c,j) = dz(c,j)*1.e3_r8 + + vol_ice = min(watsat(c,j), h2osoi_ice(c,j)/(dz(c,j)*denice)) + icefrac(c,j) = min(1._r8,vol_ice/watsat(c,j)) + end do + end do + + ! Initial set + + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + qflx_drain(c) = 0._r8 + qflx_rsub_sat(c) = 0._r8 + rsub_top(c) = 0._r8 + fracice_rsub(c) = 0._r8 +! JP add + qflx_latflow_in(c) = 0._r8 + qflx_latflow_out(c) = 0._r8 + qflx_net_latflow(c) = 0._r8 + qflx_latflow_out_vol(c) = 0._r8 +! JP end + end do + + + ! The layer index of the first unsaturated layer, + ! i.e., the layer right above the water table + + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + jwt(c) = nlevsoi + ! allow jwt to equal zero when zwt is in top layer + do j = 1,nlevsoi + if(zwt(c) <= zi(c,j)) then + jwt(c) = j-1 + exit + end if + enddo + end do + + do fc = 1, num_hillslope + c = filter_hillslopec(fc) + g = col%gridcell(c) + + ! Calculate transmissivity + + transmis = 0._r8 + ! transmissivity non-zero only when saturated conditions exist + if(zwt(c) <= zi(c,nbedrock(c))) then + ! sum of layer transmissivities + if (transmissivity_method == 'layersum') then + do j = jwt(c)+1, nbedrock(c) + if(j == jwt(c)+1) then + transmis = transmis + 1.e-3_r8*hksat(c,j)*(zi(c,j) - zwt(c)) + else + transmis = transmis + 1.e-3_r8*hksat(c,j)*dz(c,j) + endif + end do + endif + ! constant conductivity based on shallowest saturated layer hk + if (transmissivity_method == 'constant') then + transmis = k_anisotropic*(1.e-3_r8*hksat(c,jwt(c)+1)) & + *(zi(c,nbedrock(c)) - zwt(c) ) + endif + ! power law profile based on shallowest saturated layer hk + if (transmissivity_method == 'power') then + ! transmis = k_anisotropic*hksat(c,jwt(c)+1)*0.001_r8*dzsumall* & + ! ((1-1000._r8*zwt(c)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) + endif + endif ! this could be moved to include latflow calculations... + + ! kinematic wave approximation + if (baseflow_method == 'kinematic') then + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*col%hill_slope(c) + + endif + ! darcy's law + if (baseflow_method == 'darcy') then + if (col%cold(c) /= ispval) then + c_down = col%cold(c) + dgrad = (col%hill_elev(c)+zwt(c)) & + - (col%hill_elev(c_down)+zwt(c_down)) + dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(c_down)) + else +!what lower boundary condition to use?? + + endif + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad + end if + + ! convert volumetric flow to equivalent flux + qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) + + ! hilltop column has no inflow + if (col%colu(c) == ispval) then + qflx_latflow_in(c) = 0._r8 + endif + + ! current outflow is inflow to downhill column normalized by downhill area + if (col%cold(c) /= ispval) then + qflx_latflow_in(col%cold(c)) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) + endif + + enddo + + !-- Topographic runoff ------------------------- + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + + ! net lateral flow (positive out) + qflx_net_latflow(c) = qflx_latflow_out(c) - qflx_latflow_in(c) + + fff(c) = 1._r8/ hkdepth(c) + dzsum = 0._r8 + icefracsum = 0._r8 + do j = max(jwt(c),1), nlevsoi + dzsum = dzsum + dzmm(c,j) + icefracsum = icefracsum + icefrac(c,j) * dzmm(c,j) + end do + imped=10._r8**(-e_ice*(icefracsum/dzsum)) + !@@ + ! baseflow + if(zwt(c) <= zi(c,nbedrock(c))) then + if (lun%itype(col%landunit(c)) == istsoil) then + ! apply net lateral flow here + rsub_top(c) = qflx_net_latflow(c) + else + rsub_top(c) = imped * baseflow_scalar & + * tan(rpi/180._r8*col%topo_slope(c))* & + (zi(c,nbedrock(c)) - zwt(c))**(n_baseflow) + endif + else + rsub_top(c) = 0._r8 + endif + +if(c==c0) then + write(iulog,*) 'rsubtop: ',c,lun%itype(col%landunit(c)),istsoil,col%colu(c),col%cold(c) + write(iulog,'(i4,5f16.4)') col%hillslope_ndx(c),col%hill_distance(c),col%hill_width(c),col%hill_area(c),col%hill_elev(c),col%hill_slope(c) + write(iulog,'(5e16.4)') qflx_latflow_out_vol(c),qflx_latflow_in(c),qflx_latflow_out(c),qflx_net_latflow(c) + write(iulog,'(5e16.4)') qflx_net_latflow(c)*1800., qflx_net_latflow(c)*3600. + write(iulog,'(a12,2i8,2e16.4)') 'transmis: ', jwt(c),nbedrock(c),transmis + write(iulog,*) ' ' + +endif + + !-- Now remove water via rsub_top + rsub_top_tot = - rsub_top(c) * dtime + + if(rsub_top_tot > 0.) then !rising water table + do j = jwt(c)+1, nbedrock(c) + ! analytical expression for specific yield + s_y = watsat(c,j) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) + s_y=max(s_y,0.02_r8) + +if(c==c0) then + write(iulog,'(a12,5e16.4)') 's_y: ',s_y,-(s_y*(zi(c,j) - zwt(c))*1.e3) + write(iulog,*) ' ' +endif + rsub_top_layer=max(rsub_top_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) + rsub_top_layer=min(rsub_top_layer,0._r8) + h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer + +if(c==c0) then + write(iulog,'(a12,5e16.4)') 'negrsub: ',h2osoi_liq(c,jwt(c)+1), (rsub_top(c) * dtime),rsub_top_tot + write(iulog,'(a12,5e16.4)') 'rslayer: ', rsub_top_tot, rsub_top_layer + write(iulog,*) ' ' +endif + + rsub_top_tot = rsub_top_tot - rsub_top_layer + +if(c==c0) then + write(iulog,'(a12,5e16.4)') 'newrsubtoptot: ',rsub_top_tot + write(iulog,*) ' ' +endif + if (rsub_top_tot >= 0.) then + zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 + exit + else + zwt(c) = zi(c,j) + endif + enddo + + !-- remove residual rsub_top --------------------------------------------- + ! make sure no extra water removed from soil column + rsub_top(c) = rsub_top(c) - rsub_top_tot/dtime + +if(c==c0) then + write(iulog,'(a12,5e16.4)') 'posrsub: ',h2osoi_liq(c,jwt(c)+1), (rsub_top(c) * dtime) + write(iulog,*) ' ' +endif + + h2osoi_liq(c,jwt(c)+1) = h2osoi_liq(c,jwt(c)+1) - (rsub_top(c) * dtime) + ! analytical expression for specific yield + s_y = watsat(c,jwt(c)+1) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,jwt(c)+1))**(-1./bsw(c,jwt(c)+1))) + s_y=max(s_y,0.02_r8) + + zwt(c) = zwt(c) - (rsub_top(c) * dtime)/s_y/1000._r8 + rsub_top_tot = 0._r8 + + else ! deepening water table + do j = jwt(c)+1, nbedrock(c) + ! analytical expression for specific yield + s_y = watsat(c,j) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) + s_y=max(s_y,0.02_r8) + +if(c==c0) then + write(iulog,'(a12,5e16.4)') 's_y: ',s_y,-(s_y*(zi(c,j) - zwt(c))*1.e3) + write(iulog,*) ' ' +endif + rsub_top_layer=max(rsub_top_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) + rsub_top_layer=min(rsub_top_layer,0._r8) + h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer + +if(c==c0) then + write(iulog,'(a12,5e16.4)') 'negrsub: ',h2osoi_liq(c,jwt(c)+1), (rsub_top(c) * dtime),rsub_top_tot + write(iulog,'(a12,5e16.4)') 'rslayer: ', rsub_top_tot, rsub_top_layer + write(iulog,*) ' ' +endif + + rsub_top_tot = rsub_top_tot - rsub_top_layer + +if(c==c0) then + write(iulog,'(a12,5e16.4)') 'newrsubtoptot: ',rsub_top_tot + write(iulog,*) ' ' +endif + if (rsub_top_tot >= 0.) then + zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 + exit + else + zwt(c) = zi(c,j) + endif + enddo + + !-- remove residual rsub_top --------------------------------------------- + ! make sure no extra water removed from soil column + rsub_top(c) = rsub_top(c) - rsub_top_tot/dtime + endif + + zwt(c) = max(0.0_r8,zwt(c)) + zwt(c) = min(80._r8,zwt(c)) + + end do + + + ! excessive water above saturation added to the above unsaturated layer like a bucket + ! if column fully saturated, excess water goes to runoff + + do j = nlevsoi,2,-1 + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + xsi(c) = max(h2osoi_liq(c,j)-eff_porosity(c,j)*dzmm(c,j),0._r8) + h2osoi_liq(c,j) = min(eff_porosity(c,j)*dzmm(c,j), h2osoi_liq(c,j)) + h2osoi_liq(c,j-1) = h2osoi_liq(c,j-1) + xsi(c) + end do + end do + + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + + ! watmin addition to fix water balance errors + xs1(c) = max(max(h2osoi_liq(c,1)-watmin,0._r8)- & + max(0._r8,(pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_ice(c,1)-watmin)),0._r8) + h2osoi_liq(c,1) = h2osoi_liq(c,1) - xs1(c) + + if (lun%urbpoi(col%landunit(c))) then + qflx_rsub_sat(c) = xs1(c) / dtime + else + ! send this water up to h2osfc rather than sending to drainage + h2osfc(c) = h2osfc(c) + xs1(c) + qflx_rsub_sat(c) = 0._r8 + endif + ! add in ice check + xs1(c) = max(max(h2osoi_ice(c,1),0._r8)-max(0._r8,(pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_liq(c,1))),0._r8) + h2osoi_ice(c,1) = min(max(0._r8,pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_liq(c,1)), h2osoi_ice(c,1)) + qflx_ice_runoff_xs(c) = xs1(c) / dtime + end do + + ! Limit h2osoi_liq to be greater than or equal to watmin. + ! Get water needed to bring h2osoi_liq equal watmin from lower layer. + ! If insufficient water in soil layers, get from aquifer water + + do j = 1, nlevsoi-1 + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + if (h2osoi_liq(c,j) < watmin) then + xs(c) = watmin - h2osoi_liq(c,j) + ! deepen water table if water is passed from below zwt layer + if(j == jwt(c)) then + zwt(c) = zwt(c) + xs(c)/eff_porosity(c,j)/1000._r8 + endif + else + xs(c) = 0._r8 + end if + h2osoi_liq(c,j ) = h2osoi_liq(c,j ) + xs(c) + h2osoi_liq(c,j+1) = h2osoi_liq(c,j+1) - xs(c) + end do + end do + + ! Get water for bottom layer from layers above if possible + j = nlevsoi + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + if (h2osoi_liq(c,j) < watmin) then + xs(c) = watmin-h2osoi_liq(c,j) + searchforwater: do i = nlevsoi-1, 1, -1 + available_h2osoi_liq = max(h2osoi_liq(c,i)-watmin-xs(c),0._r8) + if (available_h2osoi_liq >= xs(c)) then + h2osoi_liq(c,j) = h2osoi_liq(c,j) + xs(c) + h2osoi_liq(c,i) = h2osoi_liq(c,i) - xs(c) + xs(c) = 0._r8 + exit searchforwater + else + h2osoi_liq(c,j) = h2osoi_liq(c,j) + available_h2osoi_liq + h2osoi_liq(c,i) = h2osoi_liq(c,i) - available_h2osoi_liq + xs(c) = xs(c) - available_h2osoi_liq + end if + end do searchforwater + else + xs(c) = 0._r8 + end if + ! Needed in case there is no water to be found + h2osoi_liq(c,j) = h2osoi_liq(c,j) + xs(c) + ! Instead of removing water from aquifer where it eventually + ! shows up as excess drainage to the ocean, take it back out of + ! drainage + qflx_rsub_sat(c) = qflx_rsub_sat(c) - xs(c)/dtime + + end do + + + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + + ! Sub-surface runoff and drainage + qflx_drain(c) = qflx_rsub_sat(c) + rsub_top(c) +if(c==c0)write(iulog,*) 'qdrain: ', qflx_drain(c), qflx_rsub_sat(c), rsub_top(c) + ! Set imbalance for snow capping + + qflx_qrgwl(c) = qflx_snwcp_liq(c) + + end do + + + ! No drainage for urban columns (except for pervious road as computed above) + + do fc = 1, num_urbanc + c = filter_urbanc(fc) + if (col%itype(c) /= icol_road_perv) then + qflx_drain(c) = 0._r8 + ! This must be done for roofs and impervious road (walls will be zero) + qflx_qrgwl(c) = qflx_snwcp_liq(c) + end if + end do + + end associate + + end subroutine LateralFlowHillslope + !#7 !----------------------------------------------------------------------- subroutine RenewCondensation(bounds, num_hydrologyc, filter_hydrologyc, & diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 37c1641c88..f534600e47 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -539,7 +539,6 @@ subroutine InitHistory(this, bounds) call hist_addfld1d (fname='ERRH2OSNO', units='mm', & avgflag='A', long_name='imbalance in snow depth (liquid water)', & ptr_col=this%errh2osno_col, c2l_scale_type='urbanf') - end subroutine InitHistory !----------------------------------------------------------------------- @@ -707,6 +706,12 @@ subroutine InitCold(this, bounds, & this%h2osoi_vol_col(c,j) = 0.15_r8 endif end do +! JP add, tmp for init testing +! do j = 1,nlevsoi +! this%h2osoi_vol_col(c,j) = 0.35_r8 +! end do +! JP end + else if (lun%urbpoi(l)) then if (col%itype(c) == icol_road_perv) then nlevs = nlevgrnd diff --git a/src/biogeophys/WaterfluxType.F90 b/src/biogeophys/WaterfluxType.F90 index 02b6cb163e..36d93b8d57 100644 --- a/src/biogeophys/WaterfluxType.F90 +++ b/src/biogeophys/WaterfluxType.F90 @@ -73,6 +73,9 @@ module WaterfluxType real(r8), pointer :: qflx_infl_col (:) ! col infiltration (mm H2O /s) real(r8), pointer :: qflx_surf_col (:) ! col surface runoff (mm H2O /s) real(r8), pointer :: qflx_drain_col (:) ! col sub-surface runoff (mm H2O /s) + real(r8), pointer :: qflx_latflow_in_col (:) ! col hillslope lateral flow input (mm/s) + real(r8), pointer :: qflx_latflow_out_col (:) ! col hillslope lateral flow output (mm/s) + real(r8), pointer :: qflx_net_latflow_col (:) ! col hillslope net lateral flow (mm/s) real(r8), pointer :: qflx_top_soil_col (:) ! col net water input into soil from top (mm/s) real(r8), pointer :: qflx_h2osfc_to_ice_col (:) ! col conversion of h2osfc to ice real(r8), pointer :: qflx_h2osfc_surf_col (:) ! col surface water runoff @@ -212,6 +215,9 @@ subroutine InitAllocate(this, bounds) allocate(this%qflx_infl_col (begc:endc)) ; this%qflx_infl_col (:) = nan allocate(this%qflx_surf_col (begc:endc)) ; this%qflx_surf_col (:) = nan allocate(this%qflx_drain_col (begc:endc)) ; this%qflx_drain_col (:) = nan + allocate(this%qflx_latflow_in_col (begc:endc)) ; this%qflx_latflow_in_col (:) = 0._r8 + allocate(this%qflx_latflow_out_col (begc:endc)) ; this%qflx_latflow_out_col (:) = 0._r8 + allocate(this%qflx_net_latflow_col (begc:endc)) ; this%qflx_net_latflow_col (:) = 0._r8 allocate(this%qflx_top_soil_col (begc:endc)) ; this%qflx_top_soil_col (:) = nan allocate(this%qflx_h2osfc_to_ice_col (begc:endc)) ; this%qflx_h2osfc_to_ice_col (:) = nan allocate(this%qflx_h2osfc_surf_col (begc:endc)) ; this%qflx_h2osfc_surf_col (:) = nan @@ -299,6 +305,17 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='sub-surface drainage', & ptr_col=this%qflx_drain_col, c2l_scale_type='urbanf') + this%qflx_latflow_out_col(begc:endc) = spval + call hist_addfld1d (fname='QLATFLOWOUT', units='mm/s', & + avgflag='A', long_name='hillcol lateral outflow', & + ptr_col=this%qflx_latflow_out_col, c2l_scale_type='urbanf') + + this%qflx_net_latflow_col(begc:endc) = spval + call hist_addfld1d (fname='QLATNET', units='mm/s', & + avgflag='A', long_name='hillcol net lateral flow', & + ptr_col=this%qflx_net_latflow_col, c2l_scale_type='urbanf',& + default='inactive') + this%qflx_liq_dynbal_grc(begg:endg) = spval call hist_addfld1d (fname='QFLX_LIQ_DYNBAL', units='mm/s', & avgflag='A', long_name='liq dynamic land cover change conversion runoff flux', & @@ -678,6 +695,9 @@ subroutine InitCold(this, bounds) if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then this%qflx_drain_col(c) = 0._r8 this%qflx_surf_col(c) = 0._r8 + this%qflx_latflow_in_col(c) = 0._r8 + this%qflx_latflow_out_col(c) = 0._r8 + this%qflx_net_latflow_col(c) = 0._r8 end if end do diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 9032444f19..0fab5e8c46 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -62,7 +62,18 @@ module ColumnType real(r8), pointer :: z_lake (:,:) ! layer depth for lake (m) real(r8), pointer :: lakedepth (:) ! variable lake depth (m) integer , pointer :: nbedrock (:) ! variable depth to bedrock index - +!scs + ! hillslope hydrology variables + integer, pointer :: colu (:) ! column index of uphill column (hillslope hydrology) + integer, pointer :: cold (:) ! column index of downhill column (hillslope hydrology) + integer, pointer :: hillslope_ndx (:) ! hillslope identifier + real(r8), pointer :: hill_elev (:) ! mean elevation of column relative to mean gridcell elevation + real(r8), pointer :: hill_slope (:) ! mean along-hill slope + real(r8), pointer :: hill_area (:) ! mean surface area + real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column + real(r8), pointer :: hill_distance (:) ! along-hill distance of column from bottom of hillslope + +!scs ! levgrnd_class gives the class in which each layer falls. This is relevant for ! columns where there are 2 or more fundamentally different layer types. For ! example, this distinguishes between soil and bedrock layers. The particular value @@ -118,13 +129,22 @@ subroutine Init(this, begc, endc) allocate(this%dz_lake (begc:endc,nlevlak)) ; this%dz_lake (:,:) = nan allocate(this%z_lake (begc:endc,nlevlak)) ; this%z_lake (:,:) = nan - allocate(this%nbedrock (begc:endc)) ; this%nbedrock (:) = ispval +!scs + allocate(this%colu (begc:endc)) ; this%colu (:) = ispval + allocate(this%cold (begc:endc)) ; this%cold (:) = ispval + allocate(this%hillslope_ndx(begc:endc)) ; this%hillslope_ndx (:) = ispval + allocate(this%hill_elev(begc:endc)) ; this%hill_elev (:) = spval + allocate(this%hill_slope(begc:endc)) ; this%hill_slope (:) = spval + allocate(this%hill_area(begc:endc)) ; this%hill_area (:) = spval + allocate(this%hill_width(begc:endc)) ; this%hill_width (:) = spval + allocate(this%hill_distance(begc:endc)) ; this%hill_distance (:) = spval +!scs + allocate(this%nbedrock (begc:endc)) ; this%nbedrock (:) = ispval allocate(this%levgrnd_class(begc:endc,nlevgrnd)) ; this%levgrnd_class(:,:) = ispval allocate(this%micro_sigma (begc:endc)) ; this%micro_sigma (:) = nan allocate(this%n_melt (begc:endc)) ; this%n_melt (:) = nan allocate(this%topo_slope (begc:endc)) ; this%topo_slope (:) = nan allocate(this%topo_std (begc:endc)) ; this%topo_std (:) = nan - end subroutine Init !------------------------------------------------------------------------ @@ -158,7 +178,8 @@ subroutine Clean(this) deallocate(this%topo_std ) deallocate(this%nbedrock ) deallocate(this%levgrnd_class) - + deallocate(this%colu ) + deallocate(this%cold ) end subroutine Clean !----------------------------------------------------------------------- diff --git a/src/main/GridcellType.F90 b/src/main/GridcellType.F90 index ae7f317001..9d1e5aeb40 100644 --- a/src/main/GridcellType.F90 +++ b/src/main/GridcellType.F90 @@ -29,6 +29,7 @@ module GridcellType real(r8), pointer :: londeg (:) ! longitude (degrees) integer, pointer :: nbedrock (:) ! index of uppermost bedrock layer + integer, pointer :: ncolumns (:) ! number of columns per hillslope ! Daylength real(r8) , pointer :: max_dayl (:) ! maximum daylength for this grid cell (s) @@ -69,6 +70,7 @@ subroutine Init(this, begg, endg) allocate(this%latdeg (begg:endg)) ; this%latdeg (:) = nan allocate(this%londeg (begg:endg)) ; this%londeg (:) = nan allocate(this%nbedrock (begg:endg)) ; this%nbedrock (:) = ispval + allocate(this%ncolumns (begg:endg)); this%ncolumns (:) = ispval ! This is initiailized in module DayLength allocate(this%max_dayl (begg:endg)) ; this%max_dayl (:) = nan @@ -93,6 +95,7 @@ subroutine Clean(this) deallocate(this%latdeg ) deallocate(this%londeg ) deallocate(this%nbedrock ) + deallocate(this%ncolumns ) deallocate(this%max_dayl ) deallocate(this%dayl ) deallocate(this%prev_dayl ) diff --git a/src/main/LandunitType.F90 b/src/main/LandunitType.F90 index bb6ac80d6a..d800f03d91 100644 --- a/src/main/LandunitType.F90 +++ b/src/main/LandunitType.F90 @@ -32,6 +32,7 @@ module LandunitType integer , pointer :: coli (:) ! beginning column index per landunit integer , pointer :: colf (:) ! ending column index for each landunit integer , pointer :: ncolumns (:) ! number of columns for each landunit + integer , pointer :: nhillslopes (:) ! number of hillslopes for each landunit integer , pointer :: patchi (:) ! beginning patch index for each landunit integer , pointer :: patchf (:) ! ending patch index for each landunit integer , pointer :: npatches (:) ! number of patches for each landunit @@ -82,6 +83,7 @@ subroutine Init(this, begl, endl) allocate(this%coli (begl:endl)); this%coli (:) = ispval allocate(this%colf (begl:endl)); this%colf (:) = ispval allocate(this%ncolumns (begl:endl)); this%ncolumns (:) = ispval + allocate(this%nhillslopes (begl:endl)); this%nhillslopes(:) = ispval allocate(this%patchi (begl:endl)); this%patchi (:) = ispval allocate(this%patchf (begl:endl)); this%patchf (:) = ispval allocate(this%npatches (begl:endl)); this%npatches (:) = ispval @@ -119,6 +121,7 @@ subroutine Clean(this) deallocate(this%coli ) deallocate(this%colf ) deallocate(this%ncolumns ) + deallocate(this%nhillslopes ) deallocate(this%patchi ) deallocate(this%patchf ) deallocate(this%npatches ) diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index c5398a3bf1..0eb44ee017 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -311,7 +311,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call dynSubgrid_driver(bounds_proc, & urbanparams_inst, soilstate_inst, soilhydrology_inst, lakestate_inst, & waterstate_inst, waterflux_inst, temperature_inst, energyflux_inst, & - canopystate_inst, photosyns_inst, crop_inst, glc2lnd_inst, bgc_vegetation_inst, & + canopystate_inst, photosyns_inst, crop_inst, glc2lnd_inst, bgc_vegetation_inst, & soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, & c13_soilbiogeochem_carbonstate_inst, c14_soilbiogeochem_carbonstate_inst, & soilbiogeochem_nitrogenstate_inst, soilbiogeochem_carbonflux_inst, ch4_inst, & @@ -703,8 +703,9 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! LakeHydrology after the new snow filter is built call t_startf('hydro_without_drainage') - +! JP changed inputs: call HydrologyNoDrainage(bounds_clump, & + filter(nc)%num_hillslope, filter(nc)%hillslopec, & filter(nc)%num_nolakec, filter(nc)%nolakec, & filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & filter(nc)%num_urbanc, filter(nc)%urbanc, & @@ -860,14 +861,18 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! ============================================================================ call t_startf('hydro2_drainage') - - call HydrologyDrainage(bounds_clump, & - filter(nc)%num_nolakec, filter(nc)%nolakec, & - filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & - filter(nc)%num_urbanc, filter(nc)%urbanc, & - filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & - atm2lnd_inst, glc2lnd_inst, temperature_inst, & - soilhydrology_inst, soilstate_inst, waterstate_inst, waterflux_inst, & +!scs + call HydrologyDrainage(bounds_clump, & + filter(nc)%num_hilltop, filter(nc)%hilltopc, & + filter(nc)%num_hillbottom, filter(nc)%hillbottomc, & + filter(nc)%num_hillslope, filter(nc)%hillslopec, & + filter(nc)%num_nolakec, filter(nc)%nolakec, & + filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & + filter(nc)%num_urbanc, filter(nc)%urbanc, & + filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & + atm2lnd_inst, glc2lnd_inst, temperature_inst, & + soilhydrology_inst, soilstate_inst, & + waterstate_inst, waterflux_inst, & irrigation_inst, glacier_smb_inst) call t_stopf('hydro2_drainage') diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index f395a9e007..30b6484728 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -13,7 +13,8 @@ module clm_initializeMod use clm_varctl , only : is_cold_start, is_interpolated_start use clm_varctl , only : create_glacier_mec_landunit, iulog use clm_varctl , only : use_lch4, use_cn, use_cndv, use_c13, use_c14, use_ed - use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft, wt_glc_mec, topo_glc_mec + use clm_varctl , only : nhillslope + use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft, wt_glc_mec, topo_glc_mec, nhillcol use perf_mod , only : t_startf, t_stopf use readParamsMod , only : readParameters use ncdio_pio , only : file_desc_t @@ -46,6 +47,7 @@ subroutine initialize1( ) use clm_varcon , only: clm_varcon_init use landunit_varcon , only: landunit_varcon_init, max_lunit use clm_varctl , only: fsurdat, fatmlndfrc, noland, version + use clm_varctl , only: use_hillslope use pftconMod , only: pftcon use decompInitMod , only: decompInit_lnd, decompInit_clumps, decompInit_glcp use domainMod , only: domain_check, ldomain, domain_init @@ -53,6 +55,7 @@ subroutine initialize1( ) use controlMod , only: control_init, control_print, NLFilename use ncdio_pio , only: ncd_pio_init use initGridCellsMod , only: initGridCells + use initHillslopeMod , only: initHillslopes, HillslopeDomPft use ch4varcon , only: ch4conrd use UrbanParamsType , only: UrbanInput, IsSimpleBuildTemp use dynSubgridControlMod, only: dynSubgridControl_init @@ -161,7 +164,7 @@ subroutine initialize1( ) allocate (urban_valid (begg:endg )) allocate (wt_nat_patch (begg:endg, natpft_lb:natpft_ub )) allocate (wt_cft (begg:endg, cft_lb:cft_ub )) - allocate (fert_cft (begg:endg, cft_lb:cft_ub )) + allocate (fert_cft (begg:endg, cft_lb:cft_ub )) if (create_glacier_mec_landunit) then allocate (wt_glc_mec (begg:endg, maxpatch_glcmec)) allocate (topo_glc_mec(begg:endg, maxpatch_glcmec)) @@ -169,7 +172,9 @@ subroutine initialize1( ) allocate (wt_glc_mec (1,1)) allocate (topo_glc_mec(1,1)) endif - + if(use_hillslope) then + allocate (nhillcol (begg:endg )) + endif ! Read list of Patches and their corresponding parameter values ! Independent of model resolution, Needs to stay before surfrd_get_data @@ -209,6 +214,15 @@ subroutine initialize1( ) call initGridCells(glc_behavior) + if(use_hillslope) then + ! Specify hillslope (column-level) connectivity + call initHillslopes() + + ! Set single pft for hillslope columns + call HillslopeDomPft() + + endif + ! Set global seg maps for gridcells, landlunits, columns and patches call decompInit_glcp(ns, ni, nj, glc_behavior) @@ -216,7 +230,7 @@ subroutine initialize1( ) ! Set filters call allocFilters() - + nclumps = get_proc_clumps() !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) do nc = 1, nclumps @@ -242,6 +256,7 @@ subroutine initialize1( ) ! end of the run for error checking. deallocate (wt_lunit, wt_cft, wt_glc_mec) + if(use_hillslope) deallocate (nhillcol) call t_stopf('clm_init1') diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 4da450abc9..f1775ad0e3 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -123,6 +123,18 @@ module clm_varctl ! true => separate crop landunit is not created by default logical, public :: create_crop_landunit = .false. +! JP add + ! number of hillslopes per landunit + integer, public :: nhillslope = 0 + + ! ! Postorder traversal of tree of hillslope columns. In future, will be read in. + ! ! (preorder,postorder) provides unique numbering pair of each hillslope column + ! ! with easy ways to keep track of parent/child hillslope columns. + ! ! Assume preorder is 1:nhillcols. + ! ! Default hillcol_postorder = nillcols:1:-1 creates linearly connected hillslope + ! integer, public :: hillcol_postorder = nillcols:1:-1 +! JP end + ! do not irrigate by default logical, public :: irrigate = .false. @@ -173,6 +185,9 @@ module clm_varctl ! use subgrid fluxes integer, public :: subgridflag = 1 + ! true => repartition rain/snow from atm based on temperature + logical, public :: repartition_rain_snow = .false. + ! true => write global average diagnostics to std out logical, public :: wrtdia = .false. @@ -233,6 +248,12 @@ module clm_varctl logical, public :: use_bedrock = .false. ! true => use spatially variable soil depth character(len=16), public :: soil_layerstruct = '10SL_3.5m' + !---------------------------------------------------------- + ! hillslope hydrology switch + !---------------------------------------------------------- + + logical, public :: use_hillslope = .false. ! true => use multi-column hillslope hydrology + !---------------------------------------------------------- ! plant hydraulic stress switch !---------------------------------------------------------- @@ -255,6 +276,9 @@ module clm_varctl ! true => CLM glacier area & topography changes dynamically logical , public :: glc_do_dynglacier = .false. + ! true => downscale longwave radiation + logical , public :: glcmec_downscale_longwave = .true. + ! number of days before one considers the perennially snow-covered point 'land ice' integer , public :: glc_snow_persistence_max_days = 7300 diff --git a/src/main/clm_varsur.F90 b/src/main/clm_varsur.F90 index a86fe08c64..23eb8fd6ce 100644 --- a/src/main/clm_varsur.F90 +++ b/src/main/clm_varsur.F90 @@ -40,6 +40,10 @@ module clm_instur ! subgrid glacier_mec sfc elevation real(r8), pointer :: topo_glc_mec(:,:) + + ! subgrid hillslope hydrology constituents + integer, pointer :: nhillcol(:) + !----------------------------------------------------------------------- end module clm_instur diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 190042cd4c..0113a8c434 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -222,6 +222,8 @@ subroutine control_init( ) namelist /clm_inparm/ use_bedrock + namelist /clm_inparm/ use_hillslope + namelist /clm_inparm/ use_hydrstress namelist /clm_inparm/ use_dynroot @@ -611,6 +613,8 @@ subroutine control_spmd() call mpi_bcast (use_bedrock, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_hillslope, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_hydrstress, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_dynroot, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -649,6 +653,7 @@ subroutine control_spmd() ! physics variables call mpi_bcast (nsegspc, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (subgridflag , 1, MPI_INTEGER, 0, mpicom, ier) + call mpi_bcast (repartition_rain_snow, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (wrtdia, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (single_column,1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (scmlat, 1, MPI_REAL8,0, mpicom, ier) @@ -665,6 +670,7 @@ subroutine control_spmd() call mpi_bcast (create_glacier_mec_landunit, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (maxpatch_glcmec, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (glc_do_dynglacier, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (glcmec_downscale_longwave, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (glc_snow_persistence_max_days, 1, MPI_INTEGER, 0, mpicom, ier) ! history file variables @@ -813,9 +819,19 @@ subroutine control_print () write(iulog,*) ' Number of snow layers =', nlevsno write(iulog,*) ' Max snow depth (mm) =', h2osno_max + if (repartition_rain_snow) then + write(iulog,*) 'Rain vs. snow will be repartitioned based on surface temperature' + else + write(iulog,*) 'Rain vs. snow will NOT be repartitioned based on surface temperature' + end if if (create_glacier_mec_landunit) then write(iulog,*) ' glc number of elevation classes =', maxpatch_glcmec + if (glcmec_downscale_longwave) then + write(iulog,*) ' Longwave radiation will be downscaled' + else + write(iulog,*) ' Longwave radiation will NOT be downscaled' + endif if (glc_do_dynglacier) then write(iulog,*) ' glc CLM glacier areas and topography WILL evolve dynamically' else @@ -850,6 +866,7 @@ subroutine control_print () write(iulog,*) ' land-ice albedos (unitless 0-1) = ', albice write(iulog,*) ' soil layer structure = ', soil_layerstruct + write(iulog,*) ' hillslope hydrology = ', use_hillslope write(iulog,*) ' plant hydraulic stress = ', use_hydrstress write(iulog,*) ' dynamic roots = ', use_dynroot if (nsrest == nsrContinue) then diff --git a/src/main/decompInitMod.F90 b/src/main/decompInitMod.F90 index cfb683095f..2a94eda31c 100644 --- a/src/main/decompInitMod.F90 +++ b/src/main/decompInitMod.F90 @@ -572,6 +572,7 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) coCount(gi) = icohorts ! number of ED cohorts for local gricell index gi enddo + ! Determine gstart, lstart, cstart, pstart, coStart for the OUTPUT 1d data structures ! gather the gdc subgrid counts to masterproc in glo order diff --git a/src/main/filterMod.F90 b/src/main/filterMod.F90 index 26fbd658d3..a547410041 100644 --- a/src/main/filterMod.F90 +++ b/src/main/filterMod.F90 @@ -68,7 +68,14 @@ module filterMod integer, pointer :: hydrologyc(:) ! hydrology filter (columns) integer :: num_hydrologyc ! number of columns in hydrology filter - +!scs + integer, pointer :: hilltopc(:) ! uppermost column in hillslope + integer :: num_hilltop ! number of hilltop columns + integer, pointer :: hillbottomc(:) ! downhill filter in veg. landunits (columns) + integer :: num_hillbottom ! number of columns downhill + integer, pointer :: hillslopec(:) ! hillslope hydrology filter (columns) + integer :: num_hillslope ! number of hillslope hydrology (columns) +!scs integer, pointer :: urbanl(:) ! urban filter (landunits) integer :: num_urbanl ! number of landunits in urban filter integer, pointer :: nourbanl(:) ! non-urban filter (landunits) @@ -214,7 +221,11 @@ subroutine allocFiltersOneGroup(this_filter) allocate(this_filter(nc)%natvegp(bounds%endp-bounds%begp+1)) allocate(this_filter(nc)%hydrologyc(bounds%endc-bounds%begc+1)) - +!scs + allocate(this_filter(nc)%hilltopc(bounds%endc-bounds%begc+1)) + allocate(this_filter(nc)%hillbottomc(bounds%endc-bounds%begc+1)) + allocate(this_filter(nc)%hillslopec(bounds%endc-bounds%begc+1)) +!scs allocate(this_filter(nc)%urbanp(bounds%endp-bounds%begp+1)) allocate(this_filter(nc)%nourbanp(bounds%endp-bounds%begp+1)) @@ -291,6 +302,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio use pftconMod , only : npcropmin use landunit_varcon , only : istsoil, istcrop, istice_mec use column_varcon , only : is_hydrologically_active + use clm_varcon , only : ispval ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -408,6 +420,49 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio end do this_filter(nc)%num_hydrologyc = f +!scs: currently only natveg (see subgridMod); should be possible +! for a subset of istsoil/istcrop landunits, e.g. when nhillcol = 0 + + ! Create hillslope hydrology filters at column-level + + fs = 0 + do c = bounds%begc,bounds%endc + if (col%active(c) .or. include_inactive) then + l = col%landunit(c) + if (lun%nhillslopes(l) > 0) then + fs = fs + 1 + this_filter(nc)%hillslopec(fs) = c + end if + end if + end do + this_filter(nc)%num_hillslope = fs + + fs = 0 + do c = bounds%begc,bounds%endc + if (col%active(c) .or. include_inactive) then + l = col%landunit(c) + if (lun%nhillslopes(l) > 0 .and. col%colu(c) == ispval) then + fs = fs + 1 + this_filter(nc)%hilltopc(fs) = c + end if + end if + end do + this_filter(nc)%num_hilltop = fs + + fs = 0 + do c = bounds%begc,bounds%endc + if (col%active(c) .or. include_inactive) then + l = col%landunit(c) + if (lun%nhillslopes(l) > 0 .and. col%cold(c) == ispval) then + fs = fs + 1 + this_filter(nc)%hillbottomc(fs) = c + end if + end if + end do + this_filter(nc)%num_hillbottom = fs +!scs + + ! Create prognostic crop and soil w/o prog. crop filters at patch-level ! according to where the crop model should be used diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index ace5527748..03333efd60 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2001,6 +2001,7 @@ subroutine htape_timeconst3D(t, & ! !USES: use subgridAveMod , only : c2g use clm_varpar , only : nlevgrnd ,nlevlak + use clm_varctl , only : nhillslope use shr_string_mod , only : shr_string_listAppend use domainMod , only : ldomain ! @@ -2039,7 +2040,7 @@ subroutine htape_timeconst3D(t, & character(len=*),parameter :: varnamesl(nfldsl) = (/ & 'ZLAKE ', & 'DZLAKE' & - /) + /) !----------------------------------------------------------------------- SHR_ASSERT_ALL((ubound(watsat_col) == (/bounds%endc, nlevgrnd/)), errMsg(sourcefile, __LINE__)) @@ -2323,6 +2324,39 @@ subroutine htape_timeconst(t, mode) long_name='coordinate lake levels', units='m', ncid=nfid(t)) call ncd_defvar(varname='levdcmp', xtype=tape(t)%ncprec, dim1name='levdcmp', & long_name='coordinate soil levels', units='m', ncid=nfid(t)) + +!scs + if (ldomain%isgrid2d) then + !pass + else +!!$ call ncd_defvar(varname='hslp_distance' , xtype=ncd_double, & +!!$ dim1name=namec, & +!!$ long_name='hillslope column distance', ncid=nfid(t), & +!!$ imissing_value=spval, ifill_value=spval) + + call ncd_defvar(varname='hslp_distance', xtype=ncd_double, & + dim1name=namec, long_name='hillslope column distance', & + units='m', ncid=nfid(t)) + call ncd_defvar(varname='hslp_width', xtype=ncd_double, & + dim1name=namec, long_name='hillslope column width', & + units='m', ncid=nfid(t)) + call ncd_defvar(varname='hslp_area', xtype=ncd_double, & + dim1name=namec, long_name='hillslope column area', & + units='m', ncid=nfid(t)) + call ncd_defvar(varname='hslp_elev', xtype=ncd_double, & + dim1name=namec, long_name='hillslope column elevation', & + units='m', ncid=nfid(t)) + call ncd_defvar(varname='hslp_slope', xtype=ncd_double, & + dim1name=namec, long_name='hillslope column slope', & + units='m', ncid=nfid(t)) + call ncd_defvar(varname='hslp_index', xtype=ncd_int, & + dim1name=namec, long_name='hillslope index', & + ncid=nfid(t)) + call ncd_defvar(varname='hslp_cold', xtype=ncd_int, & + dim1name=namec, long_name='hillslope downhill column index', & + ncid=nfid(t)) + end if +!scs if(use_ed)then call ncd_defvar(varname='levscls', xtype=tape(t)%ncprec, dim1name='levscls', & @@ -2343,6 +2377,17 @@ subroutine htape_timeconst(t, mode) zsoi_1d(1) = 1._r8 call ncd_io(varname='levdcmp', data=zsoi_1d, ncid=nfid(t), flag='write') end if +!scs + if (.not.ldomain%isgrid2d) then + call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_elev' , data=col%hill_elev, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') + endif + if(use_ed)then call ncd_io(varname='levscls',data=levsclass_ed, ncid=nfid(t), flag='write') call ncd_io(varname='pft_levscpf',data=pft_levscpf_ed, ncid=nfid(t), flag='write') @@ -2706,6 +2751,9 @@ subroutine hfields_write(t, mode) ! Write history output. Always output land and ocean runoff on xy grid. if (num2d == 1) then +! JP add, for debugging +! write(iulog,*) "JP: varname: ", varname +! JP end call ncd_io(flag='write', varname=varname, & dim1name=type1d_out, data=hist1do, ncid=nfid(t), nt=nt) else @@ -2866,8 +2914,10 @@ subroutine hfields_1dinfo(t, mode) !call ncd_defvar(varname='pfts1d_li', xtype=ncd_int, dim1name='pft', & ! long_name='1d landunit index of corresponding pft', ncid=ncid) - !call ncd_defvar(varname='pfts1d_ci', xtype=ncd_int, dim1name='pft', & - ! long_name='1d column index of corresponding pft', ncid=ncid) +!scs: commenting-in for hillslope hydrology (multi-column) code + call ncd_defvar(varname='pfts1d_ci', xtype=ncd_int, dim1name='pft', & + long_name='1d column index of corresponding pft', ncid=ncid) +!scs ! ---------------------------------------------------------------- call ncd_defvar(varname='pfts1d_wtgcell', xtype=ncd_double, dim1name=namep, & @@ -3007,7 +3057,9 @@ subroutine hfields_1dinfo(t, mode) ! --- EBK Do NOT write out indices that are incorrect 4/1/2011 --- Bug 1310 !call ncd_io(varname='pfts1d_gi' , data=patch%gridcell, dim1name=namep, ncid=ncid, flag='write') !call ncd_io(varname='pfts1d_li' , data=patch%landunit, dim1name=namep, ncid=ncid, flag='write') - !call ncd_io(varname='pfts1d_ci' , data=patch%column , dim1name=namep, ncid=ncid, flag='write') +!scs: commenting-in for hillslope hydrology + call ncd_io(varname='pfts1d_ci' , data=patch%column , dim1name=namep, ncid=ncid, flag='write') +!scs ! ---------------------------------------------------------------- call ncd_io(varname='pfts1d_wtgcell' , data=patch%wtgcell , dim1name=namep, ncid=ncid, flag='write') call ncd_io(varname='pfts1d_wtlunit' , data=patch%wtlunit , dim1name=namep, ncid=ncid, flag='write') diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index 8e54576bb9..ac7c325cdc 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -13,7 +13,7 @@ module initGridCellsMod ! these modules (or the two modules should be combined into one). ! ! !USES: -#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use spmdMod , only : masterproc,iam @@ -276,10 +276,14 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) integer :: m ! index integer :: ncohorts integer :: npatches ! number of patches in landunit +! JP add + integer :: ci2 ! tmp 2nd col. index +! JP end integer :: ncols integer :: nlunits integer :: pitype ! patch itype real(r8) :: wtlunit2gcell ! landunit weight in gridcell + real(r8) :: wtcol2lunit ! column weight in landunit !------------------------------------------------------------------------ ! Set decomposition properties @@ -290,13 +294,22 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) if (npatches > 0) then call add_landunit(li=li, gi=gi, ltype=ltype, wtgcell=wtlunit2gcell) - - ! Assume one column on the landunit - call add_column(ci=ci, li=li, ctype=1, wtlunit=1.0_r8) - do m = natpft_lb,natpft_ub - call add_patch(pi=pi, ci=ci, ptype=m, wtcol=wt_nat_patch(gi,m)) + ! ! Assume one column on the landunit + ! call add_column(ci=ci, li=li, ctype=1, wtlunit=1.0_r8) + + ! do m = natpft_lb,natpft_ub + ! call add_patch(pi=pi, ci=ci, ptype=m, wtcol=wt_nat_patch(gi,m)) + ! end do +!scs + wtcol2lunit = 1.0_r8/real(ncols,r8) + do ci2 = 1,ncols + call add_column(ci=ci, li=li, ctype=1, wtlunit=wtcol2lunit) + do m = natpft_lb,natpft_ub + call add_patch(pi=pi, ci=ci, ptype=m, wtcol=wt_nat_patch(gi,m)) + end do end do +!scs end if end subroutine set_landunit_veg_compete diff --git a/src/main/initSubgridMod.F90 b/src/main/initSubgridMod.F90 index 363e0ac4f5..efd3d61351 100644 --- a/src/main/initSubgridMod.F90 +++ b/src/main/initSubgridMod.F90 @@ -199,10 +199,15 @@ subroutine clm_ptrs_check(bounds) error = .false. if (minval(lun%gridcell(begl:endl)) < begg .or. maxval(lun%gridcell(begl:endl)) > endg) error=.true. + if (error) write(iulog,*) 'isgerror1' if (minval(lun%coli(begl:endl)) < begc .or. maxval(lun%coli(begl:endl)) > endc) error=.true. + if (error) write(iulog,*) 'isgerror2' if (minval(lun%colf(begl:endl)) < begc .or. maxval(lun%colf(begl:endl)) > endc) error=.true. + if (error) write(iulog,*) 'isgerror3' if (minval(lun%patchi(begl:endl)) < begp .or. maxval(lun%patchi(begl:endl)) > endp) error=.true. + if (error) write(iulog,*) 'isgerror4' if (minval(lun%patchf(begl:endl)) < begp .or. maxval(lun%patchf(begl:endl)) > endp) error=.true. + if (error) write(iulog,*) 'isgerror5' if (error) then write(iulog,*) ' clm_ptrs_check: l index ranges - ERROR' call endrun(msg=errMsg(sourcefile, __LINE__)) diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index 49918829e7..e172dd801b 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -19,9 +19,10 @@ module initVerticalMod use clm_varctl , only : use_vancouver, use_mexicocity, use_vertsoilc, use_extralakelayers use clm_varctl , only : use_bedrock, soil_layerstruct use clm_varctl , only : use_ed + use clm_varctl , only : nhillslope use clm_varcon , only : zlak, dzlak, zsoi, dzsoi, zisoi, dzsoi_decomp, spval, ispval, grlnd use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, is_hydrologically_active - use landunit_varcon , only : istdlak, istice_mec + use landunit_varcon , only : istdlak, istice_mec, istsoil use fileutils , only : getfil use LandunitType , only : lun use GridcellType , only : grc @@ -109,6 +110,8 @@ end subroutine ReadNL !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof) use clm_varcon, only : zmin_bedrock + use clm_varctl, only : use_hillslope + use HillslopeHydrologyMod ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -118,7 +121,7 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof real(r8) , intent(in) :: thick_roof(bounds%begl:) ! ! LOCAL VARAIBLES: - integer :: c,l,g,i,j,lev ! indices + integer :: c,l,g,i,j,lev,nh ! indices type(file_desc_t) :: ncid ! netcdf id logical :: readvar integer :: dimid ! dimension id @@ -131,8 +134,10 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof integer :: ier ! error status real(r8) :: scalez = 0.025_r8 ! Soil layer thickness discretization (m) real(r8) :: thick_equal = 0.2 - real(r8) ,pointer :: zbedrock_in(:) ! read in - z_bedrock - real(r8) ,pointer :: lakedepth_in(:) ! read in - lakedepth + real(r8), pointer :: ihillslope_in(:,:) ! read in - integer + real(r8), pointer :: fhillslope_in(:,:) ! read in - float + real(r8), pointer :: lakedepth_in(:) ! wall (layer node depth) + real(r8), pointer :: zbedrock_in(:) ! read in - float real(r8), allocatable :: zurb_wall(:,:) ! wall (layer node depth) real(r8), allocatable :: zurb_roof(:,:) ! roof (layer node depth) real(r8), allocatable :: dzurb_wall(:,:) ! wall (layer thickness) @@ -143,7 +148,15 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof integer :: begc, endc integer :: begl, endl integer :: jmin_bedrock - +!scs + integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope + real(r8), allocatable :: hill_alpha(:,:) ! hillslope 'alpha' parameter + real(r8), allocatable :: hill_beta(:,:) ! hillslope 'beta' parameter + real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] + real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] + real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] + real(r8) :: hillslope_area ! total area of hillslope + integer :: ctop, cbottom ! hillslope top and bottom column indices ! Possible values for levgrnd_class. The important thing is that, for a given column, ! layers that are fundamentally different (e.g., soil vs bedrock) have different ! values. This information is used in the vertical interpolation in init_interp. @@ -279,6 +292,66 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof do j = 1, nlevgrnd zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) enddo +! JP add + else if ( soil_layerstruct == '20SL_1.5m' ) then + do j=1,nlevsoi + dzsoi(j) = 1.5_r8/nlevsoi + end do + + do j = nlevsoi+1,nlevgrnd +! dzsoi(j)= 0.5_r8 ! 0.5 meter bedrock layers + dzsoi(j)= 1.5_r8/nlevsoi ! bedrock layers same thickness of soil layers + enddo + + zisoi(0) = 0._r8 + do j = 1,nlevgrnd + zisoi(j)= sum(dzsoi(1:j)) + enddo + + do j = 1, nlevgrnd + zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) + enddo +! JP end +! JP add + else if ( soil_layerstruct == '10SL_1.5m' ) then + do j=1,nlevsoi + dzsoi(j) = 1.5_r8/nlevsoi + end do + + do j = nlevsoi+1,nlevgrnd +! dzsoi(j)= 0.5_r8 ! 0.5 meter bedrock layers + dzsoi(j)= 1.5_r8/nlevsoi ! bedrock layers same thickness of soil layers + enddo + + zisoi(0) = 0._r8 + do j = 1,nlevgrnd + zisoi(j)= sum(dzsoi(1:j)) + enddo + + do j = 1, nlevgrnd + zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) + enddo +! JP end +! JP add + else if ( soil_layerstruct == '10SL_0.6m' ) then + do j=1,nlevsoi + dzsoi(j) = 0.6_r8/nlevsoi + end do + + do j = nlevsoi+1,nlevgrnd +! dzsoi(j)= 0.5_r8 ! 0.5 meter bedrock layers + dzsoi(j)= 0.6_r8/nlevsoi ! bedrock layers same thickness of soil layers + enddo + + zisoi(0) = 0._r8 + do j = 1,nlevgrnd + zisoi(j)= sum(dzsoi(1:j)) + enddo + + do j = 1, nlevgrnd + zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) + enddo +! JP end end if ! define a vertical grid spacing such that it is the normal dzsoi if @@ -525,6 +598,210 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof deallocate(zbedrock_in) + !----------------------------------------------- + ! Specify hillslope hydrology characteristics + !----------------------------------------------- + if(use_hillslope) then + allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & + hill_alpha(bounds%begl:bounds%endl,nhillslope), & + hill_beta(bounds%begl:bounds%endl,nhillslope), & + hill_length(bounds%begl:bounds%endl,nhillslope), & + hill_width(bounds%begl:bounds%endl,nhillslope), & + hill_height(bounds%begl:bounds%endl,nhillslope), & + stat=ier) + + allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) + + call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + pct_hillslope(l,:) = ihillslope_in(g,:) + enddo + deallocate(ihillslope_in) + + allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) + call ncd_io(ncid=ncid, varname='h_alpha', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_alpha not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_alpha(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_beta', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_beta not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_beta(l,:) = fhillslope_in(g,:) + enddo + call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_length(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_width(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_height(l,:) = fhillslope_in(g,:) + enddo + deallocate(fhillslope_in) + + ! Set hillslope hydrology column level variables + ! This needs to match how columns set up in subgridMod + do l = begl, endl + g = lun%gridcell(l) + if(lun%itype(l) == istsoil) then + ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost + + if (masterproc .and. 1==2) then + write(iulog,*) 'hillslope parameters' + do nh=1,nhillslope + write(iulog,'(a12,i8,5f16.4)') 'a,b,l,w,h: ', nh, hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), hill_width(l,nh),hill_height(l,nh) + write(iulog,*) ' ' + enddo + endif + + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + ctop = lun%coli(l)+(nh-1)*lun%ncolumns(l)/nhillslope + cbottom = lun%coli(l)+(nh)*lun%ncolumns(l)/nhillslope - 1 + if (masterproc .and. 1==2) then + write(iulog,*) 'hillslope distance columns' + write(iulog,'(a12,3i8,5f16.4)') 'top,c,bot: ', ctop,c,cbottom + write(iulog,*) ' ' + endif + + ! distance of lower edge of column from hillslope bottom + col%hill_distance(c) = hcol_distance(c, & + ctop, cbottom, hill_length(l,nh)) + ! if (masterproc) write(iulog,*) 'hd: ',c,col%hill_distance(c) + + ! width of lower edge of column from hillslope bottom + col%hill_width(c) = hcol_width(col%hill_distance(c),& + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'hw: ',c,col%hill_width(c) + + ! surface area of column + if (c == ctop) then + col%hill_area(c) = hcol_area(hill_length(l,nh),& + col%hill_distance(c), & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + else + col%hill_area(c) = hcol_area(col%hill_distance(c-1),& + col%hill_distance(c),& + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + endif + ! if (masterproc) write(iulog,*) 'ha: ',c,col%hill_area(c) + + ! mean elevation of column relative to mean gridcell elevation + if (c == ctop) then + col%hill_elev(c) = hcol_elevation(hill_length(l,nh),& + col%hill_distance(c),& + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + else + col%hill_elev(c) = hcol_elevation(col%hill_distance(c-1),& + col%hill_distance(c),& + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + endif + ! if (masterproc) write(iulog,*) 'he: ',c,col%hill_elev(c) + + ! mean along-hill slope of column + if (c == ctop) then + col%hill_slope(c) = hcol_slope(hill_length(l,nh),col%hill_distance(c),hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) + else + col%hill_slope(c) = hcol_slope(col%hill_distance(c-1),col%hill_distance(c),hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) + endif + ! if (masterproc) write(iulog,*) 'hs: ',c,col%hill_slope(c) + + if (masterproc .and. 1==2) then + write(iulog,*) 'hillslope geometry' + write(iulog,'(a12,i4,i10,5f16.4)') 'd,w,a,e,s: ', nh, c, col%hill_distance(c), col%hill_width(c), col%hill_area(c), col%hill_elev(c), col%hill_slope(c) + write(iulog,*) ' ' + endif + + enddo + + ! Now that column areas are determined, column weights can be recalculated + hillslope_area = 0._r8 + ! area weighted by pct_hillslope + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + hillslope_area = hillslope_area & + + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + enddo + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + col%wtlunit(c) = col%hill_area(c) & + * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + enddo + + ! Set column bedrock index + !thin soil for non-riparian columns, thick for riparian + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) /= ispval) then + do j = jmin_bedrock,nlevsoi + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + enddo + else + do j = jmin_bedrock,nlevsoi + if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then + col%nbedrock(c) = j + end if + enddo + endif + end do + + endif ! end of istsoil + enddo ! end of loop over landunits + + deallocate(pct_hillslope,hill_alpha,hill_beta,hill_length, & + hill_width,hill_height) + + endif !use_hillslope + !----------------------------------------------- ! Set lake levels and layers (no interfaces) !----------------------------------------------- @@ -693,6 +970,9 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof g = col%gridcell(c) ! check for near zero slopes, set minimum value col%topo_slope(c) = max(tslope(g), 0.2_r8) +! JP add for testing +! write(iulog,*) 'JP:slope(c): ',col%topo_slope(c) +! JP end end do deallocate(tslope) diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 1924edaf68..1e1b1f964a 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -54,6 +54,8 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & ! !DESCRIPTION: ! Obtain gridcell properties, aggregated across all landunits ! + ! !USES + ! ! !ARGUMENTS integer , intent(in) :: gi ! grid cell index type(glc_behavior_type), intent(in) :: glc_behavior @@ -72,6 +74,8 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & ! atm_topo is arbitrary for the sake of getting these counts. We don't have a true ! atm_topo value at the point of this call, so use 0. real(r8), parameter :: atm_topo = 0._r8 + + !------------------------------------------------------------------------------ npatches = 0 @@ -130,6 +134,10 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) ! ! !USES use clm_varpar, only : natpft_size + use clm_instur, only : nhillcol + use clm_varctl, only : nhillslope, use_hillslope + + ! ! !ARGUMENTS: integer, intent(in) :: gi ! grid cell index @@ -150,9 +158,15 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) npatches = natpft_size - ! Assume that the vegetated landunit has one column nlunits = 1 - ncols = 1 + if(use_hillslope) then + ncols = nhillslope * nhillcol(gi) + else + ncols = 1 + endif + npatches = ncols*natpft_size + +! write(iulog,*) 'nhillslope, nhillcol, ncols:', nhillslope, nhillcol(gi), ncols ! ------------------------------------------------------------------------- ! Number of cohorts is set here @@ -162,7 +176,6 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) ! For restart output however, we will allocate the cohort vector space ! based on all columns. ! ------------------------------------------------------------------------- - ncohorts = ncols*cohorts_per_col end subroutine subgrid_get_info_natveg @@ -496,6 +509,4 @@ function crop_patch_exists(gi, cft) result(exists) end function crop_patch_exists - - end module subgridMod diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 4e321d0c6b..66c7629af4 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -302,7 +302,7 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat) ! o real % abundance PFTs (as a percent of vegetated area) ! ! !USES: - use clm_varctl , only : create_crop_landunit + use clm_varctl , only : create_crop_landunit, use_hillslope use fileutils , only : getfil use domainMod , only : domain_type, domain_init, domain_clean use clm_instur , only : wt_lunit, topo_glc_mec @@ -414,6 +414,11 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat) call surfrd_veg_all(begg, endg, ncid, ldomain%ns) + ! Obtain hillslope hydrology info + if(use_hillslope) then + call surfrd_hillslope(begg, endg, ncid, ldomain%ns) + endif + if (use_cndv) then call surfrd_veg_dgvm(begg, endg) end if @@ -724,4 +729,55 @@ subroutine surfrd_veg_dgvm(begg, endg) end subroutine surfrd_veg_dgvm + !----------------------------------------------------------------------- + subroutine surfrd_hillslope(begg, endg, ncid, ns) + ! + ! !DESCRIPTION: + ! Determine number of hillslopes and columns for hillslope hydrology mode + ! + ! !USES: + use clm_instur, only : nhillcol + use clm_varctl, only : nhillslope + use ncdio_pio , only : ncd_inqdid, ncd_inqdlen + ! + ! !ARGUMENTS: + integer, intent(in) :: begg, endg + type(file_desc_t),intent(inout) :: ncid ! netcdf id + integer ,intent(in) :: ns ! domain size + ! + ! !LOCAL VARIABLES: + integer :: nh, m ! index + integer :: dimid,varid ! netCDF id's + integer :: ier ! error status + logical :: readvar ! is variable on dataset + real(r8),pointer :: arrayl(:) ! local array + character(len=32) :: subname = 'surfrd_hillslope' ! subroutine name +!----------------------------------------------------------------------- + + ! This temporary array is needed because ncd_io expects a pointer, + !so we can't directly pass + + allocate(arrayl(begg:endg)) + call ncd_inqdid(ncid,'nhillslope',dimid,readvar) + if (.not. readvar) then + write(iulog,*)'surfrd error: nhillslope not on surface data file' + nhillslope = 1 + else + call ncd_inqdlen(ncid,dimid,nh) + nhillslope = nh + endif + + call ncd_io(ncid=ncid, varname='nhillcol', flag='read', data=arrayl, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + write(iulog,*)'surfrd error: nhillcol not on surface data file' + nhillcol(begg:endg) = 1 + write(iulog,*)'setting nhillcol[:] = 1' + else + nhillcol(begg:endg) = arrayl(begg:endg) + endif + deallocate(arrayl) + + end subroutine surfrd_hillslope + end module surfrdMod From 1af8d1181978c6acd31abf810b721d03172ee000 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 10 Feb 2017 16:03:48 +0000 Subject: [PATCH 002/153] hillslope_hydrology_n02_clm4_5_14_r223 added new routines --- src/biogeophys/HillslopeHydrologyMod.F90 | 238 +++++++++++++++++++++++ src/main/initHillslopeMod.F90 | 195 +++++++++++++++++++ 2 files changed, 433 insertions(+) create mode 100644 src/biogeophys/HillslopeHydrologyMod.F90 create mode 100644 src/main/initHillslopeMod.F90 diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 new file mode 100644 index 0000000000..74fab4a537 --- /dev/null +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -0,0 +1,238 @@ +module HillslopeHydrologyMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Calculate geomorphological quantities for hillslope columns. + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc + use abortutils , only : endrun + use clm_varctl , only : iulog + + implicit none + private + save + + ! !PUBLIC MEMBER FUNCTIONS: + public :: hcol_distance + public :: hcol_width + public :: hcol_area + public :: hcol_elevation + public :: hcol_slope + + + ! !PRIVATE MEMBER FUNCTIONS: +! private :: + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + !----------------------------------------------------------------------- + +contains + + !------------------------------------------------------------------------------ + function hcol_distance(c, ctop, cbottom, hill_length) result(x) + ! + ! !DESCRIPTION: + ! Returns distance from the bottom of the hillslope of the + ! column's lower edge. Assumes hilltop to hillbottom column + ! ordering based on lun%coli, lun%colf (see initHillslopeMod). + ! + ! !USES: + ! + ! !ARGUMENTS: + real(r8) :: x ! function result + integer, intent(in) :: c ! current column + integer, intent(in) :: ctop ! hillslope top column + integer, intent(in) :: cbottom ! hillslope bottom column + real(r8), intent(in) :: hill_length ! total hillslope length + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'hcol_distance' + !----------------------------------------------------------------------- + + x = hill_length * real(cbottom - c,r8) & + / real(cbottom - ctop + 1,r8) + + end function hcol_distance + + function hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) result(width) + ! + ! !DESCRIPTION: + ! Returns width of lower edge of hillslope column. + ! + ! !USES: + ! + ! !ARGUMENTS: + real(r8) :: width ! function result + real(r8), intent(in) :: x ! distance along hillslope + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + real(r8) :: eps = 1.e-6_r8 + real(r8) :: y0 ! y integration limit + character(len=*), parameter :: subname = 'hcol_width' + !----------------------------------------------------------------------- + + ! width function has special case for n = 2 + ! in this implementation, integration limits depend on sign of beta + if (abs(alpha - 2._r8) < eps) then + y0 = hill_width/2._r8 + ! log blows up at x=0; 0.2 set by trial and error + if(beta < 0._r8) y0 = y0*exp(-(beta*hill_length**2/hill_height) & + * log(0.2/hill_length)) + + ! compiler does not like log(zero) + if (x == 0._r8) then + if (beta > 0) then + width = eps + else + width = hill_width/2._r8! - y0 + endif + else + width = exp(((beta*hill_length**2/hill_height) & + * log(x/hill_length)) + log(y0)) + endif + else ! n /= 2 + y0 = hill_width/2._r8 + if(beta > 0._r8) then + y0 = y0 * exp(-(2._r8*beta*hill_length**2) & + / (hill_height*(2._r8 - alpha)*alpha)) + endif + ! compiler does not like zero to a negative power. + if (x == 0._r8) then + width = y0 + else + width = exp((((2._r8*beta*hill_length**2) & + / (hill_height*(2._r8 - alpha)*alpha)) & + * (x/hill_length)**(2._r8-alpha)) & + + log(y0)) + endif + endif + ! hillslope width is twice integral [0:x] + width = 2._r8 * width + + end function hcol_width + + function hcol_area(xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(area) + ! + ! !DESCRIPTION: + ! Returns area of a hillslope column. Area is calculated by + ! numerically integrating using hcol_width function. + ! + ! + ! !USES: + ! + ! !ARGUMENTS: + real(r8) :: area ! function result + real(r8), intent(in) :: xtop ! upper integration limit + real(r8), intent(in) :: xbottom ! lower integration limit + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + integer :: n + integer, parameter :: ndiv = 100 + real(r8) :: x + real(r8) :: dx + character(len=*), parameter :: subname = 'hcol_area' + !----------------------------------------------------------------------- + ! surface area of column + dx = (xtop - xbottom)/real(ndiv) + + area = 0._r8 + do n = 0, ndiv-1 + x = xbottom + (n+0.5)*dx + area = area + dx * hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) + enddo + + end function hcol_area + + function hcol_elevation(xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) + ! + ! !DESCRIPTION: + ! Returns mean elevation of column (relative to hillslope bottom). + ! Area-weighted mean elevation is calculated by + ! numerically integrating using hcol_width function. ! + ! !USES: + ! + ! !ARGUMENTS: + real(r8) :: elev ! function result + real(r8), intent(in) :: xtop ! upper integration limit + real(r8), intent(in) :: xbottom ! lower integration limit + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + integer :: n + integer, parameter :: ndiv = 100 + real(r8) :: x, y + real(r8) :: dx + real(r8) :: dA + real(r8) :: area + character(len=*), parameter :: subname = 'hcol_elevation' + !----------------------------------------------------------------------- + ! mean elevation of column relative to hillslope bottom + ! elevation is first integrated analytically in across-slope direction + ! then summed in along-slope direction + + dx = (xtop - xbottom)/real(ndiv) + + elev = 0._r8 + area = 0._r8 + do n = 0, ndiv-1 + x = xbottom + (n+0.5)*dx + y = hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) + dA = dx * y + area = area + dA + elev = elev + dx * (hill_height*y*(x/hill_length)**alpha & + + beta*y**3/12._r8) + enddo + elev = elev / area + + end function hcol_elevation + + function hcol_slope(xtop,xbottom,alpha, hill_length, hill_height) result(slope) + ! + ! !DESCRIPTION: + ! Returns mean along-hillslope slope of hillslope column + ! + ! !USES: + ! + ! !ARGUMENTS: + real(r8) :: slope ! function result + real(r8), intent(in) :: xtop ! distance to upper edge of column + real(r8), intent(in) :: xbottom ! distance to lower edge of column + real(r8), intent(in) :: alpha ! hillslope profile curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'hcol_slope' + !----------------------------------------------------------------------- + + ! mean along-hill slope of column + slope = hill_height & + * ((xtop/hill_length)**alpha & + - (xbottom/hill_length)**alpha) & + / (xtop - xbottom) + + end function hcol_slope + +end module HillslopeHydrologyMod diff --git a/src/main/initHillslopeMod.F90 b/src/main/initHillslopeMod.F90 new file mode 100644 index 0000000000..43f2ba949f --- /dev/null +++ b/src/main/initHillslopeMod.F90 @@ -0,0 +1,195 @@ +module initHillslopeMod + +#include "shr_assert.h" + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Initializes (column-level) hillslope connectivity. + ! + ! !USES: + + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc,iam + use abortutils , only : endrun + use clm_varctl , only : iulog + use decompMod , only : bounds_type + use LandunitType , only : lun + use ColumnType , only : col + + ! + ! !PUBLIC TYPES: + implicit none + private + ! + ! !PUBLIC MEMBER FUNCTIONS: + public initHillslopes ! initialize hillslope connectivity + public HillslopeDomPft ! change patch weights to a single pft + ! + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + !----------------------------------------------------------------------- + +contains + + !------------------------------------------------------------------------ + subroutine initHillslopes() + ! + ! !DESCRIPTION: + ! Initialize hillslope connectivity. Each landunit may have multiple + ! hillslopes, and each hillslope may have multiple columns. Specify + ! uphill and downhill neighbors sequentially based on col%coli, col%colf. + ! Hilltop columns have no uphill neighbor; hillbottom columns have no + ! downhill neighbor. + + ! + ! !USES + use decompMod , only : get_proc_bounds, get_clump_bounds, get_proc_clumps + use clm_varctl , only : nhillslope + use landunit_varcon , only : istsoil, istcrop + ! + ! !ARGUMENTS: + ! + ! !LOCAL VARIABLES: + integer :: n,nc,nh,l,c,ci,cf ! indices + integer :: nclumps ! number of clumps on this processor + integer :: ncol_per_hill + type(bounds_type) :: bounds_proc + type(bounds_type) :: bounds_clump + integer :: begg, endg, begl, endl, begc, endc, begp, endp, & + begCohort, endCohort + !------------------------------------------------------------------------ + + nclumps = get_proc_clumps() + + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + do nc = 1, nclumps + + call get_clump_bounds(nc, bounds_clump) + + do l = bounds_clump%begl, bounds_clump%endl + +! Set number of hillslopes; total number of columns already set +! in clm_ptrs_compdown; this must be consistent with how columns set in +! subgrid_get_info_* routines in subgridMod +! currently only _natveg specifies multiple columns + if (lun%itype(l) == istsoil) then + lun%nhillslopes(l) = nhillslope + else + lun%nhillslopes(l) = 0 + endif + + if (lun%nhillslopes(l) > 0) then + +! number of columns per hillslope = lun%ncolumns / lun%nhillslopes +! 1st column index of each hillslope is coli+(n-1)*ncol_per_hill for n(1:nhillslope) +! last column index is coli+n*ncol_per_hill-1 + ncol_per_hill = lun%ncolumns(l) / lun%nhillslopes(l) + ! loop over hillslopes + do nh = 1,lun%nhillslopes(l) + ci = lun%coli(l) + (nh-1)*ncol_per_hill + cf = lun%coli(l) + (nh)*ncol_per_hill - 1 + ! loop over columns within each hillslope + do n = 1, ncol_per_hill + c = ci + (n-1) + + col%hillslope_ndx(c) = nh + + ! downhill columns (hillbottom has no downhill neighbor) + if(c < cf) then + col%cold(c) = c + 1 + endif + ! uphill columns (hilltop has no uphill neighbor) + if(c > ci) then + col%colu(c) = c - 1 + endif + enddo ! end loop n + enddo ! end loop nh + endif + +!!$ if(lun%itype(l) == istsoil) then +!!$ write(iulog,*) 'testlun: ', l,lun%ncolumns(l), lun%nhillslopes(l),lun%coli(l),lun%colf(l) +!!$ do c=lun%coli(l), lun%colf(l) +!!$ write(iulog,*) 'testconn: ', l,c,col%cold(c),col%colu(c) +!!$ enddo +!!$! call endrun(msg='thats it!!') +!!$ endif + + enddo ! end loop l + enddo ! end loop nc + !$OMP END PARALLEL DO + + end subroutine initHillslopes + + !------------------------------------------------------------------------ + subroutine HillslopeDomPft() + ! + ! !DESCRIPTION: + ! Reassign patch weights such that each column has a single, + ! dominant pft. + + ! + ! !USES + use decompMod , only : get_clump_bounds, get_proc_clumps + use clm_varcon , only : ispval + use landunit_varcon , only : istsoil, istcrop + use PatchType , only : patch + ! + ! !ARGUMENTS: + ! + ! !LOCAL VARIABLES: + integer :: n,nc,p,pu,pl,l,c ! indices + integer :: nclumps ! number of clumps on this processor + integer :: upland_ivt = 13 ! c3 non-arctic grass + integer :: lowland_ivt = 8 ! broadleaf deciduous tree + real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc + type(bounds_type) :: bounds_proc + type(bounds_type) :: bounds_clump + + !------------------------------------------------------------------------ + + nclumps = get_proc_clumps() + + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + do nc = 1, nclumps + + call get_clump_bounds(nc, bounds_clump) + + do l = bounds_clump%begl, bounds_clump%endl + + if (lun%itype(l) == istsoil) then + do c = lun%coli(l), lun%colf(l) + + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + + do p = col%patchi(c), col%patchf(c) + if(patch%itype(p) == lowland_ivt) pl = p + if(patch%itype(p) == upland_ivt) pu = p + enddo + + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + + ! hillbottom + if(col%cold(c) == ispval) then + patch%wtcol(pl) = sum_wtcol + patch%wtlunit(pl) = sum_wtlun + patch%wtgcell(pl) = sum_wtgrc + else + patch%wtcol(pu) = sum_wtcol + patch%wtlunit(pu) = sum_wtlun + patch%wtgcell(pu) = sum_wtgrc + endif + enddo ! end loop c + endif + enddo ! end loop l + enddo ! end loop nc + !$OMP END PARALLEL DO + + end subroutine HillslopeDomPft + +end module initHillslopeMod From ee1fc0ea4990935e03662db2ae6f10ce1f7e284d Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 13 Feb 2017 17:27:06 +0000 Subject: [PATCH 003/153] hillslope_hydrology_n03_clm4_5_14_r223 removed intials --- src/biogeophys/BalanceCheckMod.F90 | 1 - src/biogeophys/HydrologyDrainageMod.F90 | 5 ++-- src/biogeophys/HydrologyNoDrainageMod.F90 | 5 ++-- src/biogeophys/SoilHydrologyMod.F90 | 35 ++++++----------------- src/biogeophys/WaterStateType.F90 | 6 ---- src/main/ColumnType.F90 | 5 ---- src/main/clm_driver.F90 | 4 +-- src/main/clm_varcon.F90 | 2 +- src/main/clm_varctl.F90 | 9 ------ src/main/filterMod.F90 | 10 ++----- src/main/histFileMod.F90 | 20 ++++--------- src/main/initGridCellsMod.F90 | 16 ++--------- src/main/initVerticalMod.F90 | 12 +------- 13 files changed, 27 insertions(+), 103 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index f49885193e..10c57a1a3e 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -311,7 +311,6 @@ subroutine BalanceCheck( bounds, & - qflx_drain_perched(c) & - qflx_ice_runoff_snwcp(c) & - qflx_ice_runoff_xs(c) & -!scs - qflx_net_latflow(c)) * dtime ) * dtime else diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 9614b57724..b8b4696ff3 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -33,7 +33,7 @@ module HydrologyDrainageMod contains !----------------------------------------------------------------------- -! JP changed inputs + subroutine HydrologyDrainage(bounds, & num_hilltop, filter_hilltopc, & num_hillbottom, filter_hillbottomc, & @@ -69,14 +69,13 @@ subroutine HydrologyDrainage(bounds, & integer , intent(in) :: filter_urbanc(:) ! column filter for urban points integer , intent(in) :: num_do_smb_c ! number of bareland columns in which SMB is calculated, in column filter integer , intent(in) :: filter_do_smb_c(:) ! column filter for bare land SMB columns -! JP add integer , intent(in) :: num_hilltop ! number of soil cols marked "upslope" integer , intent(in) :: filter_hilltopc(:) ! column filter for designating "upslope" cols. integer , intent(in) :: num_hillbottom ! number of soil cols marked "downslope" integer , intent(in) :: filter_hillbottomc(:) ! column filter for designating "downslope" cols. integer , intent(in) :: num_hillslope ! number of soil hill cols. integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hill cols. -! JP end + type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(glc2lnd_type) , intent(in) :: glc2lnd_inst type(temperature_type) , intent(in) :: temperature_inst diff --git a/src/biogeophys/HydrologyNoDrainageMod.F90 b/src/biogeophys/HydrologyNoDrainageMod.F90 index 6ce53a1985..7eb6c0f3dc 100644 --- a/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -32,7 +32,7 @@ Module HydrologyNoDrainageMod contains !----------------------------------------------------------------------- -!scs + subroutine HydrologyNoDrainage(bounds, & num_hillslope, filter_hillslopec, & num_nolakec, filter_nolakec, & @@ -88,10 +88,9 @@ subroutine HydrologyNoDrainage(bounds, & integer , intent(inout) :: filter_snowc(:) ! column filter for snow points integer , intent(inout) :: num_nosnowc ! number of column non-snow points integer , intent(inout) :: filter_nosnowc(:) ! column filter for non-snow points -! JP add integer , intent(in) :: num_hillslope ! number of hillslope soil cols integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. -! JP end + type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(soilstate_type) , intent(inout) :: soilstate_inst type(energyflux_type) , intent(in) :: energyflux_inst diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index a2bdf15471..318c33c6d0 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1,11 +1,4 @@ module SoilHydrologyMod -! JP NOTES: CHANGES -! 1: Rewrote in terms of volume fluxes -! 2: Hillslope defined by width function, and a hill length -! 3: Options for either power-law of numerically intergrated transmissivity -! 4: Option for turning off kinematic flow assumption - -! TODO: move constants to the proper clm_var* !----------------------------------------------------------------------- ! !DESCRIPTION: @@ -136,7 +129,6 @@ subroutine SurfaceRunoff (bounds, & type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points -! JP add integer , intent(in) :: num_hillslope ! number of hillslope columns integer , intent(in) :: filter_hillslopec(:) ! column filter for hillslope columns @@ -1870,9 +1862,6 @@ subroutine ThetaBasedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) :: sat_lev real(r8) :: s1,s2,m,b ! temporary variables used to interpolate theta integer :: sat_flag -! JP add - real(r8) :: tmph2omin -! JP end !----------------------------------------------------------------------- associate( & @@ -2288,9 +2277,8 @@ subroutine LateralFlowHillslope(bounds, & use abortutils , only : endrun use GridcellType , only : grc use landunit_varcon , only : istsoil, istcrop -! JP add use clm_time_manager , only : get_nstep -! JP end + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -2302,14 +2290,13 @@ subroutine LateralFlowHillslope(bounds, & type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(waterstate_type) , intent(inout) :: waterstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst -! JP add - integer , intent(in) :: num_hillslope ! number of hillslope soil cols - integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. - integer , intent(in) :: num_hilltop ! number of hillslope soil cols - integer , intent(in) :: filter_hilltopc(:) ! column filter for designating all hillslope cols. - integer , intent(in) :: num_hillbottom ! number of hillslope soil cols - integer , intent(in) :: filter_hillbottomc(:) ! column filter for designating all hillslope cols. -! JP end + integer , intent(in) :: num_hillslope ! number of hillslope soil cols + integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. + integer , intent(in) :: num_hilltop ! number of hillslope soil cols + integer , intent(in) :: filter_hilltopc(:) ! column filter for designating all hillslope cols. + integer , intent(in) :: num_hillbottom ! number of hillslope soil cols + integer , intent(in) :: filter_hillbottomc(:) ! column filter for designating all hillslope cols. + ! ! !LOCAL VARIABLES: character(len=32) :: subname = 'LateralFlowHillslope' ! subroutine name @@ -2377,9 +2364,6 @@ subroutine LateralFlowHillslope(bounds, & watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) eff_porosity => soilstate_inst%eff_porosity_col , & ! Input: [real(r8) (:,:) ] effective porosity = porosity - vol_ice hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) -! JP add - watfc => soilstate_inst%watfc_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at field capacity -! JP end qflx_latflow_out => waterflux_inst%qflx_latflow_out_col , & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) qflx_latflow_in => waterflux_inst%qflx_latflow_in_col , & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) qflx_net_latflow_in => waterflux_inst%qflx_net_latflow_col , & ! Output: [real(r8) (:) ] net lateral saturated (mm/s) @@ -2443,12 +2427,11 @@ subroutine LateralFlowHillslope(bounds, & qflx_rsub_sat(c) = 0._r8 rsub_top(c) = 0._r8 fracice_rsub(c) = 0._r8 -! JP add + qflx_latflow_in(c) = 0._r8 qflx_latflow_out(c) = 0._r8 qflx_net_latflow(c) = 0._r8 qflx_latflow_out_vol(c) = 0._r8 -! JP end end do diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index f534600e47..de48ee0ee1 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -706,12 +706,6 @@ subroutine InitCold(this, bounds, & this%h2osoi_vol_col(c,j) = 0.15_r8 endif end do -! JP add, tmp for init testing -! do j = 1,nlevsoi -! this%h2osoi_vol_col(c,j) = 0.35_r8 -! end do -! JP end - else if (lun%urbpoi(l)) then if (col%itype(c) == icol_road_perv) then nlevs = nlevgrnd diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 0fab5e8c46..de3f2897a9 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -62,7 +62,6 @@ module ColumnType real(r8), pointer :: z_lake (:,:) ! layer depth for lake (m) real(r8), pointer :: lakedepth (:) ! variable lake depth (m) integer , pointer :: nbedrock (:) ! variable depth to bedrock index -!scs ! hillslope hydrology variables integer, pointer :: colu (:) ! column index of uphill column (hillslope hydrology) integer, pointer :: cold (:) ! column index of downhill column (hillslope hydrology) @@ -73,7 +72,6 @@ module ColumnType real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column real(r8), pointer :: hill_distance (:) ! along-hill distance of column from bottom of hillslope -!scs ! levgrnd_class gives the class in which each layer falls. This is relevant for ! columns where there are 2 or more fundamentally different layer types. For ! example, this distinguishes between soil and bedrock layers. The particular value @@ -128,8 +126,6 @@ subroutine Init(this, begc, endc) allocate(this%lakedepth (begc:endc)) ; this%lakedepth (:) = spval allocate(this%dz_lake (begc:endc,nlevlak)) ; this%dz_lake (:,:) = nan allocate(this%z_lake (begc:endc,nlevlak)) ; this%z_lake (:,:) = nan - -!scs allocate(this%colu (begc:endc)) ; this%colu (:) = ispval allocate(this%cold (begc:endc)) ; this%cold (:) = ispval allocate(this%hillslope_ndx(begc:endc)) ; this%hillslope_ndx (:) = ispval @@ -138,7 +134,6 @@ subroutine Init(this, begc, endc) allocate(this%hill_area(begc:endc)) ; this%hill_area (:) = spval allocate(this%hill_width(begc:endc)) ; this%hill_width (:) = spval allocate(this%hill_distance(begc:endc)) ; this%hill_distance (:) = spval -!scs allocate(this%nbedrock (begc:endc)) ; this%nbedrock (:) = ispval allocate(this%levgrnd_class(begc:endc,nlevgrnd)) ; this%levgrnd_class(:,:) = ispval allocate(this%micro_sigma (begc:endc)) ; this%micro_sigma (:) = nan diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 0eb44ee017..21a0471e12 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -703,7 +703,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! LakeHydrology after the new snow filter is built call t_startf('hydro_without_drainage') -! JP changed inputs: + call HydrologyNoDrainage(bounds_clump, & filter(nc)%num_hillslope, filter(nc)%hillslopec, & filter(nc)%num_nolakec, filter(nc)%nolakec, & @@ -861,7 +861,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! ============================================================================ call t_startf('hydro2_drainage') -!scs + call HydrologyDrainage(bounds_clump, & filter(nc)%num_hilltop, filter(nc)%hilltopc, & filter(nc)%num_hillbottom, filter(nc)%hillbottomc, & diff --git a/src/main/clm_varcon.F90 b/src/main/clm_varcon.F90 index e051207ec1..8958d45157 100644 --- a/src/main/clm_varcon.F90 +++ b/src/main/clm_varcon.F90 @@ -122,7 +122,7 @@ module clm_varcon real(r8) :: thk_bedrock = 3.0_r8 ! thermal conductivity of 'typical' saturated granitic rock ! (Clauser and Huenges, 1995)(W/m/K) - real(r8) :: csol_bedrock = 2.0e6_r8 ! vol. heat capacity of granite/sandstone J/(m3 K)(Shabbir, 2000) !scs + real(r8) :: csol_bedrock = 2.0e6_r8 ! vol. heat capacity of granite/sandstone J/(m3 K)(Shabbir, 2000) real(r8), parameter :: zmin_bedrock = 0.4_r8 ! minimum soil depth [m] !!! C13 diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index f1775ad0e3..47969bdf94 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -123,18 +123,9 @@ module clm_varctl ! true => separate crop landunit is not created by default logical, public :: create_crop_landunit = .false. -! JP add ! number of hillslopes per landunit integer, public :: nhillslope = 0 - ! ! Postorder traversal of tree of hillslope columns. In future, will be read in. - ! ! (preorder,postorder) provides unique numbering pair of each hillslope column - ! ! with easy ways to keep track of parent/child hillslope columns. - ! ! Assume preorder is 1:nhillcols. - ! ! Default hillcol_postorder = nillcols:1:-1 creates linearly connected hillslope - ! integer, public :: hillcol_postorder = nillcols:1:-1 -! JP end - ! do not irrigate by default logical, public :: irrigate = .false. diff --git a/src/main/filterMod.F90 b/src/main/filterMod.F90 index a547410041..09dd1cdaf6 100644 --- a/src/main/filterMod.F90 +++ b/src/main/filterMod.F90 @@ -68,14 +68,12 @@ module filterMod integer, pointer :: hydrologyc(:) ! hydrology filter (columns) integer :: num_hydrologyc ! number of columns in hydrology filter -!scs integer, pointer :: hilltopc(:) ! uppermost column in hillslope integer :: num_hilltop ! number of hilltop columns integer, pointer :: hillbottomc(:) ! downhill filter in veg. landunits (columns) integer :: num_hillbottom ! number of columns downhill integer, pointer :: hillslopec(:) ! hillslope hydrology filter (columns) integer :: num_hillslope ! number of hillslope hydrology (columns) -!scs integer, pointer :: urbanl(:) ! urban filter (landunits) integer :: num_urbanl ! number of landunits in urban filter integer, pointer :: nourbanl(:) ! non-urban filter (landunits) @@ -221,11 +219,9 @@ subroutine allocFiltersOneGroup(this_filter) allocate(this_filter(nc)%natvegp(bounds%endp-bounds%begp+1)) allocate(this_filter(nc)%hydrologyc(bounds%endc-bounds%begc+1)) -!scs allocate(this_filter(nc)%hilltopc(bounds%endc-bounds%begc+1)) allocate(this_filter(nc)%hillbottomc(bounds%endc-bounds%begc+1)) allocate(this_filter(nc)%hillslopec(bounds%endc-bounds%begc+1)) -!scs allocate(this_filter(nc)%urbanp(bounds%endp-bounds%begp+1)) allocate(this_filter(nc)%nourbanp(bounds%endp-bounds%begp+1)) @@ -420,8 +416,8 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio end do this_filter(nc)%num_hydrologyc = f -!scs: currently only natveg (see subgridMod); should be possible -! for a subset of istsoil/istcrop landunits, e.g. when nhillcol = 0 + ! Currently only natveg (see subgridMod); should be possible + ! for a subset of istsoil/istcrop landunits, e.g. when nhillcol = 0 ! Create hillslope hydrology filters at column-level @@ -460,8 +456,6 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio end if end do this_filter(nc)%num_hillbottom = fs -!scs - ! Create prognostic crop and soil w/o prog. crop filters at patch-level ! according to where the crop model should be used diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 03333efd60..c24652d7d8 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2325,15 +2325,9 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='levdcmp', xtype=tape(t)%ncprec, dim1name='levdcmp', & long_name='coordinate soil levels', units='m', ncid=nfid(t)) -!scs if (ldomain%isgrid2d) then !pass else -!!$ call ncd_defvar(varname='hslp_distance' , xtype=ncd_double, & -!!$ dim1name=namec, & -!!$ long_name='hillslope column distance', ncid=nfid(t), & -!!$ imissing_value=spval, ifill_value=spval) - call ncd_defvar(varname='hslp_distance', xtype=ncd_double, & dim1name=namec, long_name='hillslope column distance', & units='m', ncid=nfid(t)) @@ -2356,7 +2350,6 @@ subroutine htape_timeconst(t, mode) dim1name=namec, long_name='hillslope downhill column index', & ncid=nfid(t)) end if -!scs if(use_ed)then call ncd_defvar(varname='levscls', xtype=tape(t)%ncprec, dim1name='levscls', & @@ -2377,7 +2370,7 @@ subroutine htape_timeconst(t, mode) zsoi_1d(1) = 1._r8 call ncd_io(varname='levdcmp', data=zsoi_1d, ncid=nfid(t), flag='write') end if -!scs + if (.not.ldomain%isgrid2d) then call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') @@ -2751,9 +2744,6 @@ subroutine hfields_write(t, mode) ! Write history output. Always output land and ocean runoff on xy grid. if (num2d == 1) then -! JP add, for debugging -! write(iulog,*) "JP: varname: ", varname -! JP end call ncd_io(flag='write', varname=varname, & dim1name=type1d_out, data=hist1do, ncid=nfid(t), nt=nt) else @@ -2914,10 +2904,10 @@ subroutine hfields_1dinfo(t, mode) !call ncd_defvar(varname='pfts1d_li', xtype=ncd_int, dim1name='pft', & ! long_name='1d landunit index of corresponding pft', ncid=ncid) -!scs: commenting-in for hillslope hydrology (multi-column) code +! commenting-in for hillslope hydrology (multi-column) code call ncd_defvar(varname='pfts1d_ci', xtype=ncd_int, dim1name='pft', & long_name='1d column index of corresponding pft', ncid=ncid) -!scs +! ! ---------------------------------------------------------------- call ncd_defvar(varname='pfts1d_wtgcell', xtype=ncd_double, dim1name=namep, & @@ -3057,9 +3047,9 @@ subroutine hfields_1dinfo(t, mode) ! --- EBK Do NOT write out indices that are incorrect 4/1/2011 --- Bug 1310 !call ncd_io(varname='pfts1d_gi' , data=patch%gridcell, dim1name=namep, ncid=ncid, flag='write') !call ncd_io(varname='pfts1d_li' , data=patch%landunit, dim1name=namep, ncid=ncid, flag='write') -!scs: commenting-in for hillslope hydrology +! commenting-in for hillslope hydrology call ncd_io(varname='pfts1d_ci' , data=patch%column , dim1name=namep, ncid=ncid, flag='write') -!scs +! ! ---------------------------------------------------------------- call ncd_io(varname='pfts1d_wtgcell' , data=patch%wtgcell , dim1name=namep, ncid=ncid, flag='write') call ncd_io(varname='pfts1d_wtlunit' , data=patch%wtlunit , dim1name=namep, ncid=ncid, flag='write') diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index ac7c325cdc..7184d1f16b 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -273,17 +273,14 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) integer , intent(inout) :: pi ! patch index ! ! !LOCAL VARIABLES: - integer :: m ! index + integer :: m,ci2 ! index integer :: ncohorts integer :: npatches ! number of patches in landunit -! JP add - integer :: ci2 ! tmp 2nd col. index -! JP end integer :: ncols integer :: nlunits integer :: pitype ! patch itype real(r8) :: wtlunit2gcell ! landunit weight in gridcell - real(r8) :: wtcol2lunit ! column weight in landunit + real(r8) :: wtcol2lunit ! column weight in landunit !------------------------------------------------------------------------ ! Set decomposition properties @@ -295,13 +292,6 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) if (npatches > 0) then call add_landunit(li=li, gi=gi, ltype=ltype, wtgcell=wtlunit2gcell) - ! ! Assume one column on the landunit - ! call add_column(ci=ci, li=li, ctype=1, wtlunit=1.0_r8) - - ! do m = natpft_lb,natpft_ub - ! call add_patch(pi=pi, ci=ci, ptype=m, wtcol=wt_nat_patch(gi,m)) - ! end do -!scs wtcol2lunit = 1.0_r8/real(ncols,r8) do ci2 = 1,ncols call add_column(ci=ci, li=li, ctype=1, wtlunit=wtcol2lunit) @@ -309,7 +299,7 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) call add_patch(pi=pi, ci=ci, ptype=m, wtcol=wt_nat_patch(gi,m)) end do end do -!scs + end if end subroutine set_landunit_veg_compete diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index e172dd801b..c6f064b304 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -148,7 +148,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof integer :: begc, endc integer :: begl, endl integer :: jmin_bedrock -!scs integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope real(r8), allocatable :: hill_alpha(:,:) ! hillslope 'alpha' parameter real(r8), allocatable :: hill_beta(:,:) ! hillslope 'beta' parameter @@ -247,7 +246,7 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof zisoi(nlevgrnd) = zsoi(nlevgrnd) + 0.5_r8*dzsoi(nlevgrnd) else if ( soil_layerstruct == '49SL_10m' ) then - !scs: 10 meter soil column, nlevsoi set to 49 in clm_varpar + ! 10 meter soil column, nlevsoi set to 49 in clm_varpar do j = 1,10 dzsoi(j)= 1.e-2_r8 !10mm layers enddo @@ -292,7 +291,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof do j = 1, nlevgrnd zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) enddo -! JP add else if ( soil_layerstruct == '20SL_1.5m' ) then do j=1,nlevsoi dzsoi(j) = 1.5_r8/nlevsoi @@ -311,8 +309,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof do j = 1, nlevgrnd zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) enddo -! JP end -! JP add else if ( soil_layerstruct == '10SL_1.5m' ) then do j=1,nlevsoi dzsoi(j) = 1.5_r8/nlevsoi @@ -331,8 +327,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof do j = 1, nlevgrnd zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) enddo -! JP end -! JP add else if ( soil_layerstruct == '10SL_0.6m' ) then do j=1,nlevsoi dzsoi(j) = 0.6_r8/nlevsoi @@ -351,7 +345,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof do j = 1, nlevgrnd zsoi(j) = 0.5*(zisoi(j-1) + zisoi(j)) enddo -! JP end end if ! define a vertical grid spacing such that it is the normal dzsoi if @@ -970,9 +963,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof g = col%gridcell(c) ! check for near zero slopes, set minimum value col%topo_slope(c) = max(tslope(g), 0.2_r8) -! JP add for testing -! write(iulog,*) 'JP:slope(c): ',col%topo_slope(c) -! JP end end do deallocate(tslope) From 2d070013e0b46d87a6f03287e8be681f06ae4321 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 7 Mar 2017 23:00:16 +0000 Subject: [PATCH 004/153] hillslope_hydrology_n04_clm4_5_14_r226 merged to r226 --- SVN_EXTERNAL_DIRECTORIES.standalone | 8 +- bld/CLMBuildNamelist.pm | 38 +- .../namelist_defaults_clm4_5.xml | 25 +- .../namelist_definition_clm4_5.xml | 42 ++ cime_config/config_compsets.xml | 184 +++---- cime_config/testdefs/testlist_clm.xml | 168 ------ .../clm50cropIrrigMonth_interp/user_nl_clm | 2 +- .../clm/irrig_spunup/user_nl_clm | 2 +- doc/ChangeLog | 511 ++++++++++++++++++ doc/ChangeSum | 3 + src/biogeochem/CNPhenologyMod.F90 | 12 +- src/biogeochem/CNVegetationFacade.F90 | 2 + src/biogeochem/CropType.F90 | 72 ++- src/biogeophys/BalanceCheckMod.F90 | 5 +- src/biogeophys/CanopyHydrologyMod.F90 | 6 +- src/biogeophys/EnergyFluxType.F90 | 5 + src/biogeophys/HillslopeHydrologyMod.F90 | 40 +- src/biogeophys/SnowHydrologyMod.F90 | 16 +- src/biogeophys/SoilHydrologyMod.F90 | 4 +- src/biogeophys/WaterStateType.F90 | 10 +- src/main/atm2lndMod.F90 | 45 +- src/main/atm2lndType.F90 | 70 ++- src/main/clm_driver.F90 | 5 - src/main/clm_initializeMod.F90 | 2 +- src/main/clm_instMod.F90 | 2 +- src/main/clm_varcon.F90 | 4 +- src/main/controlMod.F90 | 29 +- src/main/initHillslopeMod.F90 | 8 - src/main/initVerticalMod.F90 | 54 +- .../atm2lnd_test/test_downscale_forcings.pf | 148 +++-- .../atm2lnd_test/test_partition_precip.pf | 1 + .../unittestSimpleSubgridSetupsMod.F90 | 31 ++ test/tools/TSMscript_tools.sh | 2 +- tools/SVN_EXTERNAL_DIRECTORIES | 2 +- 34 files changed, 1112 insertions(+), 446 deletions(-) diff --git a/SVN_EXTERNAL_DIRECTORIES.standalone b/SVN_EXTERNAL_DIRECTORIES.standalone index f955b1123c..5b15c80852 100644 --- a/SVN_EXTERNAL_DIRECTORIES.standalone +++ b/SVN_EXTERNAL_DIRECTORIES.standalone @@ -1,5 +1,5 @@ -cime https://github.com/CESM-Development/cime/tags/cime5.2.0-alpha.9 -components/clm/tools/gen_domain https://github.com/CESM-Development/cime/tags/cime5.2.0-alpha.9/tools/mapping/gen_domain_files -components/cism https://svn-ccsm-models.cgd.ucar.edu/glc/trunk_tags/cism2_1_24 +cime https://github.com/CESM-Development/cime/tags/cime5.2.0-alpha.25 +components/clm/tools/gen_domain https://github.com/CESM-Development/cime/tags/cime5.2.0-alpha.25/tools/mapping/gen_domain_files +components/cism https://svn-ccsm-models.cgd.ucar.edu/glc/trunk_tags/cism2_1_29 components/rtm https://svn-ccsm-models.cgd.ucar.edu/rivrtm/trunk_tags/rtm1_0_59 -components/mosart https://svn-ccsm-models.cgd.ucar.edu/mosart/trunk_tags/mosart1_0_19 +components/mosart https://svn-ccsm-models.cgd.ucar.edu/mosart/trunk_tags/mosart1_0_20 diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 91bfc6c9aa..e4757b0602 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1565,6 +1565,7 @@ sub process_namelist_inline_logic { setup_logic_glacier($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref, $physv); setup_logic_dynamic_plant_nitrogen_alloc($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_luna($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_hillslope($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_hydrstress($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_dynamic_roots($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_params_file($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); @@ -2929,6 +2930,19 @@ sub setup_logic_luna { #------------------------------------------------------------------------------- +sub setup_logic_hillslope { + # + # Hillslope hydrology model + # + my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + + if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); + } +} + +#------------------------------------------------------------------------------- + sub setup_logic_hydrstress { # # Plant hydraulic stress model @@ -3500,6 +3514,8 @@ sub setup_logic_snowpack { if ($physv->as_long() >= $physv->as_long("clm4_5")) { add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nlevsno'); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'h2osno_max'); + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'int_snow_max'); + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'n_melt_glcmec'); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'wind_dependent_snow_density'); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_overburden_compaction_method'); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lotmp_snowdensity_method'); @@ -3529,11 +3545,25 @@ sub setup_logic_atm_forcing { if ($physv->as_long() >= $physv->as_long("clm4_5")) { add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glcmec_downscale_longwave'); add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'repartition_rain_snow'); + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lapse_rate'); + + my $var; + + foreach $var ("lapse_rate_longwave", + "longwave_downscaling_limit") { + if ( $nl->get_value("glcmec_downscale_longwave") =~ /$TRUE/i ) { + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); + } else { + if (defined($nl->get_value($var))) { + fatal_error("$var can only be set if glcmec_downscale_longwave is true"); + } + } + } - foreach my $var ("precip_repartition_glc_all_snow_t", - "precip_repartition_glc_all_rain_t", - "precip_repartition_nonglc_all_snow_t", - "precip_repartition_nonglc_all_rain_t") { + foreach $var ("precip_repartition_glc_all_snow_t", + "precip_repartition_glc_all_rain_t", + "precip_repartition_nonglc_all_snow_t", + "precip_repartition_nonglc_all_rain_t") { if ( $nl->get_value("repartition_rain_snow") =~ /$TRUE/i ) { add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); } else { diff --git a/bld/namelist_files/namelist_defaults_clm4_5.xml b/bld/namelist_files/namelist_defaults_clm4_5.xml index af250babd1..5cdb89dd11 100644 --- a/bld/namelist_files/namelist_defaults_clm4_5.xml +++ b/bld/namelist_files/namelist_defaults_clm4_5.xml @@ -139,6 +139,14 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .true. + +0.006 + + +0.032 + +0.5 + 0. 2. @@ -229,6 +237,14 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 5 10000.0 1000.0 + +2000. + +1.e30 + +1.0 +10.0 + .true. .false. @@ -350,13 +366,18 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 1.d-9 + + +.false. +.false. + .false. .false. .true. - diff --git a/bld/namelist_files/namelist_definition_clm4_5.xml b/bld/namelist_files/namelist_definition_clm4_5.xml index a5a1300191..d93710b488 100644 --- a/bld/namelist_files/namelist_definition_clm4_5.xml +++ b/bld/namelist_files/namelist_definition_clm4_5.xml @@ -551,6 +551,11 @@ LUNA operates on C3 and non-crop vegetation (see vcmax_opt for how other veg is LUNA: Leaf Utilization of Nitrogen for Assimilation + +Toggle to turn on the hillslope hydrology model + + Toggle to turn on the plant hydraulic stress model @@ -1263,6 +1268,28 @@ This downscaling is conservative. Default: .true. + +Surface temperature lapse rate (K m-1) +A positive value means a decrease in temperature with increasing height + + + +Longwave radiation lapse rate (W m-2 m-1) +A positive value means a decrease in LW radiation with increasing height +Only relevant if glcmec_downscale_longwave is .true. + + + +Relative limit for how much longwave downscaling can be done (unitless) +The pre-normalized, downscaled longwave is restricted to be in the range +[lwrad*(1-longwave_downscaling_limit), lwrad*(1+longwave_downscaling_limit)] +This parameter must be in the range [0,1] +Only relevant if glcmec_downscale_longwave is .true. + + Temperature below which all precipitation falls as snow, for glacier columns (deg C) @@ -2042,6 +2069,21 @@ Changes in this value should possibly be accompanied by changes in: glc_snow_persistence_max_days > 0. + +Limit applied to integrated snowfall when determining changes in snow-covered fraction during melt +(mm H2O) + + + +SCA shape parameter for glc_mec (glacier multiple elevation class) columns +For most columns, n_melt is based on the standard deviation of 1km topography in the grid cell; +but glc_mec columns already account for subgrid topographic variability through their use of +multiple elevation classes; thus, to avoid double-accounting for topographic variability +in these columns, we use a fixed value of n_melt. + + If TRUE, the density of new snow depends on wind speed, and there is also diff --git a/cime_config/config_compsets.xml b/cime_config/config_compsets.xml index 02ef728b82..c7acf00de6 100644 --- a/cime_config/config_compsets.xml +++ b/cime_config/config_compsets.xml @@ -457,113 +457,113 @@ - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid + hybrid - I1850CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I1850CN_f19_g16_c100503 - I1850CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I1850CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I1850CN_f09_g16_c100503 - I1850CN_f09_g16_c100503 - I1850CLM40CRUCN_f09_g16_clm4500_c130514 - I1850CLM40CRUCN_f09_g16_clm4500_c130514 - I2000CN_f09_g16_c100503 - I1850CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 + I1850CN_f19_g16_c100503 + I2000CN_f19_g16_c100503 + I2000CN_f19_g16_c100503 + I1850CN_f19_g16_c100503 + I1850CN_f19_g16_c100503 + I2000CN_f19_g16_c100503 + I1850CN_f19_g16_c100503 + I2000CN_f19_g16_c100503 + I2000CN_f19_g16_c100503 + I2000CN_f19_g16_c100503 + I2000CN_f19_g16_c100503 + I2000CN_f09_g16_c100503 + I2000CN_f09_g16_c100503 + I1850CN_f09_g16_c100503 + I1850CN_f09_g16_c100503 + I1850CLM40CRUCN_f09_g16_clm4500_c130514 + I1850CLM40CRUCN_f09_g16_clm4500_c130514 + I2000CN_f09_g16_c100503 + I1850CN_f09_g16_c100503 + I2000CN_f09_g16_c100503 + I2000CN_f09_g16_c100503 + I2000CN_f09_g16_c100503 + I2000CN_f09_g16_c100503 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 1122-01-01 - 1122-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 1122-01-01 + 1122-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 + 0001-01-01 - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init + ccsm4_init diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 0a9568a7b9..57c8b1ce29 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -2,9 +2,6 @@ - - yellowstone - null @@ -14,27 +11,17 @@ hobart - - - yellowstone - - - edison yellowstone - edison yellowstone yellowstone - edison - edison - edison hobart hobart janus @@ -79,9 +66,6 @@ yellowstone - - edison - @@ -130,9 +114,6 @@ yellowstone yellowstone - - edison - null @@ -157,12 +138,8 @@ yellowstone - yellowstone yellowstone - - edison - yellowstone @@ -172,14 +149,12 @@ - edison yellowstone yellowstone - edison hobart yellowstone yellowstone @@ -194,8 +169,6 @@ - edison - edison yellowstone yellowstone @@ -224,15 +197,11 @@ - edison yellowstone yellowstone - - edison - @@ -249,7 +218,6 @@ - edison yellowstone @@ -318,9 +286,6 @@ hobart - - edison - yellowstone @@ -331,9 +296,6 @@ - - edison - yellowstone @@ -344,7 +306,6 @@ - edison yellowstone yellowstone @@ -385,9 +346,6 @@ - - edison - null @@ -426,14 +384,8 @@ yellowstone - - - yellowstone - - - edison yellowstone @@ -465,25 +417,13 @@ - - - yellowstone - - - - - yellowstone - - ed - edison yellowstone yellowstone - edison yellowstone yellowstone @@ -493,7 +433,6 @@ - edison yellowstone yellowstone yellowstone @@ -502,7 +441,6 @@ hobart - edison yellowstone yellowstone @@ -515,7 +453,6 @@ yellowstone - edison hobart yellowstone yellowstone @@ -523,12 +460,6 @@ hobart - - yellowstone - - - yellowstone - hobart @@ -552,17 +483,12 @@ yellowstone yellowstone - - yellowstone - - edison yellowstone - edison yellowstone @@ -575,8 +501,6 @@ - edison - edison yellowstone @@ -585,9 +509,6 @@ yellowstone - - yellowstone - @@ -621,9 +542,6 @@ yellowstone yellowstone - - edison - yellowstone @@ -644,9 +562,6 @@ yellowstone - - edison - @@ -662,28 +577,18 @@ yellowstone - - edison - yellowstone - - edison - - yellowstone yellowstone - - yellowstone - @@ -770,27 +675,22 @@ - edison yellowstone - edison yellowstone - edison yellowstone - edison yellowstone - edison yellowstone @@ -803,23 +703,12 @@ - - - yellowstone - - hobart - - edison - - - edison - yellowstone @@ -831,7 +720,6 @@ hobart - edison janus yellowstone yellowstone @@ -850,25 +738,18 @@ - - edison - yellowstone - edison yellowstone - - edison - yellowstone @@ -889,7 +770,6 @@ - edison yellowstone yellowstone @@ -913,12 +793,8 @@ - edison yellowstone - - yellowstone - null @@ -927,8 +803,6 @@ - edison - edison yellowstone @@ -936,7 +810,6 @@ - edison yellowstone yellowstone @@ -944,7 +817,6 @@ hobart - edison yellowstone yellowstone yellowstone @@ -991,12 +863,6 @@ - - edison - - - edison - yellowstone yellowstone @@ -1042,9 +908,6 @@ - - edison - null @@ -1064,18 +927,12 @@ - - edison - yellowstone yellowstone - - edison - @@ -1088,7 +945,6 @@ - edison yellowstone @@ -1222,9 +1078,6 @@ - - edison - yellowstone @@ -1294,11 +1147,6 @@ hobart - - - edison - - @@ -1365,7 +1213,6 @@ - edison yellowstone yellowstone @@ -1386,11 +1233,6 @@ - - - edison - - null @@ -1451,7 +1293,6 @@ - edison yellowstone yellowstone @@ -1475,7 +1316,6 @@ - edison yellowstone @@ -1532,7 +1372,6 @@ - edison yellowstone @@ -1557,7 +1396,6 @@ - edison yellowstone @@ -1596,12 +1434,6 @@ hobart hopper - - eastwind - evergreen - olympus - yellowstone - diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm index 99147469e7..adb7e61f9d 100644 --- a/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm @@ -1,5 +1,5 @@ use_init_interp = .true. -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IGM1850GSWP3CLM50BGCCROPIRR.0031-01-01.1.9x2.5_g1v6_gl5_simyr1850_c160908.nc' +finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IGM1850GSWP3CLM50BGCCROPIRR.0031-01-01.1.9x2.5_g1v6_gl5_simyr1850_c170219.nc' init_interp_fill_missing_with_natveg = .true. ! need this as IC file is glc_mec use_hydrstress = .false. diff --git a/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm index 79b12dfb03..4fb55295df 100644 --- a/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm @@ -1,5 +1,5 @@ use_init_interp = .true. -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IGM1850GSWP3CLM50BGCCROPIRR.0031-01-01.1.9x2.5_g1v6_gl5_simyr1850_c160908.nc' +finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IGM1850GSWP3CLM50BGCCROPIRR.0031-01-01.1.9x2.5_g1v6_gl5_simyr1850_c170219.nc' init_interp_fill_missing_with_natveg = .true. ! need this as IC file is glc_mec hist_fincl1 += 'QIRRIG_DEMAND' diff --git a/doc/ChangeLog b/doc/ChangeLog index 0258027f69..1398de472e 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,515 @@ =============================================================== +Tag name: clm4_5_14_r226 +Originator(s): erik (Erik Kluzek) +Date: Thu Mar 2 15:12:50 MST 2017 +One-line Summary: Update cime, mosart and cism to a version that is cesm2_0_beta05 or part of beta06 + +Purpose of changes +------------------ + +Update cime version and cism to version that similar to that in cesm2_0_beta05, but with many fixes in cime for +clm. Also update mosart to fix a bug on hobart. The update of cism does change answers as it makes CISM2 the +default with the new 4km greenland grid. + +There are some user improvements in the latest cime version. Long term archiving issues are fixed. A file +called CASEROOT is added to your case's $RUNDIR so that you can easily see where your source code is. A few +options were added to create_newcase and create_clone (see details below). + +NOTE: You will need to use the "--run-unsupported" to create_newcase for compsets/grids that aren't tested or supported!!! + +Fix a few other existing bugs. Fix createcrop_landunit to work with the new CLM surface datasets. Bring in a +workaround for a compiler bug with intel 17 and 18. Bring in a version of PTCLM that works with the latest cime. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2417 -- fix createcrop_landunit for new datasets with 16 PFTs + 2418 -- fix grid match for config_compsets.xml (cime issue 1079 still there) + 2424 -- Update mosart to 1_0_20 to fix the nag bug + 2479 -- workaround for intel compiler bug + 2357 -- PTCLM broken in cime5 + +CIME Issues fixed (include issue #): archiving, unit-tests, grid issues, gnu compiler, + cime issues fixed: 1075, 1053, 1051, 1073, 1072, 1089 + +Known bugs introduced in this tag (include bugzilla ID): + 1074 -- hcru_hcru grid no longer works gives PIO error + 1079 -- mask for grid matching + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + Add support for cheyenne + CASEROOT file added to $RUNDIR to show path to source + Add "--run-unsupported" option to create_newcase + Add "--cime-output-root" option to create_clone + Fix long term achiving issues + +Changes made to namelist defaults (e.g., changed parameter values): drv namelist changes + PIO namelists have different defaults + some grids are null and maps are idmap when they aren't needed + clm40 removed from all active compsets + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: Seems to run faster (~20%)! (we don't understand why) + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + Refactoring in cime for unit-testing, add schema files for cime xml files + buildnml faster + config_grids and xmlquery was refactored + +Changes to tests or testing: Add test with mosart on hobart + +Code reviewed by: self, sacks + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + tools-tests (components/clm/test/tools): + + yellowstone - PASS + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - OK + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu (clm45 only) - OK + hobart_nag - OK + +CLM tag used for the baseline comparisons: clm4_5_14_r225 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes. Compsets with CISM + + Summarize any changes to answers, i.e., + - what code configurations: All with CISM + - what platforms/compilers: All + - nature of change (roundoff; larger than roundoff/same climate; new climate): + compsets are updated to default to CISM2 and the new 4km greenland grid + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): cime, cism, mosart, PTCLM + + cime to cime5.2.0-alpha25 + mosart to mosart1_0_20 + cism to cism2_1_29 + PTCLM to PTCLM2_170302 + +List all files eliminated: + + D components/clm/tools/shared + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/cime_config/config_compsets.xml - Workaround in 2418 for cime issue 1079 + M components/clm/test/tools/TSMscript_tools.sh --- Fix arguments sent to TCB scrip + +=============================================================== +=============================================================== +Tag name: clm4_5_14_r225 +Originator(s): sacks (Bill Sacks) +Date: Sun Feb 19 14:42:13 MST 2017 +One-line Summary: Fix GDD accumulation in new crop columns + +Purpose of changes +------------------ + +For newly-initiating crop columns in the middle of a run, the 20-year-average +GDD variables (gdd*20) were not being initialized correctly. They were starting +as spval, and then taking essentially forever to come down to some reasonable +value. This caused major problems for both dynamic landunits and when running +init_interp from one crop run to another, where the new run had some new crop +types - such as going from a run without irrigation to a run with irrigation. + +This tag fixes these problems. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): +- If you do a CROP run, setting use_init_interp to .true., and pointing to a + previous initial conditions file generated with a crop run (thus having + restyear > 0 on the restart file), then GDD accumulation will get reset. This + means that the first year of your run won't have any crop growth. After this + initial "burn-in" period, it will run fine. This is only an issue when using + initial conditions generated prior to this tag, and is only an issue when + using init_interp. + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: New initial conditions file for tests that use +clm50cropIrrigMonth_interp or irrig_spunup testmods - see details below. + +Code reviewed by: self + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + hobart_nag - ok + + ok means tests pass, some expected baseline failures: + + Baseline comparisons fail because GDD accumulation is now fixed for + transient crops: + ERS_Ly3_Mmpi-serial.1x1_smallvilleIA.IHISTCLM50BGCCROP.yellowstone_gnu.clm-cropMonthOutput + ERS_Ly6_Mmpi-serial.1x1_smallvilleIA.IHISTCLM50BGCCROP.yellowstone_gnu.clm-cropMonthOutput + SMS_D_Ly6_Mmpi-serial.1x1_smallvilleIA.IHISTCLM45BGCCROP.yellowstone_pgi.clm-cropMonthOutput + + These tests point to a previously-spun-up crop file, and use init_interp. I + have adjusted this file to add the new patch-level nyrs_crop_active + variable, which I set to 30 for all active crop PFTs (in agreement with the + old restyear). However, this initial conditions file does not have any + non-irrigated crop PFTs! So crop behavior was wrong in the baseline run, + because non-irrigated crops started with spval gdd*20 values. + SMS_D_P24x1_Ld5.f10_f10.ICRUCLM50BGCCROP.hobart_nag.clm-irrig_spunup + ERP_D_P15x2_Ld5.f10_f10.ICRUCLM50BGCCROP.yellowstone_intel.clm-irrig_spunup + ERP_P60x2_Lm36.f10_f10.ICRUCLM50BGCCROP.yellowstone_intel.clm-clm50cropIrrigMonth_interp + +CLM tag used for the baseline comparisons: clm4_5_14_r224 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: + - Transient crop cases + - Any crop case for which initial conditions are init_interp'ed from a + previous crop case: nyrs_crop_active is reset to 0 in this case + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + Potentially new climate for transient crop cases + + If bitwise differences were observed, how did you show they were no worse + than roundoff? n/a + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: n/a + + URL for LMWG diagnostics output used to validate new climate: n/a + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Main changes, as noted above +M components/clm/src/main/clm_driver.F90 +M components/clm/src/biogeochem/CNPhenologyMod.F90 +M components/clm/src/biogeochem/CNVegetationFacade.F90 +M components/clm/src/biogeochem/CropType.F90 + +========= Point to new version of initial conditions file - same as old, but + hacked to have nyrs_crop_active patch-level variable: set to 30 for + active crop PFTs, 0 elsewhere. This hack is needed since we run + init_interp for these tests: this allows crops to grow initially. +M components/clm/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm +M components/clm/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm + +=============================================================== +=============================================================== +Tag name: clm4_5_14_r224 +Originator(s): sacks (Bill Sacks) +Date: Fri Feb 10 06:27:53 MST 2017 +One-line Summary: Tweaks for glaciers and snow + +Purpose of changes +------------------ + +A number of answer-changing tweaks for glaciers and snow, mainly with the intent +of improving glacial melt over Greenland in CESM2. + +(1) New longwave downscaling parameterization, based on Van Tricht et al. (2016, + TC) Figure 6, doi:10.5194/tc-10-2379-2016. This uses a simple linear lapse + rate for LW radiation, which seems better supported by observations than the + old approach based on blackbody radiation relationships. Two new namelist + parameters control this behavior: lapse_rate_longwave and + longwave_downscaling_limit. This changes answers for all cases with multiple + elevation classes - i.e., all cases with CISM (IG, etc.), just over the + regions with downscaling (Greenland and Antarctica). This change is from Leo + van Kampenhout. + +(2) Modified the parameterization of snow cover fraction during melt to improve + glacial melt over Greenland in CESM2: + + (a) New value for n_melt (parameter controlling snow cover fraction as snow + melts) over glc_mec columns for CLM5. The previous value of 10 resulted + in near-100% snow cover fraction over glaciers. The new value of 1 + allows snow cover fractions more similar to other landcover + types. n_melt_glcmec is a new namelist parameter. This changes answers + for all CLM5 cases with glc_mec (i.e., with CISM), just over glc_mec + landunits. + + (b) For all landcover types, maintain snow cover fraction at 100% when + h2osno exceeds 2m SWE in CLM5. This is important in conjunction with + (a), in order to avoid snow cover fraction dropping significantly below + 100% when very deep (e.g., 10m) snow packs begin to melt. This is + controlled by a new namelist parameter, int_snow_max, which can be set + to a very large value to retrieve the old behavior. This changes answers + for all CLM5 cases; in principle, it changes answersfor all landunits, + but in practice, this should only matter where we have a very deep snow + pack - typically, just in regions where the snow persists for more than + a year. + + These two changes were proposed in a discussion with Leo van Kampenhout, + Bill Lipscomb, Dave Lawrence and Sean Swenson. + +(3) Set the ddz3 term controlling snow compaction for glaciers and wetlands in + the same way as for soil and crop landunits. This should have been included + in clm4_5_14_r222 (which brought in consistency in the treatment of snow + cover fraction in glacier & wetland landunits), but was overlooked in that + tag. This changes answers for all cases, just over glacier, glacier_mec and + wetland columns. This change was reviewed by Sean Swenson and Leo van + Kampenhout. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- New namelist variables: + - lapse_rate: the temperature lapse rate for downscaling over ice sheets + (default kept the same as before, though there may be roundoff-level + differences due to the precision of the namelist parameter) + - lapse_rate_longwave: the longwave radiation lapse rate for downscaling over + ice sheets + - longwave_downscaling_limit: the relative limit capping longwave radiation + downscaling + - n_melt_glcmec: the value of n_melt (parameter controlling snow cover fraction + as snow melts) over glc_mec columns + - int_snow_max: limit applied to integrated snowfall when determining changes in + snow-covered fraction during melt +- INT_SNOW diagnostic now inactive by default + +Changes made to namelist defaults (e.g., changed parameter values): Some of the +new namelist variables have defaults different from the previous hard-coded +values, but no changes to existing namelist defaults. + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: Removed a bunch of no-longer-used test lists: +aux_clm_ys_intel, aux_clm_ys_pgi, aux_science, aux_scripts, aux_testsystem, +csltiming, aux_rasm + +Code reviewed by: self + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - ok + + tests pass, differences as expected + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + hobart_nag - ok + + ok means tests pass, but differences from baselines and namelist differences + as expected + +CLM tag used for the baseline comparisons: clm4_5_14_r223 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: ALL + - what platforms/compilers: ALL + - nature of change (roundoff; larger than roundoff/same climate; new climate): + Larger than roundoff. Expect at least small regional climate differences - + specifically over Greenland and Antarctica. + + Answer changes are from: + + (1) New longwave downscaling parameterization. This changes answers for all + cases with multiple elevation classes - i.e., all cases with CISM (IG, + etc.), just over the regions with downscaling (Greenland and + Antarctica). + + (2) New value for n_melt over glc_mec columns for CLM5. This changes answers + for all CLM5 cases with glc_mec (i.e., with CISM), just over glc_mec + landunits. + + (3) Modified parameterization of snow cover fraction during melt to maintain + snow cover fraction at 100% when h2osno exceeds 2m SWE in CLM5. This + changes answers for all CLM5 cases; in principle, it changes answersfor + all landunits, but in practice, this should only matter where we have a + very deep snow pack - typically, just in regions where the snow persists + for more than a year. + + (4) Set the ddz3 term controlling snow compaction for glaciers and wetlands + in the same way as for soil and crop landunits. This changes answers for + all cases, just over glacier, glacier_mec and wetland columns. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= New longwave radiation downscaling; make lapse rate a namelist + parameter; refactor unit tests a bit +M components/clm/src/main/atm2lndMod.F90 +M components/clm/src/main/atm2lndType.F90 +M components/clm/src/main/test/atm2lnd_test/test_downscale_forcings.pf +M components/clm/src/main/test/atm2lnd_test/test_partition_precip.pf + +========= Apply int_snow_max; treat ddz3 consistently for glaciers and wetlands +M components/clm/src/biogeophys/SnowHydrologyMod.F90 +M components/clm/src/biogeophys/CanopyHydrologyMod.F90 + +========= New int_snow_max and n_melt_glcmec namelist variables +M components/clm/src/main/controlMod.F90 +M components/clm/src/main/clm_varcon.F90 +M components/clm/src/main/initVerticalMod.F90 + +========= Add some inactive history fields that just apply over glaciers +M components/clm/src/biogeophys/EnergyFluxType.F90 +M components/clm/src/biogeophys/WaterStateType.F90 + +========= New setup_landunit_ncols utility method +M components/clm/src/unit_test_shr/unittestSimpleSubgridSetupsMod.F90 + +========= New namelist parameters, as documented above +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml +M components/clm/bld/CLMBuildNamelist.pm + +========= Remove unneeded use statements +M components/clm/src/main/clm_driver.F90 +M components/clm/src/main/clm_instMod.F90 + +========= Remove no-longer-used testlists: aux_clm_ys_intel, aux_clm_ys_pgi, + aux_science, aux_scripts, aux_testsystem, csltiming, aux_rasm. Main + motivation is that lists starting with 'aux_*' now have special + meaning, indicating what compset/grid combinations we test regularly. +M components/clm/cime_config/testdefs/testlist_clm.xml + +=============================================================== +=============================================================== Tag name: clm4_5_14_r223 Originator(s): sacks (Bill Sacks) Date: Fri Feb 3 10:07:24 MST 2017 diff --git a/doc/ChangeSum b/doc/ChangeSum index a2a1d84b89..eac0f0accd 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,8 @@ Tag Who Date Summary ============================================================================================================================ + clm4_5_14_r226 erik 03/02/2017 Update cime, mosart and ccism to a version that is cesm2_0_beta05 or part of beta06 + clm4_5_14_r225 sacks 02/19/2017 Fix GDD accumulation in new crop columns + clm4_5_14_r224 sacks 02/10/2017 Tweaks for glaciers and snow clm4_5_14_r223 sacks 02/03/2017 Handle patch-level C&N variables correctly with dynamic landunits clm4_5_14_r222 sacks 01/27/2017 Fix energy budget bug with fractional snow on glacier and wetland columns clm4_5_14_r221 sacks 01/24/2017 Change rain-snow partitioning and ice albedo for glacier columns diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index 572ee63e3c..a216477530 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -423,12 +423,11 @@ subroutine CNPhenologyClimate (num_soilp, filter_soilp, num_pcropp, filter_pcrop integer , intent(in) :: filter_pcropp(:)! filter for prognostic crop patches type(temperature_type) , intent(inout) :: temperature_inst type(cnveg_state_type) , intent(inout) :: cnveg_state_inst - type(crop_type) , intent(in) :: crop_inst + type(crop_type) , intent(inout) :: crop_inst ! ! !LOCAL VARIABLES: integer :: p ! indices integer :: fp ! lake filter patch index - integer :: nyrs ! number of years prognostic crop has run real(r8) :: dayspyr ! days per year (days) integer :: kyr ! current year integer :: kmo ! month of year (1, ..., 12) @@ -439,7 +438,9 @@ subroutine CNPhenologyClimate (num_soilp, filter_soilp, num_pcropp, filter_pcrop !----------------------------------------------------------------------- associate( & - t_ref2m => temperature_inst%t_ref2m_patch , & ! Input: [real(r8) (:) ] 2m air temperature (K) + nyrs_crop_active => crop_inst%nyrs_crop_active_patch, & ! InOut: [integer (:) ] number of years this crop patch has been active + + t_ref2m => temperature_inst%t_ref2m_patch , & ! Input: [real(r8) (:) ] 2m air temperature (K) gdd0 => temperature_inst%gdd0_patch , & ! Output: [real(r8) (:) ] growing deg. days base 0 deg C (ddays) gdd8 => temperature_inst%gdd8_patch , & ! Output: [real(r8) (:) ] " " " " 8 " " " gdd10 => temperature_inst%gdd10_patch , & ! Output: [real(r8) (:) ] " " " " 10 " " " @@ -469,18 +470,17 @@ subroutine CNPhenologyClimate (num_soilp, filter_soilp, num_pcropp, filter_pcrop if (num_pcropp > 0) then ! get time-related info call get_curr_date(kyr, kmo, kda, mcsec) - nyrs = crop_inst%CropRestYear end if do fp = 1,num_pcropp p = filter_pcropp(fp) - if (kmo == 1 .and. kda == 1 .and. nyrs == 0) then ! YR 1: + if (kmo == 1 .and. kda == 1 .and. nyrs_crop_active(p) == 0) then ! YR 1: gdd020(p) = 0._r8 ! set gdd..20 variables to 0 gdd820(p) = 0._r8 ! and crops will not be planted gdd1020(p) = 0._r8 end if if (kmo == 1 .and. kda == 1 .and. mcsec == 0) then ! <-- END of EVERY YR: - if (nyrs == 1) then ! <-- END of YR 1 + if (nyrs_crop_active(p) == 1) then ! <-- END of YR 1 gdd020(p) = gdd0(p) ! <-- END of YR 1 gdd820(p) = gdd8(p) ! <-- END of YR 1 gdd1020(p) = gdd10(p) ! <-- END of YR 1 diff --git a/src/biogeochem/CNVegetationFacade.F90 b/src/biogeochem/CNVegetationFacade.F90 index c8f2736053..bc586bc2f2 100644 --- a/src/biogeochem/CNVegetationFacade.F90 +++ b/src/biogeochem/CNVegetationFacade.F90 @@ -736,6 +736,8 @@ subroutine EcosystemDynamicsPreDrainage(this, bounds, & character(len=*), parameter :: subname = 'EcosystemDynamicsPreDrainage' !----------------------------------------------------------------------- + call crop_inst%CropIncrementYear(num_pcropp, filter_pcropp) + call CNDriverNoLeaching(bounds, & num_soilc, filter_soilc, & num_soilp, filter_soilp, & diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index 7df7e8987b..29dd796290 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -28,6 +28,7 @@ module CropType type, public :: crop_type ! Note that cropplant and harvdate could be 2D to facilitate rotation + integer , pointer :: nyrs_crop_active_patch (:) ! number of years this crop patch has been active (0 for non-crop patches) logical , pointer :: croplive_patch (:) ! patch Flag, true if planted, not harvested logical , pointer :: cropplant_patch (:) ! patch Flag, true if planted integer , pointer :: harvdate_patch (:) ! patch harvest date @@ -36,7 +37,6 @@ module CropType 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 - integer :: CropRestYear ! restart year from initial conditions file - increment as time elapses real(r8), pointer :: latbaset_patch (:) ! Latitude vary baset for gddplant (degree C) character(len=20) :: baset_mapping real(r8) :: baset_latvary_intercept @@ -56,7 +56,7 @@ module CropType ! , which was fixed in pgi 14.7. procedure, public :: CropUpdateAccVars - procedure, public :: CropRestIncYear + procedure, public :: CropIncrementYear ! Private routines procedure, private :: InitAllocate @@ -182,6 +182,7 @@ subroutine InitAllocate(this, bounds) begp = bounds%begp; endp = bounds%endp + allocate(this%nyrs_crop_active_patch(begp:endp)) ; this%nyrs_crop_active_patch(:) = 0 allocate(this%croplive_patch (begp:endp)) ; this%croplive_patch (:) = .false. allocate(this%cropplant_patch(begp:endp)) ; this%cropplant_patch(:) = .false. allocate(this%harvdate_patch (begp:endp)) ; this%harvdate_patch (:) = huge(1) @@ -192,8 +193,6 @@ subroutine InitAllocate(this, bounds) allocate(this%cphase_patch (begp:endp)) ; this%cphase_patch (:) = 0.0_r8 allocate(this%latbaset_patch (begp:endp)) ; this%latbaset_patch (:) = spval - this%CropRestYear = 0 - end subroutine InitAllocate !----------------------------------------------------------------------- @@ -262,6 +261,9 @@ subroutine InitCold(this, bounds) do p= bounds%begp,bounds%endp g = patch%gridcell(p) ivt = patch%itype(p) + + this%nyrs_crop_active_patch(p) = 0 + if ( grc%latdeg(g) >= 0.0_r8 .and. grc%latdeg(g) <= 30.0_r8) then this%latbaset_patch(p)=pftcon%baset(ivt)+12._r8-0.4_r8*grc%latdeg(g) else if (grc%latdeg(g) < 0.0_r8 .and. grc%latdeg(g) >= -30.0_r8) then @@ -381,6 +383,8 @@ subroutine Restart(this, bounds, ncid, flag) ! !USES: use restUtilMod use ncdio_pio + use PatchType, only : patch + use pftconMod, only : npcropmin, npcropmax ! ! !ARGUMENTS: class(crop_type), intent(inout) :: this @@ -390,6 +394,7 @@ subroutine Restart(this, bounds, ncid, flag) ! ! !LOCAL VARIABLES: integer, pointer :: temp1d(:) ! temporary + integer :: restyear integer :: p logical :: readvar ! determine if variable is on initial file @@ -397,6 +402,31 @@ subroutine Restart(this, bounds, ncid, flag) !----------------------------------------------------------------------- if (use_crop) then + call restartvar(ncid=ncid, flag=flag, varname='nyrs_crop_active', xtype=ncd_int, & + dim1name='pft', & + long_name='Number of years this crop patch has been active (0 for non-crop patches)', & + units='years', & + interpinic_flag='interp', readvar=readvar, data=this%nyrs_crop_active_patch) + if (flag == 'read' .and. .not. readvar) then + ! BACKWARDS_COMPATIBILITY(wjs, 2017-02-17) Old restart files did not have this + ! patch-level variable. Instead, they had a single scalar tracking the number + ! of years the crop model ran. Copy this scalar onto all *active* crop patches. + + ! Some arguments in the following restartvar call are irrelevant, because we + ! only call this for 'read'. I'm simply maintaining the old restartvar call. + call restartvar(ncid=ncid, flag=flag, varname='restyear', xtype=ncd_int, & + long_name='Number of years prognostic crop ran', units="years", & + interpinic_flag='copy', readvar=readvar, data=restyear) + if (readvar) then + do p = bounds%begp, bounds%endp + if (patch%itype(p) >= npcropmin .and. patch%itype(p) <= npcropmax .and. & + patch%active(p)) then + this%nyrs_crop_active_patch(p) = restyear + end if + end do + end if + end if + allocate(temp1d(bounds%begp:bounds%endp)) if (flag == 'write') then do p= bounds%begp,bounds%endp @@ -455,10 +485,6 @@ subroutine Restart(this, bounds, ncid, flag) dim1name='pft', long_name='vernalization factor', units='', & interpinic_flag='interp', readvar=readvar, data=this%vf_patch) - call restartvar(ncid=ncid, flag=flag, varname='restyear', xtype=ncd_int, & - long_name='Number of years prognostic crop ran', units="years", & - interpinic_flag='copy', readvar=readvar, data=this%CropRestYear) - call restartvar(ncid=ncid, flag=flag, varname='cphase',xtype=ncd_double, & dim1name='pft', long_name='crop phenology phase', & units='0-not planted, 1-planted, 2-leaf emerge, 3-grain fill, 4-harvest', & @@ -576,40 +602,42 @@ subroutine CropUpdateAccVars(this, bounds, t_ref2m_patch, t_soisno_col) end subroutine CropUpdateAccVars !----------------------------------------------------------------------- - subroutine CropRestIncYear (this) + subroutine CropIncrementYear (this, num_pcropp, filter_pcropp) ! ! !DESCRIPTION: - ! Increment the crop restart year, if appropriate + ! Increment the crop year, if appropriate ! - ! This routine should be called every time step, but only once for all clumps (to - ! avoid inadvertently updating nyrs multiple times) + ! This routine should be called every time step ! ! !USES: use clm_time_manager , only : get_curr_date, is_first_step ! ! !ARGUMENTS: class(crop_type) :: this + integer , intent(in) :: num_pcropp ! number of prog. crop patches in filter + integer , intent(in) :: filter_pcropp(:) ! filter for prognostic crop patches ! ! !LOCAL VARIABLES: integer kyr ! current year integer kmo ! month of year (1, ..., 12) integer kda ! day of month (1, ..., 31) integer mcsec ! seconds of day (0, ..., seconds/day) + integer :: fp, p !----------------------------------------------------------------------- - ! Update restyear only when running with prognostic crop - if ( use_crop )then - - ! Update restyear when it's the start of a new year - but don't do that at the - ! very start of the run - call get_curr_date ( kyr, kmo, kda, mcsec) - if ((kmo == 1 .and. kda == 1 .and. mcsec == 0) .and. .not. is_first_step()) then - this%CropRestYear = this%CropRestYear + 1 - end if + call get_curr_date ( kyr, kmo, kda, mcsec) + ! Update nyrs when it's the end of the year (unless it's the very start of the + ! run). This assumes that, if this patch is active at the end of the year, then it was + ! active for the whole year. + if ((kmo == 1 .and. kda == 1 .and. mcsec == 0) .and. .not. is_first_step()) then + do fp = 1, num_pcropp + p = filter_pcropp(fp) + this%nyrs_crop_active_patch(p) = this%nyrs_crop_active_patch(p) + 1 + end do end if - end subroutine CropRestIncYear + end subroutine CropIncrementYear !----------------------------------------------------------------------- subroutine checkDates( ) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 10c57a1a3e..7ff0387460 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -152,7 +152,7 @@ subroutine BalanceCheck( bounds, & use clm_varcon , only : spval use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_perv, icol_road_imperv - use landunit_varcon , only : istdlak, istsoil,istcrop,istwet + use landunit_varcon , only : istdlak, istsoil,istcrop,istwet,istice,istice_mec use clm_varctl , only : create_glacier_mec_landunit use clm_time_manager , only : get_step_size, get_nstep use clm_initializeMod , only : surfalb_inst @@ -419,7 +419,8 @@ subroutine BalanceCheck( bounds, & endif if (col%itype(c) == icol_road_perv .or. lun%itype(l) == istsoil .or. & - lun%itype(l) == istcrop .or. lun%itype(l) == istwet ) then + lun%itype(l) == istcrop .or. lun%itype(l) == istwet .or. & + lun%itype(l) == istice .or. lun%itype(l) == istice_mec) then snow_sources(c) = (qflx_snow_grnd_col(c) - qflx_snow_h2osfc(c) ) & + frac_sno_eff(c) * (qflx_rain_grnd_col(c) & + qflx_dew_snow(c) + qflx_dew_grnd(c) ) + qflx_h2osfc_to_ice(c) diff --git a/src/biogeophys/CanopyHydrologyMod.F90 b/src/biogeophys/CanopyHydrologyMod.F90 index 6c8e615eb6..099edeffba 100644 --- a/src/biogeophys/CanopyHydrologyMod.F90 +++ b/src/biogeophys/CanopyHydrologyMod.F90 @@ -155,7 +155,7 @@ subroutine CanopyHydrology(bounds, & ! temperature in the subroutine clm\_leaftem.f90, not in this subroutine. ! ! !USES: - use clm_varcon , only : hfus, denice, zlnd, rpi, spval, tfrz + use clm_varcon , only : hfus, denice, zlnd, rpi, spval, tfrz, int_snow_max use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use landunit_varcon , only : istcrop, istice, istwet, istsoil, istice_mec use clm_varctl , only : subgridflag @@ -214,6 +214,7 @@ subroutine CanopyHydrology(bounds, & real(r8) :: delf_melt real(r8) :: fsno_new real(r8) :: accum_factor + real(r8) :: int_snow_limited ! integrated snowfall, limited to be no greater than int_snow_max [mm] real(r8) :: newsnow(bounds%begc:bounds%endc) real(r8) :: snowmelt(bounds%begc:bounds%endc) integer :: j @@ -525,7 +526,8 @@ subroutine CanopyHydrology(bounds, & ! first compute change from melt during previous time step if(snowmelt(c) > 0._r8) then - smr=min(1._r8,(h2osno(c))/(int_snow(c))) + int_snow_limited = min(int_snow(c), int_snow_max) + smr=min(1._r8,h2osno(c)/int_snow_limited) frac_sno(c) = 1. - (acos(min(1._r8,(2.*smr - 1._r8)))/rpi)**(n_melt(c)) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index 35ab82db67..8f66eb086e 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -334,6 +334,11 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp) avgflag='A', long_name='net infrared (longwave) radiation', & ptr_patch=this%eflx_lwrad_net_patch, c2l_scale_type='urbanf') + call hist_addfld1d (fname='FIRA_ICE', units='W/m^2', & + avgflag='A', long_name='net infrared (longwave) radiation (ice landunits only)', & + ptr_patch=this%eflx_lwrad_net_patch, c2l_scale_type='urbanf', l2g_scale_type='ice',& + default='inactive') + this%eflx_lwrad_net_r_patch(begp:endp) = spval call hist_addfld1d (fname='FIRA_R', units='W/m^2', & avgflag='A', long_name='Rural net infrared (longwave) radiation', & diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 74fab4a537..2d1882093b 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -38,7 +38,7 @@ function hcol_distance(c, ctop, cbottom, hill_length) result(x) ! ! !DESCRIPTION: ! Returns distance from the bottom of the hillslope of the - ! column's lower edge. Assumes hilltop to hillbottom column + ! column's node. Assumes hilltop to hillbottom column ! ordering based on lun%coli, lun%colf (see initHillslopeMod). ! ! !USES: @@ -55,7 +55,7 @@ function hcol_distance(c, ctop, cbottom, hill_length) result(x) character(len=*), parameter :: subname = 'hcol_distance' !----------------------------------------------------------------------- - x = hill_length * real(cbottom - c,r8) & + x = hill_length * (real(cbottom - c,r8) +0.5_r8) & / real(cbottom - ctop + 1,r8) end function hcol_distance @@ -63,7 +63,7 @@ end function hcol_distance function hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) result(width) ! ! !DESCRIPTION: - ! Returns width of lower edge of hillslope column. + ! Returns width of hillslope column. ! ! !USES: ! @@ -78,30 +78,37 @@ function hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) result(widt ! ! !LOCAL VARIABLES: real(r8) :: eps = 1.e-6_r8 - real(r8) :: y0 ! y integration limit + real(r8) :: x0,y0,yl ! integration limits character(len=*), parameter :: subname = 'hcol_width' !----------------------------------------------------------------------- ! width function has special case for n = 2 ! in this implementation, integration limits depend on sign of beta if (abs(alpha - 2._r8) < eps) then - y0 = hill_width/2._r8 - ! log blows up at x=0; 0.2 set by trial and error - if(beta < 0._r8) y0 = y0*exp(-(beta*hill_length**2/hill_height) & - * log(0.2/hill_length)) + + ! function blows up for x0=0; integration limits set by trial and error + if(beta < 0._r8) then + y0 = hill_width/2._r8 + yl = 0.1_r8 + x0=hill_length *(yl/y0)**(-hill_height/(beta*hill_length**2)) + else + x0 = 0.2_r8 + y0 = (hill_width/2._r8)& + *(x0/hill_length)**(beta*hill_length**2/hill_height) + endif ! compiler does not like log(zero) if (x == 0._r8) then - if (beta > 0) then - width = eps + if (beta < 0._r8) then + width = hill_width/2._r8 else - width = hill_width/2._r8! - y0 + width = eps endif else - width = exp(((beta*hill_length**2/hill_height) & - * log(x/hill_length)) + log(y0)) + width = y0*(x/x0)**(beta*hill_length**2/hill_height) endif - else ! n /= 2 + else + ! alpha /= 2 case, x0 equals zero y0 = hill_width/2._r8 if(beta > 0._r8) then y0 = y0 * exp(-(2._r8*beta*hill_length**2) & @@ -111,10 +118,9 @@ function hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) result(widt if (x == 0._r8) then width = y0 else - width = exp((((2._r8*beta*hill_length**2) & + width = y0*exp((((2._r8*beta*hill_length**2) & / (hill_height*(2._r8 - alpha)*alpha)) & - * (x/hill_length)**(2._r8-alpha)) & - + log(y0)) + * (x/hill_length)**(2._r8-alpha))) endif endif ! hillslope width is twice integral [0:x] diff --git a/src/biogeophys/SnowHydrologyMod.F90 b/src/biogeophys/SnowHydrologyMod.F90 index c1be8be9af..6e289b7c77 100644 --- a/src/biogeophys/SnowHydrologyMod.F90 +++ b/src/biogeophys/SnowHydrologyMod.F90 @@ -552,7 +552,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ! ! !USES: use clm_time_manager, only : get_step_size - use clm_varcon , only : denice, denh2o, tfrz, rpi + use clm_varcon , only : denice, denh2o, tfrz, rpi, int_snow_max use landunit_varcon , only : istdlak, istsoil, istcrop use clm_varctl , only : subgridflag ! @@ -589,12 +589,14 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & real(r8) :: wsum ! snowpack total water mass (ice+liquid) [kg/m2] real(r8) :: fsno_melt real(r8) :: ddz4 ! Rate of compaction of snowpack due to wind drift. + real(r8) :: int_snow_limited ! integrated snowfall, limited to be no greater than int_snow_max [mm] !----------------------------------------------------------------------- associate( & snl => col%snl , & ! Input: [integer (:) ] number of snow layers n_melt => col%n_melt , & ! Input: [real(r8) (:) ] SCA shape parameter - ltype => lun%itype , & ! Input: [integer (:) ] landunit type + lakpoi => lun%lakpoi , & ! Input: [logical (:) ] true => landunit is a lake point + urbpoi => lun%urbpoi , & ! Input: [logical (:) ] true => landunit is an urban point forc_wind => atm2lnd_inst%forc_wind_grc , & ! Input: [real(r8) (:) ] atmospheric wind speed (m/s) t_soisno => temperature_inst%t_soisno_col , & ! Input: [real(r8) (:,:) ] soil temperature (Kelvin) @@ -675,14 +677,20 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ! Compaction occurring during melt if (imelt(c,j) == 1) then - if(subgridflag==1 .and. (ltype(col%landunit(c)) == istsoil .or. ltype(col%landunit(c)) == istcrop)) then + l = col%landunit(c) + ! For consistency with other uses of subgridflag==1 (e.g., in + ! CanopyHydrologyMod), we apply this code over all landunits other + ! than lake and urban. (In CanopyHydrologyMod, the uses of subgridflag + ! are in a nolake filter, and check .not. urbpoi.) + if(subgridflag==1 .and. (.not. lakpoi(l) .and. .not. urbpoi(l))) then ! first term is delta mass over mass ddz3 = max(0._r8,min(1._r8,(swe_old(c,j) - wx)/wx)) ! 2nd term is delta fsno over fsno, allowing for negative values for ddz3 if((swe_old(c,j) - wx) > 0._r8) then wsum = sum(h2osoi_liq(c,snl(c)+1:0)+h2osoi_ice(c,snl(c)+1:0)) - fsno_melt = 1. - (acos(2.*min(1._r8,wsum/int_snow(c)) - 1._r8)/rpi)**(n_melt(c)) + int_snow_limited = min(int_snow(c), int_snow_max) + fsno_melt = 1. - (acos(2.*min(1._r8,wsum/int_snow_limited) - 1._r8)/rpi)**(n_melt(c)) ddz3 = ddz3 - max(0._r8,(fsno_melt - frac_sno(c))/frac_sno(c)) endif diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 318c33c6d0..651fa99ea1 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2490,8 +2490,8 @@ subroutine LateralFlowHillslope(bounds, & if (baseflow_method == 'darcy') then if (col%cold(c) /= ispval) then c_down = col%cold(c) - dgrad = (col%hill_elev(c)+zwt(c)) & - - (col%hill_elev(c_down)+zwt(c_down)) + dgrad = (col%hill_elev(c)+(zi(c,nbedrock(c))-zwt(c))) & + - (col%hill_elev(c_down)+(zi(c,nbedrock(c))-zwt(c_down))) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(c_down)) else !what lower boundary condition to use?? diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index de48ee0ee1..905c200dc1 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -469,7 +469,13 @@ subroutine InitHistory(this, bounds) this%int_snow_col(begc:endc) = spval call hist_addfld1d (fname='INT_SNOW', units='mm', & avgflag='A', long_name='accumulated swe (vegetated landunits only)', & - ptr_col=this%int_snow_col, l2g_scale_type='veg') + ptr_col=this%int_snow_col, l2g_scale_type='veg', & + default='inactive') + + call hist_addfld1d (fname='INT_SNOW_ICE', units='mm', & + avgflag='A', long_name='accumulated swe (ice landunits only)', & + ptr_col=this%int_snow_col, l2g_scale_type='ice', & + default='inactive') if (create_glacier_mec_landunit) then this%snow_persistence_col(begc:endc) = spval @@ -559,7 +565,7 @@ subroutine InitCold(this, bounds, & use column_varcon , only : icol_shadewall, icol_road_perv use column_varcon , only : icol_road_imperv, icol_roof, icol_sunwall use clm_varcon , only : denice, denh2o, spval, sb, bdsno - use clm_varcon , only : h2osno_max, zlnd, tfrz, spval, pc + use clm_varcon , only : zlnd, tfrz, spval, pc use clm_varctl , only : fsurdat, iulog use clm_varctl , only : use_bedrock use spmdMod , only : masterproc diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index e2bbd0607c..8980d8b45d 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -70,7 +70,7 @@ subroutine downscale_forcings(bounds, & ! (rain vs. snow partitioning) is adjusted everywhere. ! ! !USES: - use clm_varcon , only : rair, cpair, grav, lapse_glcmec + use clm_varcon , only : rair, cpair, grav use QsatMod , only : Qsat ! ! !ARGUMENTS: @@ -98,6 +98,9 @@ subroutine downscale_forcings(bounds, & SHR_ASSERT_ALL((ubound(eflx_sh_precip_conversion) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) associate(& + ! Parameters: + lapse_rate => atm2lnd_inst%params%lapse_rate , & ! Input: [real(r8)] Surface temperature lapse rate (K m-1) + ! Gridcell-level metadata: forc_topo_g => atm2lnd_inst%forc_topo_grc , & ! Input: [real(r8) (:)] atmospheric surface height (m) @@ -153,7 +156,7 @@ subroutine downscale_forcings(bounds, & pbot_g = forc_pbot_g(g) ! atm sfc pressure rhos_g = forc_rho_g(g) ! atm density zbot = atm2lnd_inst%forc_hgt_grc(g) ! atm ref height - tbot_c = tbot_g-lapse_glcmec*(hsurf_c-hsurf_g) ! sfc temp for column + tbot_c = tbot_g-lapse_rate*(hsurf_c-hsurf_g) ! sfc temp for column Hbot = rair*0.5_r8*(tbot_g+tbot_c)/grav ! scale ht at avg temp pbot_c = pbot_g*exp(-(hsurf_c-hsurf_g)/Hbot) ! column sfc press @@ -403,9 +406,6 @@ subroutine downscale_longwave(bounds, downscale_filter_c, & ! Downscale longwave radiation from gridcell to column ! Must be done AFTER temperature downscaling ! - ! !USES: - use clm_varcon , only : lapse_glcmec - ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds type(filter_col_type) , intent(in) :: downscale_filter_c @@ -426,6 +426,10 @@ subroutine downscale_longwave(bounds, downscale_filter_c, & !----------------------------------------------------------------------- associate(& + ! Parameters: + lapse_rate_longwave => atm2lnd_inst%params%lapse_rate_longwave , & ! Input: [real(r8)] longwave radiation lapse rate (W m-2 m-1) + longwave_downscaling_limit => atm2lnd_inst%params%longwave_downscaling_limit, & ! Input: [real(r8)] Relative limit for how much longwave downscaling can be done (unitless) + ! Gridcell-level metadata: forc_topo_g => atm2lnd_inst%forc_topo_grc , & ! Input: [real(r8) (:)] atmospheric surface height (m) @@ -433,11 +437,9 @@ subroutine downscale_longwave(bounds, downscale_filter_c, & topo_c => topo_inst%topo_col , & ! Input: [real(r8) (:)] column surface height (m) ! Gridcell-level fields: - forc_t_g => atm2lnd_inst%forc_t_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric temperature (Kelvin) forc_lwrad_g => atm2lnd_inst%forc_lwrad_not_downscaled_grc, & ! Input: [real(r8) (:)] downward longwave (W/m**2) ! Column-level (downscaled) fields: - forc_t_c => atm2lnd_inst%forc_t_downscaled_col , & ! Input: [real(r8) (:)] atmospheric temperature (Kelvin) forc_lwrad_c => atm2lnd_inst%forc_lwrad_downscaled_col & ! Output: [real(r8) (:)] downward longwave (W/m**2) ) @@ -468,14 +470,19 @@ subroutine downscale_longwave(bounds, downscale_filter_c, & hsurf_g = forc_topo_g(g) hsurf_c = topo_c(c) - ! Here we assume that deltaLW = (dLW/dT)*(dT/dz)*deltaz - ! We get dLW/dT = 4*eps*sigma*T^3 = 4*LW/T from the Stefan-Boltzmann law, - ! evaluated at the mean temp. - ! We assume the same temperature lapse rate as above. - - forc_lwrad_c(c) = forc_lwrad_g(g) - & - 4.0_r8 * forc_lwrad_g(g)/(0.5_r8*(forc_t_c(c)+forc_t_g(g))) * & - lapse_glcmec * (hsurf_c - hsurf_g) + ! Assume a linear decrease in downwelling longwave radiation with increasing + ! elevation, based on Van Tricht et al. (2016, TC) Figure 6, + ! doi:10.5194/tc-10-2379-2016 + forc_lwrad_c(c) = forc_lwrad_g(g) - lapse_rate_longwave * (hsurf_c-hsurf_g) + ! But ensure that we don't depart too far from the atmospheric forcing value: + ! negative values of lwrad are certainly bad, but small positive values might + ! also be bad. We can especially run into trouble due to the normalization: a + ! small lwrad value in one column can lead to a big normalization factor, + ! leading to huge lwrad values in other columns. + forc_lwrad_c(c) = min(forc_lwrad_c(c), & + forc_lwrad_g(g) * (1._r8 + longwave_downscaling_limit)) + forc_lwrad_c(c) = max(forc_lwrad_c(c), & + forc_lwrad_g(g) * (1._r8 - longwave_downscaling_limit)) ! Keep track of the gridcell-level weighted sum for later normalization. ! @@ -573,8 +580,12 @@ subroutine build_normalization(orig_field, sum_field, sum_wts, norms) norms = 1.0_r8 elsewhere (sum_field == 0._r8) - ! Avoid divide by zero; this should only happen if the gridcell-level value is 0, - ! in which case the normalization doesn't matter + ! Avoid divide by zero. If this is because both sum_field and orig_field are 0, + ! then the normalization doesn't matter. If sum_field == 0 while orig_field /= 0, + ! then we have a problem: no normalization will allow us to recover the original + ! gridcell mean. We should probably catch this and abort, but for now we're + ! relying on error checking in the caller (checking for conservation) to catch + ! this potential problem. norms = 1.0_r8 elsewhere diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index 6c7178c7e8..75449486e6 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -29,6 +29,17 @@ module atm2lndType ! true => downscale longwave radiation logical :: glcmec_downscale_longwave + ! Surface temperature lapse rate (K m-1) + real(r8) :: lapse_rate + + ! longwave radiation lapse rate (W m-2 m-1) + real(r8) :: lapse_rate_longwave + + ! Relative limit for how much longwave downscaling can be done (unitless) + ! The pre-normalized, downscaled longwave is restricted to be in the range + ! [lwrad*(1-longwave_downscaling_limit), lwrad*(1+longwave_downscaling_limit)] + real(r8) :: longwave_downscaling_limit + ! Rain-snow ramp for glacier landunits ! frac_rain = (temp - all_snow_t) * frac_rain_slope ! (all_snow_t is in K) @@ -159,6 +170,7 @@ module atm2lndType !----------------------------------------------------------------------- function atm2lnd_params_constructor(repartition_rain_snow, glcmec_downscale_longwave, & + lapse_rate, lapse_rate_longwave, longwave_downscaling_limit, & precip_repartition_glc_all_snow_t, precip_repartition_glc_all_rain_t, & precip_repartition_nonglc_all_snow_t, precip_repartition_nonglc_all_rain_t) & result(params) @@ -173,6 +185,17 @@ function atm2lnd_params_constructor(repartition_rain_snow, glcmec_downscale_long logical, intent(in) :: repartition_rain_snow logical, intent(in) :: glcmec_downscale_longwave + ! Surface temperature lapse rate (K m-1) + real(r8), intent(in) :: lapse_rate + + ! Longwave radiation lapse rate (W m-2 m-1) + ! Must be present if glcmec_downscale_longwave is true; ignored otherwise + real(r8), intent(in), optional :: lapse_rate_longwave + + ! Relative limit for how much longwave downscaling can be done (unitless) + ! Must be present if glcmec_downscale_longwave is true; ignored otherwise + real(r8), intent(in), optional :: longwave_downscaling_limit + ! End-points of the rain-snow ramp for glacier landunits (degrees C) ! Must be present if repartition_rain_snow is true; ignored otherwise real(r8), intent(in), optional :: precip_repartition_glc_all_snow_t @@ -191,6 +214,31 @@ function atm2lnd_params_constructor(repartition_rain_snow, glcmec_downscale_long params%repartition_rain_snow = repartition_rain_snow params%glcmec_downscale_longwave = glcmec_downscale_longwave + params%lapse_rate = lapse_rate + + if (glcmec_downscale_longwave) then + if (.not. present(lapse_rate_longwave)) then + call endrun(subname // & + ' ERROR: For glcmec_downscale_longwave true, lapse_rate_longwave must be provided') + end if + if (.not. present(longwave_downscaling_limit)) then + call endrun(subname // & + ' ERROR: For glcmec_downscale_longwave true, longwave_downscaling_limit must be provided') + end if + + if (longwave_downscaling_limit < 0._r8 .or. & + longwave_downscaling_limit > 1._r8) then + call endrun(subname // & + ' ERROR: longwave_downscaling_limit must be between 0 and 1') + end if + + params%lapse_rate_longwave = lapse_rate_longwave + params%longwave_downscaling_limit = longwave_downscaling_limit + else + params%lapse_rate_longwave = nan + params%longwave_downscaling_limit = nan + end if + if (repartition_rain_snow) then ! Make sure all of the repartitioning-related parameters are present @@ -298,9 +346,11 @@ subroutine InitForTesting(this, bounds, params) if (present(params)) then l_params = params else + ! Use arbitrary values l_params = atm2lnd_params_type( & repartition_rain_snow = .false., & - glcmec_downscale_longwave = .false.) + glcmec_downscale_longwave = .false., & + lapse_rate = 0.01_r8) end if call this%InitAllocate(bounds) @@ -330,6 +380,9 @@ subroutine ReadNamelist(this, NLFilename) ! temporary variables corresponding to the components of atm2lnd_params_type logical :: repartition_rain_snow logical :: glcmec_downscale_longwave + real(r8) :: lapse_rate + real(r8) :: lapse_rate_longwave + real(r8) :: longwave_downscaling_limit real(r8) :: precip_repartition_glc_all_snow_t real(r8) :: precip_repartition_glc_all_rain_t real(r8) :: precip_repartition_nonglc_all_snow_t @@ -343,12 +396,16 @@ subroutine ReadNamelist(this, NLFilename) !----------------------------------------------------------------------- namelist /atm2lnd_inparm/ repartition_rain_snow, glcmec_downscale_longwave, & + lapse_rate, lapse_rate_longwave, longwave_downscaling_limit, & precip_repartition_glc_all_snow_t, precip_repartition_glc_all_rain_t, & precip_repartition_nonglc_all_snow_t, precip_repartition_nonglc_all_rain_t ! Initialize namelist variables to defaults repartition_rain_snow = .false. glcmec_downscale_longwave = .false. + lapse_rate = nan + lapse_rate_longwave = nan + longwave_downscaling_limit = nan precip_repartition_glc_all_snow_t = nan precip_repartition_glc_all_rain_t = nan precip_repartition_nonglc_all_snow_t = nan @@ -371,6 +428,9 @@ subroutine ReadNamelist(this, NLFilename) call shr_mpi_bcast(repartition_rain_snow, mpicom) call shr_mpi_bcast(glcmec_downscale_longwave, mpicom) + call shr_mpi_bcast(lapse_rate, mpicom) + call shr_mpi_bcast(lapse_rate_longwave, mpicom) + call shr_mpi_bcast(longwave_downscaling_limit, mpicom) call shr_mpi_bcast(precip_repartition_glc_all_snow_t, mpicom) call shr_mpi_bcast(precip_repartition_glc_all_rain_t, mpicom) call shr_mpi_bcast(precip_repartition_nonglc_all_snow_t, mpicom) @@ -383,6 +443,11 @@ subroutine ReadNamelist(this, NLFilename) ! be NaN if certain options are turned off. write(iulog,*) 'repartition_rain_snow = ', repartition_rain_snow write(iulog,*) 'glcmec_downscale_longwave = ', glcmec_downscale_longwave + write(iulog,*) 'lapse_rate = ', lapse_rate + if (glcmec_downscale_longwave) then + write(iulog,*) 'lapse_rate_longwave = ', lapse_rate_longwave + write(iulog,*) 'longwave_downscaling_limit = ', longwave_downscaling_limit + end if if (repartition_rain_snow) then write(iulog,*) 'precip_repartition_glc_all_snow_t = ', precip_repartition_glc_all_snow_t write(iulog,*) 'precip_repartition_glc_all_rain_t = ', precip_repartition_glc_all_rain_t @@ -395,6 +460,9 @@ subroutine ReadNamelist(this, NLFilename) this%params = atm2lnd_params_type( & repartition_rain_snow = repartition_rain_snow, & glcmec_downscale_longwave = glcmec_downscale_longwave, & + lapse_rate = lapse_rate, & + lapse_rate_longwave = lapse_rate_longwave, & + longwave_downscaling_limit = longwave_downscaling_limit, & precip_repartition_glc_all_snow_t = precip_repartition_glc_all_snow_t, & precip_repartition_glc_all_rain_t = precip_repartition_glc_all_rain_t, & precip_repartition_nonglc_all_snow_t = precip_repartition_nonglc_all_snow_t, & diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 21a0471e12..c7b4076728 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -164,10 +164,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call get_proc_bounds(bounds_proc) nclumps = get_proc_clumps() - ! Update time-related info - - call crop_inst%CropRestIncYear() - ! ======================================================================== ! In the first time step of a run that used cold start or init_interp, glacier areas ! will start at whatever is specified on the surface dataset, because coupling fields @@ -1230,7 +1226,6 @@ subroutine clm_drv_init(bounds, & use shr_kind_mod , only : r8 => shr_kind_r8 use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use clm_varpar , only : nlevsno - use clm_varcon , only : h2osno_max use CanopyStateType , only : canopystate_type use WaterStateType , only : waterstate_type use WaterFluxType , only : waterflux_type diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 30b6484728..b393e9dd65 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -219,7 +219,7 @@ subroutine initialize1( ) call initHillslopes() ! Set single pft for hillslope columns - call HillslopeDomPft() +! call HillslopeDomPft() endif diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 88312ae2b4..a13ba39d91 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -10,7 +10,7 @@ module clm_instMod use clm_varpar , only : ndecomp_pools, nlevdecomp_full use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_ed, use_voc use clm_varctl , only : use_century_decomp, use_crop - use clm_varcon , only : h2osno_max, bdsno, c13ratio, c14ratio + use clm_varcon , only : bdsno, c13ratio, c14ratio use landunit_varcon , only : istice, istice_mec, istsoil use perf_mod , only : t_startf, t_stopf use controlMod , only : NLFilename diff --git a/src/main/clm_varcon.F90 b/src/main/clm_varcon.F90 index 8958d45157..45756f96ab 100644 --- a/src/main/clm_varcon.F90 +++ b/src/main/clm_varcon.F90 @@ -178,8 +178,8 @@ module clm_varcon !------------------------------------------------------------------ real(r8) :: h2osno_max = -999.0_r8 ! max allowed snow thickness (mm H2O) - real(r8), parameter :: lapse_glcmec = 0.006_r8 ! surface temperature lapse rate (deg m-1) - ! Pritchard et al. (GRL, 35, 2008) use 0.006 + real(r8) :: int_snow_max = -999.0_r8 ! limit applied to integrated snowfall when determining changes in snow-covered fraction during melt (mm H2O) + real(r8) :: n_melt_glcmec = -999.0_r8 ! SCA shape parameter for glc_mec columns integer, private :: i ! loop index diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 0113a8c434..da1bc2e436 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -17,7 +17,7 @@ module controlMod use abortutils , only: endrun use spmdMod , only: masterproc use decompMod , only: clump_pproc - use clm_varcon , only: h2osno_max + use clm_varcon , only: h2osno_max, int_snow_max, n_melt_glcmec use clm_varpar , only: maxpatch_pft, maxpatch_glcmec, numrad, nlevsno use histFileMod , only: max_tapes, max_namlen use histFileMod , only: hist_empty_htapes, hist_dov2xy, hist_avgflag_pertape, hist_type1d_pertape @@ -186,7 +186,7 @@ subroutine control_init( ) namelist /clm_inparm/ & maxpatch_glcmec, glc_do_dynglacier, & glc_snow_persistence_max_days, & - nlevsno, h2osno_max + nlevsno, h2osno_max, int_snow_max, n_melt_glcmec ! Other options @@ -385,8 +385,9 @@ subroutine control_init( ) end if end if - ! If nlevsno, h2osno_max are equal to their junk default value, then they were not specified - ! by the user namelist and we generate an error message. Also check nlevsno for bounds. + ! If nlevsno, h2osno_max, int_snow_max or n_melt_glcmec are equal to their junk + ! default value, then they were not specified by the user namelist and we generate + ! an error message. Also check nlevsno for bounds. if (nlevsno < 3 .or. nlevsno > 12) then write(iulog,*)'ERROR: nlevsno = ',nlevsno,' is not supported, must be in range 3-12.' call endrun(msg=' ERROR: invalid value for nlevsno in CLM namelist. '//& @@ -397,6 +398,16 @@ subroutine control_init( ) call endrun(msg=' ERROR: invalid value for h2osno_max in CLM namelist. '//& errMsg(sourcefile, __LINE__)) endif + if (int_snow_max <= 0.0_r8) then + write(iulog,*)'ERROR: int_snow_max = ',int_snow_max,' is not supported, must be greater than 0.0.' + call endrun(msg=' ERROR: invalid value for int_snow_max in CLM namelist. '//& + errMsg(sourcefile, __LINE__)) + endif + if (n_melt_glcmec <= 0.0_r8) then + write(iulog,*)'ERROR: n_melt_glcmec = ',n_melt_glcmec,' is not supported, must be greater than 0.0.' + call endrun(msg=' ERROR: invalid value for n_melt_glcmec in CLM namelist. '//& + errMsg(sourcefile, __LINE__)) + endif endif ! end of if-masterproc if-block @@ -665,6 +676,8 @@ subroutine control_spmd() ! snow pack variables call mpi_bcast (nlevsno, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (h2osno_max, 1, MPI_REAL8, 0, mpicom, ier) + call mpi_bcast (int_snow_max, 1, MPI_REAL8, 0, mpicom, ier) + call mpi_bcast (n_melt_glcmec, 1, MPI_REAL8, 0, mpicom, ier) ! glacier_mec variables call mpi_bcast (create_glacier_mec_landunit, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -819,11 +832,9 @@ subroutine control_print () write(iulog,*) ' Number of snow layers =', nlevsno write(iulog,*) ' Max snow depth (mm) =', h2osno_max - if (repartition_rain_snow) then - write(iulog,*) 'Rain vs. snow will be repartitioned based on surface temperature' - else - write(iulog,*) 'Rain vs. snow will NOT be repartitioned based on surface temperature' - end if + write(iulog,*) ' Limit applied to integrated snowfall when determining changes in' + write(iulog,*) ' snow-covered fraction during melt (mm) =', int_snow_max + write(iulog,*) ' SCA shape parameter for glc_mec columns (n_melt_glcmec) =', n_melt_glcmec if (create_glacier_mec_landunit) then write(iulog,*) ' glc number of elevation classes =', maxpatch_glcmec diff --git a/src/main/initHillslopeMod.F90 b/src/main/initHillslopeMod.F90 index 43f2ba949f..0ac0066706 100644 --- a/src/main/initHillslopeMod.F90 +++ b/src/main/initHillslopeMod.F90 @@ -108,14 +108,6 @@ subroutine initHillslopes() enddo ! end loop nh endif -!!$ if(lun%itype(l) == istsoil) then -!!$ write(iulog,*) 'testlun: ', l,lun%ncolumns(l), lun%nhillslopes(l),lun%coli(l),lun%colf(l) -!!$ do c=lun%coli(l), lun%colf(l) -!!$ write(iulog,*) 'testconn: ', l,c,col%cold(c),col%colu(c) -!!$ enddo -!!$! call endrun(msg='thats it!!') -!!$ endif - enddo ! end loop l enddo ! end loop nc !$OMP END PARALLEL DO diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index c6f064b304..4c65293c14 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -109,7 +109,7 @@ end subroutine ReadNL !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof) - use clm_varcon, only : zmin_bedrock + use clm_varcon, only : zmin_bedrock, n_melt_glcmec use clm_varctl, only : use_hillslope use HillslopeHydrologyMod ! @@ -155,6 +155,9 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] real(r8) :: hillslope_area ! total area of hillslope + real(r8) :: column_length ! length of column [m] + real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope + real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope integer :: ctop, cbottom ! hillslope top and bottom column indices ! Possible values for levgrnd_class. The important thing is that, for a given column, ! layers that are fundamentally different (e.g., soil vs bedrock) have different @@ -705,46 +708,31 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof ctop, cbottom, hill_length(l,nh)) ! if (masterproc) write(iulog,*) 'hd: ',c,col%hill_distance(c) + !distance of lower edge of column from hillslope bottom + column_length = hill_length(l,nh)/(lun%ncolumns(l)/nhillslope) + le_distance = col%hill_distance(c) - 0.5_r8*column_length + ue_distance = col%hill_distance(c) + 0.5_r8*column_length + ! width of lower edge of column from hillslope bottom - col%hill_width(c) = hcol_width(col%hill_distance(c),& + col%hill_width(c) = hcol_width(le_distance, & hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & hill_width(l,nh),hill_height(l,nh)) ! if (masterproc) write(iulog,*) 'hw: ',c,col%hill_width(c) - ! surface area of column - if (c == ctop) then - col%hill_area(c) = hcol_area(hill_length(l,nh),& - col%hill_distance(c), & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - else - col%hill_area(c) = hcol_area(col%hill_distance(c-1),& - col%hill_distance(c),& - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - endif + col%hill_area(c) = hcol_area(ue_distance, le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) ! if (masterproc) write(iulog,*) 'ha: ',c,col%hill_area(c) ! mean elevation of column relative to mean gridcell elevation - if (c == ctop) then - col%hill_elev(c) = hcol_elevation(hill_length(l,nh),& - col%hill_distance(c),& - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - else - col%hill_elev(c) = hcol_elevation(col%hill_distance(c-1),& - col%hill_distance(c),& - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - endif + col%hill_elev(c) = hcol_elevation(ue_distance, le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) ! if (masterproc) write(iulog,*) 'he: ',c,col%hill_elev(c) ! mean along-hill slope of column - if (c == ctop) then - col%hill_slope(c) = hcol_slope(hill_length(l,nh),col%hill_distance(c),hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) - else - col%hill_slope(c) = hcol_slope(col%hill_distance(c-1),col%hill_distance(c),hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) - endif + col%hill_slope(c) = hcol_slope(ue_distance, le_distance, & + hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) ! if (masterproc) write(iulog,*) 'hs: ',c,col%hill_slope(c) if (masterproc .and. 1==2) then @@ -990,9 +978,9 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof if (lun%itype(l)==istice_mec .and. glc_behavior%allow_multiple_columns_grc(g)) then ! ice_mec columns already account for subgrid topographic variability through ! their use of multiple elevation classes; thus, to avoid double-accounting for - ! topographic variability in these columns, we ignore topo_std and use a value - ! of n_melt that assumes little topographic variability within the column - col%n_melt(c) = 10._r8 + ! topographic variability in these columns, we ignore topo_std and use a fixed + ! value of n_melt. + col%n_melt(c) = n_melt_glcmec else col%n_melt(c) = 200.0/max(10.0_r8, col%topo_std(c)) end if diff --git a/src/main/test/atm2lnd_test/test_downscale_forcings.pf b/src/main/test/atm2lnd_test/test_downscale_forcings.pf index af942eb1cb..4fe5621c7b 100644 --- a/src/main/test/atm2lnd_test/test_downscale_forcings.pf +++ b/src/main/test/atm2lnd_test/test_downscale_forcings.pf @@ -24,13 +24,18 @@ module test_downscale_forcings type, extends(TestCase) :: TestDownscaleForcings type(atm2lnd_type) :: atm2lnd_inst type(topo_type_always_downscale) :: topo_inst + real(r8), allocatable :: eflx_sh_precip_conversion(:) contains procedure :: setUp procedure :: tearDown procedure :: create_atm2lnd procedure :: create_topo + procedure :: call_downscale_forcings end type TestDownscaleForcings + real(r8), parameter :: lapse_rate = 0.006_r8 + real(r8), parameter :: lapse_rate_longwave = 0.03_r8 + real(r8), parameter :: tol = 1.e-13_r8 contains @@ -66,7 +71,7 @@ contains end subroutine tearDown subroutine create_atm2lnd(this, forc_topo, forc_t, forc_th, forc_q, forc_pbot, forc_rho, & - forc_lwrad, forc_rain, forc_snow, glcmec_downscale_longwave) + forc_lwrad, forc_rain, forc_snow, glcmec_downscale_longwave, longwave_downscaling_limit) ! Initializes this%atm2lnd_inst and sets gridcell-level, non-downscaled forcing ! fields based on inputs. Excluded inputs are given a default value class(TestDownscaleForcings), intent(inout) :: this @@ -83,6 +88,9 @@ contains ! If not provided, assumed to be true logical, intent(in), optional :: glcmec_downscale_longwave + ! If not provided, assumed to be longwave_downscaling_limit_default + real(r8), intent(in), optional :: longwave_downscaling_limit + real(r8), parameter :: forc_t_default = 301._r8 real(r8), parameter :: forc_th_default = 302._r8 real(r8), parameter :: forc_q_default = 0.01_r8 @@ -92,9 +100,12 @@ contains real(r8), parameter :: forc_rain_default = 21._r8 real(r8), parameter :: forc_snow_default = 22._r8 + real(r8), parameter :: longwave_downscaling_limit_default = 1._r8 + real(r8), parameter :: forc_hgt = 2._r8 logical :: l_glcmec_downscale_longwave + real(r8) :: l_longwave_downscaling_limit type(atm2lnd_params_type) :: atm2lnd_params ! ------------------------------------------------------------------------ @@ -105,9 +116,18 @@ contains l_glcmec_downscale_longwave = .true. end if + if (present(longwave_downscaling_limit)) then + l_longwave_downscaling_limit = longwave_downscaling_limit + else + l_longwave_downscaling_limit = longwave_downscaling_limit_default + end if + atm2lnd_params = atm2lnd_params_type( & repartition_rain_snow = .false., & - glcmec_downscale_longwave = l_glcmec_downscale_longwave) + glcmec_downscale_longwave = l_glcmec_downscale_longwave, & + lapse_rate = lapse_rate, & + lapse_rate_longwave = lapse_rate_longwave, & + longwave_downscaling_limit = l_longwave_downscaling_limit) call this%atm2lnd_inst%InitForTesting(bounds, atm2lnd_params) this%atm2lnd_inst%forc_topo_grc(bounds%begg:bounds%endg) = forc_topo(:) @@ -171,6 +191,17 @@ contains this%topo_inst%topo_col(bounds%begc:bounds%endc) = topo_col(:) end subroutine create_topo + subroutine call_downscale_forcings(this) + ! Wraps the call to downscale_forcings + ! + ! Modifies this%atm2lnd_inst and this%eflx_sh_precip_conversion + class(TestDownscaleForcings), intent(inout) :: this + + this%eflx_sh_precip_conversion = col_array() + call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & + this%eflx_sh_precip_conversion) + end subroutine call_downscale_forcings + ! ======================================================================== ! Begin actual tests ! ======================================================================== @@ -182,7 +213,6 @@ contains @Test subroutine topo_greaterThan_atmTopo_gives_colder_forc_t(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: atm_topo = 17._r8 real(r8), parameter :: forc_t = 301._r8 @@ -192,11 +222,9 @@ contains forc_topo = [atm_topo], & forc_t = [forc_t]) call this%create_topo(topo_col = [atm_topo + 10._r8]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify @assertGreaterThan(forc_t, this%atm2lnd_inst%forc_t_downscaled_col(begc)) @@ -209,25 +237,19 @@ contains @Test subroutine twoTopos_at_atmTopo_give_nearlyIdentical_forc_lwrad(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: topo = 17._r8 real(r8), parameter :: forc_lwrad = 101._r8 ! Setup - call unittest_subgrid_setup_start() - call unittest_add_gridcell() - call create_landunit_ncols(ltype = 1, lweight = 1._r8, & + call setup_landunit_ncols(ltype = 1, & ctypes = [0, 1], cweights = [0.7_r8, 0.3_r8]) - call unittest_subgrid_setup_end() call this%create_atm2lnd( & forc_topo = [topo], & forc_lwrad = [forc_lwrad]) call this%create_topo(topo_col = [topo, topo]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify associate(lwrad_col => this%atm2lnd_inst%forc_lwrad_downscaled_col) @@ -236,6 +258,74 @@ contains end associate end subroutine twoTopos_at_atmTopo_give_nearlyIdentical_forc_lwrad + @Test + subroutine lwrad_adjusted_correctly(this) + class(TestDownscaleForcings), intent(inout) :: this + real(r8), parameter :: atm_topo = 17._r8 + real(r8), parameter :: topo_diff = 10._r8 + real(r8), parameter :: forc_lwrad = 101._r8 + real(r8) :: expected(3) + + ! Setup + ! The columns of interest are the first and third. However, note that they have 0 + ! weight, in order to avoid needing to take normalization into account. We construct + ! the grid so that the normalization factor will be 1 by putting the 100% area column + ! at the atmosphere's topographic height. + call setup_landunit_ncols(ltype = 1, & + ctypes = [0, 1, 2], cweights = [0.0_r8, 1.0_r8, 0.0_r8]) + call this%create_atm2lnd( & + forc_topo = [atm_topo], & + forc_lwrad = [forc_lwrad]) + call this%create_topo(topo_col = [atm_topo - topo_diff, atm_topo, atm_topo + topo_diff]) + + ! Exercise + call this%call_downscale_forcings() + + ! Verify + associate(lwrad_col => this%atm2lnd_inst%forc_lwrad_downscaled_col) + expected(1) = forc_lwrad + lapse_rate_longwave * topo_diff + expected(2) = forc_lwrad + expected(3) = forc_lwrad - lapse_rate_longwave * topo_diff + @assertEqual(expected, lwrad_col(bounds%begc:bounds%endc), tolerance=tol) + end associate + end subroutine lwrad_adjusted_correctly + + @Test + subroutine lwrad_downscaling_limited(this) + ! Make sure that the downscaling of lwrad obeys the specified bounds + class(TestDownscaleForcings), intent(inout) :: this + real(r8), parameter :: atm_topo = 5000._r8 + real(r8), parameter :: forc_lwrad = 100._r8 + ! Use a very big topo_diff in order to trigger the limit: + real(r8), parameter :: topo_diff = 4000._r8 + real(r8), parameter :: longwave_downscaling_limit = 0.4_r8 + real(r8) :: expected(3) + + ! Setup + ! The columns of interest are the first and third. However, note that they have 0 + ! weight, in order to avoid needing to take normalization into account. We construct + ! the grid so that the normalization factor will be 1 by putting the 100% area column + ! at the atmosphere's topographic height. + call setup_landunit_ncols(ltype = 1, & + ctypes = [0, 1, 2], cweights = [0.0_r8, 1.0_r8, 0.0_r8]) + call this%create_atm2lnd( & + forc_topo = [atm_topo], & + forc_lwrad = [forc_lwrad], & + longwave_downscaling_limit = longwave_downscaling_limit) + call this%create_topo(topo_col = [atm_topo - topo_diff, atm_topo, atm_topo + topo_diff]) + + ! Exercise + call this%call_downscale_forcings() + + ! Verify + associate(lwrad_col => this%atm2lnd_inst%forc_lwrad_downscaled_col) + expected(1) = forc_lwrad * (1._r8 + longwave_downscaling_limit) + expected(2) = forc_lwrad + expected(3) = forc_lwrad * (1._r8 - longwave_downscaling_limit) + @assertEqual(expected, lwrad_col(bounds%begc:bounds%endc), tolerance=tol) + end associate + end subroutine lwrad_downscaling_limited + ! ------------------------------------------------------------------------ ! Tests with topo at atmosphere topo: downscaled forcing should be identical to ! atmospheric forcing @@ -244,7 +334,6 @@ contains @Test subroutine topo_at_atmTopo_gives_identical_forc_t(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: topo = 17._r8 real(r8), parameter :: forc_t = 301._r8 @@ -254,11 +343,9 @@ contains forc_topo = [topo], & forc_t = [forc_t]) call this%create_topo(topo_col = [topo]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify @assertEqual(forc_t, this%atm2lnd_inst%forc_t_downscaled_col(begc)) @@ -268,7 +355,6 @@ contains @Test subroutine topo_at_atmTopo_gives_identical_forc_th(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: topo = 17._r8 real(r8), parameter :: forc_th = 302._r8 @@ -278,11 +364,9 @@ contains forc_topo = [topo], & forc_th = [forc_th]) call this%create_topo(topo_col = [topo]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify @assertEqual(forc_th, this%atm2lnd_inst%forc_th_downscaled_col(begc)) @@ -292,7 +376,6 @@ contains @Test subroutine topo_at_atmTopo_gives_identical_forc_q(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: topo = 17._r8 real(r8), parameter :: forc_q = 0.01_r8 @@ -302,11 +385,9 @@ contains forc_topo = [topo], & forc_q = [forc_q]) call this%create_topo(topo_col = [topo]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify @assertEqual(forc_q, this%atm2lnd_inst%forc_q_downscaled_col(begc)) @@ -316,7 +397,6 @@ contains @Test subroutine topo_at_atmTopo_gives_identical_forc_pbot(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: topo = 17._r8 real(r8), parameter :: forc_pbot = 100000._r8 @@ -326,11 +406,9 @@ contains forc_topo = [topo], & forc_pbot = [forc_pbot]) call this%create_topo(topo_col = [topo]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify @assertEqual(forc_pbot, this%atm2lnd_inst%forc_pbot_downscaled_col(begc)) @@ -340,7 +418,6 @@ contains @Test subroutine topo_at_atmTopo_gives_identical_forc_rho(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: topo = 17._r8 real(r8), parameter :: forc_rho = 1.1_r8 @@ -350,11 +427,9 @@ contains forc_topo = [topo], & forc_rho = [forc_rho]) call this%create_topo(topo_col = [topo]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify @assertEqual(forc_rho, this%atm2lnd_inst%forc_rho_downscaled_col(begc)) @@ -364,7 +439,6 @@ contains @Test subroutine topo_at_atmTopo_gives_identical_forc_lwrad(this) class(TestDownscaleForcings), intent(inout) :: this - real(r8), allocatable :: eflx_sh_precip_conversion(:) real(r8), parameter :: topo = 17._r8 real(r8), parameter :: forc_lwrad = 101._r8 @@ -374,11 +448,9 @@ contains forc_topo = [topo], & forc_lwrad = [forc_lwrad]) call this%create_topo(topo_col = [topo]) - eflx_sh_precip_conversion = col_array() ! Exercise - call downscale_forcings(bounds, this%topo_inst, this%atm2lnd_inst, & - eflx_sh_precip_conversion) + call this%call_downscale_forcings() ! Verify @assertEqual(forc_lwrad, this%atm2lnd_inst%forc_lwrad_downscaled_col(begc)) diff --git a/src/main/test/atm2lnd_test/test_partition_precip.pf b/src/main/test/atm2lnd_test/test_partition_precip.pf index 4cf6b045c2..4e996988d0 100644 --- a/src/main/test/atm2lnd_test/test_partition_precip.pf +++ b/src/main/test/atm2lnd_test/test_partition_precip.pf @@ -70,6 +70,7 @@ contains atm2lnd_params = atm2lnd_params_type( & repartition_rain_snow = l_repartition_rain_snow, & glcmec_downscale_longwave = .false., & + lapse_rate = 0.01_r8, & ! arbitrary (this is unused for these tests) precip_repartition_glc_all_snow_t = precip_repartition_glc_all_snow_t, & precip_repartition_glc_all_rain_t = precip_repartition_glc_all_rain_t, & precip_repartition_nonglc_all_snow_t = precip_repartition_nonglc_all_snow_t, & diff --git a/src/unit_test_shr/unittestSimpleSubgridSetupsMod.F90 b/src/unit_test_shr/unittestSimpleSubgridSetupsMod.F90 index 5f3095e872..681357df7b 100644 --- a/src/unit_test_shr/unittestSimpleSubgridSetupsMod.F90 +++ b/src/unit_test_shr/unittestSimpleSubgridSetupsMod.F90 @@ -24,6 +24,10 @@ module unittestSimpleSubgridSetupsMod ! Create a grid that has a single gridcell with N vegetated patches public :: setup_n_veg_patches + ! Create a grid that has a single gridcell with one landunit of a given type with N + ! columns, each with a single patch of type noveg + public :: setup_landunit_ncols + ! Create a grid that has N grid cells, each with a single vegetated patch public :: setup_ncells_single_veg_patch @@ -106,6 +110,33 @@ subroutine setup_n_veg_patches(pwtcol, pft_types) end subroutine setup_n_veg_patches + !----------------------------------------------------------------------- + subroutine setup_landunit_ncols(ltype, ctypes, cweights) + ! + ! !DESCRIPTION: + ! Create a grid that has a single gridcell with one landunit of a given type with N + ! columns, each with a single patch of type noveg + ! + ! !USES: + ! + ! !ARGUMENTS: + integer, intent(in) :: ltype ! landunit type + integer, intent(in) :: ctypes(:) ! array of column types; one column is created for each element in the array + real(r8), intent(in) :: cweights(:) ! array of column weights on the landunit + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'setup_landunit_ncols' + !----------------------------------------------------------------------- + + call unittest_subgrid_setup_start() + call unittest_add_gridcell() + call create_landunit_ncols(ltype = ltype, lweight = 1._r8, & + ctypes = ctypes, cweights = cweights) + call unittest_subgrid_setup_end() + + end subroutine setup_landunit_ncols + !----------------------------------------------------------------------- subroutine setup_ncells_single_veg_patch(ncells, pft_type) diff --git a/test/tools/TSMscript_tools.sh b/test/tools/TSMscript_tools.sh index 5439d8c020..5a5ef2d5c1 100755 --- a/test/tools/TSMscript_tools.sh +++ b/test/tools/TSMscript_tools.sh @@ -51,7 +51,7 @@ cfgfile=${3#*^} if [[ "$1" == "PTCLM" ]]; then echo "TSMscript_tools.sh: calling TCBscripttools.sh to prepare executables for $1" - ${CLM_SCRIPTDIR}/TCBscripttools.sh $1 $2 $cfgfile + ${CLM_SCRIPTDIR}/TCBscripttools.sh $1 $cfgfile rc=$? if [ $rc -ne 0 ]; then echo "TSMscript_tools.sh: error from TCBscripttools.sh= $rc" diff --git a/tools/SVN_EXTERNAL_DIRECTORIES b/tools/SVN_EXTERNAL_DIRECTORIES index 329bdad465..99a32434ab 100644 --- a/tools/SVN_EXTERNAL_DIRECTORIES +++ b/tools/SVN_EXTERNAL_DIRECTORIES @@ -1 +1 @@ -PTCLM https://svn-ccsm-models.cgd.ucar.edu/PTCLM/trunk_tags/PTCLM2_160818 +PTCLM https://svn-ccsm-models.cgd.ucar.edu/PTCLM/trunk_tags/PTCLM2_170302 From fa7b4eccb514884aeba525173b6cec66b7c4e2da Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 14 Mar 2017 15:05:48 +0000 Subject: [PATCH 005/153] hillslope_hydrology_n05_clm4_5_14_r226 added hillslope factory modules --- bld/CLMBuildNamelist.pm | 17 +- .../namelist_defaults_clm4_5.xml | 4 + .../namelist_definition_clm4_5.xml | 5 + src/biogeophys/CanopyTemperatureMod.F90 | 1 + src/biogeophys/HillslopeHydrologyBaseMod.F90 | 200 ++++++++ .../HillslopeHydrologyFactoryMod.F90 | 126 +++++ .../HillslopeHydrologyIndependentMod.F90 | 404 ++++++++++++++++ .../HillslopeHydrologyTroch02Mod.F90 | 432 ++++++++++++++++++ src/biogeophys/SoilHydrologyMod.F90 | 2 +- src/main/ColumnType.F90 | 2 + src/main/clm_instMod.F90 | 14 +- src/main/initVerticalMod.F90 | 207 +-------- 12 files changed, 1205 insertions(+), 209 deletions(-) create mode 100644 src/biogeophys/HillslopeHydrologyBaseMod.F90 create mode 100644 src/biogeophys/HillslopeHydrologyFactoryMod.F90 create mode 100644 src/biogeophys/HillslopeHydrologyIndependentMod.F90 create mode 100644 src/biogeophys/HillslopeHydrologyTroch02Mod.F90 diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index e4757b0602..e5cdb258b2 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1703,6 +1703,11 @@ sub process_namelist_inline_logic { ############################################# setup_logic_soil_resis($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + ############################################# + # namelist group: hillslope_hydrology_inparm # + ############################################# + setup_logic_hillslope_hydrology($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + ############################################# # namelist group: canopyfluxes_inparm # ############################################# @@ -3481,6 +3486,16 @@ sub setup_logic_soil_resis { } #------------------------------------------------------------------------------- +sub setup_logic_hillslope_hydrology { + # + my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + + if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { + add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_geomorphology' ); + } +} +#------------------------------------------------------------------------------- + sub setup_logic_canopyfluxes { # my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; @@ -3623,7 +3638,7 @@ sub write_output_files { soilhydrology_inparm luna friction_velocity mineral_nitrogen_dynamics soilwater_movement_inparm rooting_profile_inparm soil_resis_inparm bgc_shared canopyfluxes_inparm - clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm + clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm hillslope_hydrology_inparm cnprecision_inparm clm_glacier_behavior crop irrigation_inparm); #@groups = qw(clm_inparm clm_canopyhydrology_inparm clm_soilhydrology_inparm diff --git a/bld/namelist_files/namelist_defaults_clm4_5.xml b/bld/namelist_files/namelist_defaults_clm4_5.xml index 5cdb89dd11..c221832b1e 100644 --- a/bld/namelist_files/namelist_defaults_clm4_5.xml +++ b/bld/namelist_files/namelist_defaults_clm4_5.xml @@ -123,6 +123,10 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 1 0 + +independent +independent + 1.d-2 0.0090932 diff --git a/bld/namelist_files/namelist_definition_clm4_5.xml b/bld/namelist_files/namelist_definition_clm4_5.xml index d93710b488..751b128675 100644 --- a/bld/namelist_files/namelist_definition_clm4_5.xml +++ b/bld/namelist_files/namelist_definition_clm4_5.xml @@ -176,6 +176,11 @@ Changes soil evaporative resistance method from Sakaguchi and Zeng formulation (1). + +Equation set used to derive hillslope geomorphology + + The method type to use for CNFire diff --git a/src/biogeophys/CanopyTemperatureMod.F90 b/src/biogeophys/CanopyTemperatureMod.F90 index 0440eec2af..b858e63184 100644 --- a/src/biogeophys/CanopyTemperatureMod.F90 +++ b/src/biogeophys/CanopyTemperatureMod.F90 @@ -453,6 +453,7 @@ subroutine CanopyTemperature(bounds, & forc_hgt_t_patch(p) = forc_hgt_t(g) + z0m(p) + displa(p) forc_hgt_q_patch(p) = forc_hgt_q(g) + z0m(p) + displa(p) end if + else if (lun%itype(l) == istwet .or. lun%itype(l) == istice & .or. lun%itype(l) == istice_mec) then forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(c) diff --git a/src/biogeophys/HillslopeHydrologyBaseMod.F90 b/src/biogeophys/HillslopeHydrologyBaseMod.F90 new file mode 100644 index 0000000000..0e2916eb58 --- /dev/null +++ b/src/biogeophys/HillslopeHydrologyBaseMod.F90 @@ -0,0 +1,200 @@ +module HillslopeHydrologyBaseMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Calculate geomorphological quantities for hillslope columns. + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc + use abortutils , only : endrun + use clm_varctl , only : iulog + use decompMod , only : bounds_type + + implicit none + private + save + + !----------------------------------------------------------------------- + + ! !PUBLIC TYPES: + type, abstract, public :: hillslope_geomorphology_type + private + ! variable declarations + + contains + ! procedure declarations + procedure (Init_interface) , deferred :: Init + procedure (hcol_width_interface) , deferred :: hcol_width + procedure (hcol_elevation_interface), deferred :: hcol_elevation + procedure (hcol_slope_interface) , deferred :: hcol_slope + procedure :: hcol_distance + procedure :: hcol_area + + end type hillslope_geomorphology_type + + !----------------------------------------------------------------------- + + abstract interface + + subroutine Init_interface(this,bounds,fsurdat) + ! + ! !DESCRIPTION: + ! Initialize hillslope geomorphology + ! + ! !USES: + + use decompMod, only : bounds_type + import hillslope_geomorphology_type + + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_type), intent(inout) :: this + type(bounds_type), intent(in) :: bounds + character(len=*) , intent(in) :: fsurdat ! surface data file name + end subroutine Init_interface + + function hcol_width_interface(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) + ! + ! !DESCRIPTION: + ! Returns width of hillslope column. + ! + ! !USES: + use shr_kind_mod , only : r8 => shr_kind_r8 + import hillslope_geomorphology_type + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_type) , intent(in) :: this + real(r8) :: width ! function result + real(r8), intent(in) :: x ! distance along hillslope + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + + end function hcol_width_interface + + !----------------------------------------------------------------------- + function hcol_slope_interface(this,xtop,xbottom,alpha, hill_length, hill_height) result(slope) + ! + ! !DESCRIPTION: + ! Returns mean along-hillslope slope of hillslope column + ! + ! !USES: + use shr_kind_mod , only : r8 => shr_kind_r8 + import hillslope_geomorphology_type + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_type) , intent(in) :: this + real(r8) :: slope ! function result + real(r8), intent(in) :: xtop ! distance to upper edge of column + real(r8), intent(in) :: xbottom ! distance to lower edge of column + real(r8), intent(in) :: alpha ! hillslope profile curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_height ! total hillslope height + end function hcol_slope_interface + + !----------------------------------------------------------------------- + + function hcol_elevation_interface(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) + ! + ! !DESCRIPTION: + ! Returns mean elevation of column (relative to hillslope bottom). + ! Area-weighted mean elevation is calculated by + ! numerically integrating using hcol_width function. ! + ! !USES: + use shr_kind_mod , only : r8 => shr_kind_r8 + import hillslope_geomorphology_type + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_type) , intent(in) :: this + real(r8) :: elev ! function result + real(r8), intent(in) :: xtop ! upper integration limit + real(r8), intent(in) :: xbottom ! lower integration limit + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + + end function hcol_elevation_interface + + end interface + +! PRIVATE + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +contains + + !----------------------------------------------------------------------- + function hcol_distance(this, c, ctop, cbottom, hill_length) result(x) + ! + ! !DESCRIPTION: + ! Returns distance from the bottom of the hillslope of the + ! column's node. Assumes hilltop to hillbottom column + ! ordering based on lun%coli, lun%colf (see initHillslopeMod). + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_type) , intent(in) :: this + real(r8) :: x ! function result + integer, intent(in) :: c ! current column + integer, intent(in) :: ctop ! hillslope top column + integer, intent(in) :: cbottom ! hillslope bottom column + real(r8), intent(in) :: hill_length ! total hillslope length + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'hcol_distance' + !----------------------------------------------------------------------- + + x = hill_length * (real(cbottom - c,r8) +0.5_r8) & + / real(cbottom - ctop + 1,r8) + + end function hcol_distance + + !----------------------------------------------------------------------- + function hcol_area(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(area) + ! + ! !DESCRIPTION: + ! Returns area of a hillslope column. Area is calculated by + ! numerically integrating using hcol_width function. + ! + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_type) , intent(in) :: this + real(r8) :: area ! function result + real(r8), intent(in) :: xtop ! upper integration limit + real(r8), intent(in) :: xbottom ! lower integration limit + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + integer :: n + integer, parameter :: ndiv = 100 + real(r8) :: x + real(r8) :: dx + character(len=*), parameter :: subname = 'hcol_area' + !----------------------------------------------------------------------- + ! surface area of column + dx = (xtop - xbottom)/real(ndiv) + + area = 0._r8 + do n = 0, ndiv-1 + x = xbottom + (n+0.5)*dx + area = area + dx * this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) + enddo + + end function hcol_area + +end module HillslopeHydrologyBaseMod diff --git a/src/biogeophys/HillslopeHydrologyFactoryMod.F90 b/src/biogeophys/HillslopeHydrologyFactoryMod.F90 new file mode 100644 index 0000000000..d396e49fa1 --- /dev/null +++ b/src/biogeophys/HillslopeHydrologyFactoryMod.F90 @@ -0,0 +1,126 @@ +module HillslopeHydrologyFactoryMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Calculate geomorphological quantities for hillslope columns. + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc + use abortutils , only : endrun + use clm_varctl , only : iulog, use_hillslope + use decompMod , only : bounds_type + implicit none + private + save + +! namelist variable specifying geomorphology defining equation set + character(len=256) :: hillslope_geomorphology + + !----------------------------------------------------------------------- + + ! !PUBLIC ROUTINES + public :: create_and_init_hillslope_geomorphology_type + + ! !PRIVATE ROUTINES + private :: hillslope_geomorphology_readNL + +contains + + function create_and_init_hillslope_geomorphology_type(bounds) result(hg) + ! + ! !DESCRIPTION: + ! Create and initialize an object of hillslope_geomorphology_type, + ! and return this object. The particular type is determined based on + ! the use_hillslope namelist parameter. + ! + ! !USES: + use controlMod , only : NLFilename + use clm_varctl , only : use_hillslope, fsurdat + use HillslopeHydrologyBaseMod , only : hillslope_geomorphology_type + use HillslopeHydrologyIndependentMod , only : hillslope_geomorphology_independent_type + use HillslopeHydrologyTroch02Mod , only : hillslope_geomorphology_troch02_type + + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_type), allocatable :: hg ! function result + type(bounds_type), intent(in) :: bounds + + !----------------------------------------------------------------- + + call hillslope_geomorphology_readNL(NLFilename) + + select case (trim(hillslope_geomorphology)) + case ('independent') + allocate(hg, source = hillslope_geomorphology_independent_type()) + case ('troch02') + allocate(hg, source = hillslope_geomorphology_troch02_type()) + + end select + + call hg%Init(bounds, fsurdat) + + end function create_and_init_hillslope_geomorphology_type + + !----------------------------------------------------------------------- + subroutine hillslope_geomorphology_readNL(NLFilename) + ! + !DESCRIPTIONS + ! Read the namelist for soil resistance method + ! + ! !USES: + use abortutils , only : endrun + use fileutils , only : getavu, relavu + use spmdMod , only : mpicom, masterproc + use shr_mpi_mod , only : shr_mpi_bcast + use clm_varctl , only : iulog + use clm_nlUtilsMod , only : find_nlgroup_name + + ! !ARGUMENTS: + !------------------------------------------------------------------------------ + implicit none + character(len=*), intent(IN) :: NLFilename ! Namelist filename + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + character(*), parameter :: subName = "('hillslope_geomorphology_readNL')" + + !----------------------------------------------------------------------- + +! MUST agree with name in namelist and read statement + namelist /hillslope_hydrology_inparm/ hillslope_geomorphology + + ! Default values for namelist + + hillslope_geomorphology = 'independent' + + ! Read soil_resis namelist + if (masterproc) then + nu_nml = getavu() + open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call find_nlgroup_name(nu_nml, 'hillslope_hydrology_inparm', status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=hillslope_hydrology_inparm,iostat=nml_error) + if (nml_error /= 0) then + call endrun(subname // ':: ERROR reading hillslope_hydrology namelist') + end if + else + call endrun(subname // ':: ERROR reading hillslope_hydrology namelist') + end if + close(nu_nml) + call relavu( nu_nml ) + + endif + + call shr_mpi_bcast(hillslope_geomorphology, mpicom) + + if (masterproc) then + write(iulog,*) ' ' + write(iulog,*) 'hillslope hydrology settings:' + write(iulog,*) ' hillslope_geomorphology = ',hillslope_geomorphology + endif + + end subroutine hillslope_geomorphology_readNL + +end module HillslopeHydrologyFactoryMod diff --git a/src/biogeophys/HillslopeHydrologyIndependentMod.F90 b/src/biogeophys/HillslopeHydrologyIndependentMod.F90 new file mode 100644 index 0000000000..cddc0a2911 --- /dev/null +++ b/src/biogeophys/HillslopeHydrologyIndependentMod.F90 @@ -0,0 +1,404 @@ +module HillslopeHydrologyIndependentMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Calculate geomorphological quantities for hillslope columns + ! assuming independent profile and plan shapes. + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use HillslopeHydrologyBaseMod, only : hillslope_geomorphology_type + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc + use abortutils , only : endrun + use clm_varctl , only : iulog + use decompMod , only : bounds_type + + implicit none + private + save + + ! PRIVATE + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + ! !PUBLIC TYPES: + + type, extends(hillslope_geomorphology_type), public :: & + hillslope_geomorphology_independent_type + private + + ! variable declarations + + contains + + procedure :: Init + procedure :: hcol_width + procedure :: hcol_elevation + procedure :: hcol_slope + + end type hillslope_geomorphology_independent_type + + !----------------------------------------------------------------------- + interface hillslope_geomorphology_independent_type + + end interface hillslope_geomorphology_independent_type + + + !----------------------------------------------------------------------- + +contains + + !----------------------------------------------------------------------- + function hcol_width(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) + ! + ! !DESCRIPTION: + ! Returns width of hillslope column. + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_independent_type) , intent(in) :: this + real(r8) :: width ! function result + real(r8), intent(in) :: x ! distance along hillslope + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + real(r8) :: eps = 1.e-6_r8 + real(r8) :: x0,y0,yl ! integration limits + real(r8) :: slope, intercept + character(len=*), parameter :: subname = 'hcol_width' + !----------------------------------------------------------------------- + + ! width varies linearly with distance + + ! divergent +! y0 = hill_width/2._r8 +! yl = 0.25_r8 * yl + ! convergent + yl = hill_width/2._r8 + y0 = 0.1_r8 * yl +! y0 = 1.0_r8 * yl + + slope = (yl - y0)/(hill_length) + intercept = y0 + width = slope*x + intercept + + ! hillslope width is twice integral [0:x] + width = 2._r8 * width + + end function hcol_width + + !----------------------------------------------------------------------- + function hcol_elevation(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) + ! + ! !DESCRIPTION: + ! Returns mean elevation of column (relative to hillslope bottom). + ! Area-weighted mean elevation is calculated by + ! numerically integrating using hcol_width function. ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_independent_type) , intent(in) :: this + real(r8) :: elev ! function result + real(r8), intent(in) :: xtop ! upper integration limit + real(r8), intent(in) :: xbottom ! lower integration limit + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + integer :: n + integer, parameter :: ndiv = 100 + real(r8) :: x, y + real(r8) :: dx + real(r8) :: dA + real(r8) :: area + character(len=*), parameter :: subname = 'hcol_elevation' + !----------------------------------------------------------------------- + ! mean elevation of column relative to hillslope bottom + ! elevation is considered 1-d + + dx = (xtop - xbottom)/real(ndiv) + + elev = 0._r8 + area = 0._r8 + do n = 0, ndiv-1 + x = xbottom + (n+0.5)*dx + y = this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) + dA = dx * y + area = area + dA + elev = elev + dx * y * hill_height*(x/hill_length)**alpha + enddo + elev = elev / area + + end function hcol_elevation + + !----------------------------------------------------------------------- + function hcol_slope(this,xtop,xbottom,alpha, hill_length, hill_height) result(slope) + ! + ! !DESCRIPTION: + ! Returns mean along-hillslope slope of hillslope column + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_independent_type) , intent(in) :: this + real(r8) :: slope ! function result + real(r8), intent(in) :: xtop ! distance to upper edge of column + real(r8), intent(in) :: xbottom ! distance to lower edge of column + real(r8), intent(in) :: alpha ! hillslope profile curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'hcol_slope' + !----------------------------------------------------------------------- + + ! mean along-hill slope of column + slope = hill_height & + * ((xtop/hill_length)**alpha & + - (xbottom/hill_length)**alpha) & + / (xtop - xbottom) + + end function hcol_slope + + !----------------------------------------------------------------------- + + subroutine Init(this,bounds,fsurdat) + ! + ! !DESCRIPTION: + ! Initialize hillslope geomorphology + ! + ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use clm_varctl , only : nhillslope + use clm_varcon , only : zmin_bedrock, zisoi + use clm_varpar , only : nlevsoi + use spmdMod , only : masterproc + use fileutils , only : getfil + use clm_varcon , only : spval, ispval, grlnd + use landunit_varcon , only : istsoil + use ncdio_pio + + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_independent_type) , intent(inout) :: this + type(bounds_type), intent(in) :: bounds + character(len=*) , intent(in) :: fsurdat ! surface data file name + real(r8), pointer :: ihillslope_in(:,:) ! read in - integer + real(r8), pointer :: fhillslope_in(:,:) ! read in - float + integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope + real(r8), allocatable :: hill_alpha(:,:) ! hillslope 'alpha' parameter + real(r8), allocatable :: hill_beta(:,:) ! hillslope 'beta' parameter + real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] + real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] + real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] + + type(file_desc_t) :: ncid ! netcdf id + logical :: readvar ! check whether variable on file + character(len=256) :: locfn ! local filename + integer :: ierr ! error code + integer :: c, l, g, j, nh ! indices + + real(r8) :: hillslope_area ! total area of hillslope + real(r8) :: column_length ! length of column [m] + real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope + real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope + integer :: ctop, cbottom ! hillslope top and bottom column indices + + character(len=*), parameter :: subname = 'Init' + + !----------------------------------------------------------------------- + + ! Open surface dataset to read in data below + + call getfil (fsurdat, locfn, 0) + call ncd_pio_openfile (ncid, locfn, 0) + + allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & + hill_alpha(bounds%begl:bounds%endl,nhillslope), & + hill_beta(bounds%begl:bounds%endl,nhillslope), & + hill_length(bounds%begl:bounds%endl,nhillslope), & + hill_width(bounds%begl:bounds%endl,nhillslope), & + hill_height(bounds%begl:bounds%endl,nhillslope), & + stat=ierr) + + allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) + + call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + pct_hillslope(l,:) = ihillslope_in(g,:) + enddo + deallocate(ihillslope_in) + + allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) + call ncd_io(ncid=ncid, varname='h_alpha', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_alpha not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_alpha(l,:) = fhillslope_in(g,:) + enddo +!scs +hill_alpha = 4 + + call ncd_io(ncid=ncid, varname='h_beta', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_beta not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_beta(l,:) = fhillslope_in(g,:) + enddo + call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_length(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_width(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_height(l,:) = fhillslope_in(g,:) + enddo + deallocate(fhillslope_in) + + ! Set hillslope hydrology column level variables + ! This needs to match how columns set up in subgridMod + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + if(lun%itype(l) == istsoil) then + ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost + + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + ctop = lun%coli(l)+(nh-1)*lun%ncolumns(l)/nhillslope + cbottom = lun%coli(l)+(nh)*lun%ncolumns(l)/nhillslope - 1 + + ! distance of lower edge of column from hillslope bottom + col%hill_distance(c) = this%hcol_distance(c, & + ctop, cbottom, hill_length(l,nh)) + ! if (masterproc) write(iulog,*) 'hd: ',c,col%hill_distance(c) + + !distance of lower edge of column from hillslope bottom + column_length = hill_length(l,nh)/(lun%ncolumns(l)/nhillslope) + le_distance = col%hill_distance(c) - 0.5_r8*column_length + ue_distance = col%hill_distance(c) + 0.5_r8*column_length + + ! width of lower edge of column from hillslope bottom + col%hill_width(c) = this%hcol_width(le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'hw: ',c,col%hill_width(c) + + col%hill_area(c) = this%hcol_area(ue_distance, le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'ha: ',c,col%hill_area(c) + + ! mean elevation of column relative to mean gridcell elevation + col%hill_elev(c) = this%hcol_elevation(ue_distance, le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'he: ',c,col%hill_elev(c) + + ! mean along-hill slope of column + col%hill_slope(c) = this%hcol_slope(ue_distance, le_distance, & + hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'hs: ',c,col%hill_slope(c) + + enddo + + ! Now that column areas are determined, column weights can be recalculated + hillslope_area = 0._r8 + ! area weighted by pct_hillslope + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + hillslope_area = hillslope_area & + + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + enddo + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + col%wtlunit(c) = col%hill_area(c) & + * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + enddo + + ! Set column bedrock index + !thin soil for non-riparian columns, thick for riparian + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) /= ispval) then + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + end if + enddo + else + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then + col%nbedrock(c) = j + end if + end if + enddo + endif + end do + + endif ! end of istsoil + enddo ! end of loop over landunits + + deallocate(pct_hillslope,hill_alpha,hill_beta,hill_length, & + hill_width,hill_height) + + call ncd_pio_closefile(ncid) + + end subroutine Init + +end module HillslopeHydrologyIndependentMod diff --git a/src/biogeophys/HillslopeHydrologyTroch02Mod.F90 b/src/biogeophys/HillslopeHydrologyTroch02Mod.F90 new file mode 100644 index 0000000000..21dcce9c2d --- /dev/null +++ b/src/biogeophys/HillslopeHydrologyTroch02Mod.F90 @@ -0,0 +1,432 @@ +module HillslopeHydrologyTroch02Mod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Calculate geomorphological quantities for hillslope columns + ! assuming Troch et al., AWR, 2002 profile and plan shapes. + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use HillslopeHydrologyBaseMod, only : hillslope_geomorphology_type + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc + use abortutils , only : endrun + use clm_varctl , only : iulog + use decompMod , only : bounds_type + + implicit none + private + save + + ! PRIVATE + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + ! !PUBLIC TYPES: + + type, extends(hillslope_geomorphology_type), public :: & + hillslope_geomorphology_troch02_type + private + + ! variable declarations + + contains + + procedure :: Init + procedure :: hcol_width + procedure :: hcol_elevation + procedure :: hcol_slope + + end type hillslope_geomorphology_troch02_type + + !----------------------------------------------------------------------- + interface hillslope_geomorphology_troch02_type + + end interface hillslope_geomorphology_troch02_type + + + !----------------------------------------------------------------------- + +contains + + !----------------------------------------------------------------------- + function hcol_width(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) + ! + ! !DESCRIPTION: + ! Returns width of hillslope column. + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_troch02_type) , intent(in) :: this + real(r8) :: width ! function result + real(r8), intent(in) :: x ! distance along hillslope + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + real(r8) :: eps = 1.e-6_r8 + real(r8) :: x0,y0,yl ! integration limits + character(len=*), parameter :: subname = 'hcol_width' + !----------------------------------------------------------------------- + + ! width function has special case for n = 2 + ! in this implementation, integration limits depend on sign of beta + if (abs(alpha - 2._r8) < eps) then + + ! function blows up for x0=0; integration limits set by trial and error + if(beta < 0._r8) then + y0 = hill_width/2._r8 + yl = 0.1_r8 + x0=hill_length *(yl/y0)**(-hill_height/(beta*hill_length**2)) + else + x0 = 0.2_r8 + y0 = (hill_width/2._r8)& + *(x0/hill_length)**(beta*hill_length**2/hill_height) + endif + + ! compiler does not like log(zero) + if (x == 0._r8) then + if (beta < 0._r8) then + width = hill_width/2._r8 + else + width = eps + endif + else + width = y0*(x/x0)**(beta*hill_length**2/hill_height) + endif + else + ! alpha /= 2 case, x0 equals zero + y0 = hill_width/2._r8 + if(beta > 0._r8) then + y0 = y0 * exp(-(2._r8*beta*hill_length**2) & + / (hill_height*(2._r8 - alpha)*alpha)) + endif + ! compiler does not like zero to a negative power. + if (x == 0._r8) then + width = y0 + else + width = y0*exp((((2._r8*beta*hill_length**2) & + / (hill_height*(2._r8 - alpha)*alpha)) & + * (x/hill_length)**(2._r8-alpha))) + endif + endif + ! hillslope width is twice integral [0:x] + width = 2._r8 * width + + end function hcol_width + + !----------------------------------------------------------------------- + + function hcol_elevation(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) + ! + ! !DESCRIPTION: + ! Returns mean elevation of column (relative to hillslope bottom). + ! Area-weighted mean elevation is calculated by + ! numerically integrating using hcol_width function. ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_troch02_type) , intent(in) :: this + real(r8) :: elev ! function result + real(r8), intent(in) :: xtop ! upper integration limit + real(r8), intent(in) :: xbottom ! lower integration limit + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + integer :: n + integer, parameter :: ndiv = 100 + real(r8) :: x, y + real(r8) :: dx + real(r8) :: dA + real(r8) :: area + character(len=*), parameter :: subname = 'hcol_elevation' + !----------------------------------------------------------------------- + ! mean elevation of column relative to hillslope bottom + ! elevation is first integrated analytically in across-slope direction + ! then summed in along-slope direction + + dx = (xtop - xbottom)/real(ndiv) + + elev = 0._r8 + area = 0._r8 + do n = 0, ndiv-1 + x = xbottom + (n+0.5)*dx + y = this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) + dA = dx * y + area = area + dA + elev = elev + dx * (hill_height*y*(x/hill_length)**alpha & + + beta*y**3/12._r8) + enddo + elev = elev / area + + end function hcol_elevation + + !----------------------------------------------------------------------- + + function hcol_slope(this, xtop,xbottom,alpha, hill_length, hill_height) result(slope) + ! + ! !DESCRIPTION: + ! Returns mean along-hillslope slope of hillslope column + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_troch02_type) , intent(in) :: this + real(r8) :: slope ! function result + real(r8), intent(in) :: xtop ! distance to upper edge of column + real(r8), intent(in) :: xbottom ! distance to lower edge of column + real(r8), intent(in) :: alpha ! hillslope profile curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'hcol_slope' + !----------------------------------------------------------------------- + + ! mean along-hill slope of column + slope = hill_height & + * ((xtop/hill_length)**alpha & + - (xbottom/hill_length)**alpha) & + / (xtop - xbottom) + + end function hcol_slope + + !----------------------------------------------------------------------- + + subroutine Init(this,bounds,fsurdat) + ! + ! !DESCRIPTION: + ! Initialize hillslope geomorphology + ! + ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use clm_varctl , only : nhillslope + use clm_varcon , only : zmin_bedrock, zisoi + use clm_varpar , only : nlevsoi + use spmdMod , only : masterproc + use fileutils , only : getfil + use clm_varcon , only : spval, ispval, grlnd + use landunit_varcon , only : istsoil + use ncdio_pio + + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_troch02_type) , intent(inout) :: this + type(bounds_type), intent(in) :: bounds + character(len=*) , intent(in) :: fsurdat ! surface data file name + real(r8), pointer :: ihillslope_in(:,:) ! read in - integer + real(r8), pointer :: fhillslope_in(:,:) ! read in - float + integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope + real(r8), allocatable :: hill_alpha(:,:) ! hillslope 'alpha' parameter + real(r8), allocatable :: hill_beta(:,:) ! hillslope 'beta' parameter + real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] + real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] + real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] + + type(file_desc_t) :: ncid ! netcdf id + logical :: readvar ! check whether variable on file + character(len=256) :: locfn ! local filename + integer :: ierr ! error code + integer :: c, l, g, j, nh ! indices + + real(r8) :: hillslope_area ! total area of hillslope + real(r8) :: column_length ! length of column [m] + real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope + real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope + integer :: ctop, cbottom ! hillslope top and bottom column indices + + character(len=*), parameter :: subname = 'Init' + + !----------------------------------------------------------------------- + + ! Open surface dataset to read in data below + + call getfil (fsurdat, locfn, 0) + call ncd_pio_openfile (ncid, locfn, 0) + + allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & + hill_alpha(bounds%begl:bounds%endl,nhillslope), & + hill_beta(bounds%begl:bounds%endl,nhillslope), & + hill_length(bounds%begl:bounds%endl,nhillslope), & + hill_width(bounds%begl:bounds%endl,nhillslope), & + hill_height(bounds%begl:bounds%endl,nhillslope), & + stat=ierr) + + allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) + + call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + pct_hillslope(l,:) = ihillslope_in(g,:) + enddo + deallocate(ihillslope_in) + + allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) + call ncd_io(ncid=ncid, varname='h_alpha', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_alpha not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_alpha(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_beta', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_beta not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_beta(l,:) = fhillslope_in(g,:) + enddo + call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_length(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_width(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_height(l,:) = fhillslope_in(g,:) + enddo + deallocate(fhillslope_in) + + ! Set hillslope hydrology column level variables + ! This needs to match how columns set up in subgridMod + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + if(lun%itype(l) == istsoil) then + ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost + + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + ctop = lun%coli(l)+(nh-1)*lun%ncolumns(l)/nhillslope + cbottom = lun%coli(l)+(nh)*lun%ncolumns(l)/nhillslope - 1 + + ! distance of lower edge of column from hillslope bottom + col%hill_distance(c) = this%hcol_distance(c, & + ctop, cbottom, hill_length(l,nh)) + ! if (masterproc) write(iulog,*) 'hd: ',c,col%hill_distance(c) + + !distance of lower edge of column from hillslope bottom + column_length = hill_length(l,nh)/(lun%ncolumns(l)/nhillslope) + le_distance = col%hill_distance(c) - 0.5_r8*column_length + ue_distance = col%hill_distance(c) + 0.5_r8*column_length + + ! width of lower edge of column from hillslope bottom + col%hill_width(c) = this%hcol_width(le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'hw: ',c,col%hill_width(c) + + col%hill_area(c) = this%hcol_area(ue_distance, le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'ha: ',c,col%hill_area(c) + + ! mean elevation of column relative to mean gridcell elevation + col%hill_elev(c) = this%hcol_elevation(ue_distance, le_distance, & + hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & + hill_width(l,nh),hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'he: ',c,col%hill_elev(c) + + ! mean along-hill slope of column + col%hill_slope(c) = this%hcol_slope(ue_distance, le_distance, & + hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) + ! if (masterproc) write(iulog,*) 'hs: ',c,col%hill_slope(c) + + enddo + + ! Now that column areas are determined, column weights can be recalculated + hillslope_area = 0._r8 + ! area weighted by pct_hillslope + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + hillslope_area = hillslope_area & + + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + enddo + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + col%wtlunit(c) = col%hill_area(c) & + * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + enddo + + ! Set column bedrock index + !thin soil for non-riparian columns, thick for riparian + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) /= ispval) then + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + end if + enddo + else + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then + col%nbedrock(c) = j + end if + end if + enddo + endif + end do + + endif ! end of istsoil + enddo ! end of loop over landunits + + deallocate(pct_hillslope,hill_alpha,hill_beta,hill_length, & + hill_width,hill_height) + + call ncd_pio_closefile(ncid) + + end subroutine Init + +end module HillslopeHydrologyTroch02Mod diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 651fa99ea1..4512e1aa4b 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2343,7 +2343,7 @@ subroutine LateralFlowHillslope(bounds, & real(r8) :: transmis real(r8) :: dgrad real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent - real(r8), parameter :: k_anisotropic = 50._r8 + real(r8), parameter :: k_anisotropic = 20._r8 real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) integer :: c0, nstep diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index de3f2897a9..0d568427be 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -71,6 +71,8 @@ module ColumnType real(r8), pointer :: hill_area (:) ! mean surface area real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column real(r8), pointer :: hill_distance (:) ! along-hill distance of column from bottom of hillslope +! for init_interp, add information on relative position +! real(r8), pointer :: relative_position (:) ! relative position of column along hillslope ! levgrnd_class gives the class in which each layer falls. This is relevant for ! columns where there are 2 or more fundamentally different layer types. For diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index a13ba39d91..26d72b3dda 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -8,7 +8,8 @@ module clm_instMod use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type use clm_varpar , only : ndecomp_pools, nlevdecomp_full - use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_ed, use_voc + use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_ed, use_voc, use_hillslope + use clm_varctl , only : use_century_decomp, use_crop use clm_varcon , only : bdsno, c13ratio, c14ratio use landunit_varcon , only : istice, istice_mec, istsoil @@ -73,6 +74,7 @@ module clm_instMod use ColumnType , only : col use PatchType , only : patch use CLMFatesInterfaceMod , only : hlm_fates_interface_type + use HillslopeHydrologyBaseMod , only : hillslope_geomorphology_type use SoilWaterRetentionCurveMod , only : soil_water_retention_curve_type use NutrientCompetitionMethodMod , only : nutrient_competition_method_type ! @@ -115,6 +117,7 @@ module clm_instMod type(lnd2glc_type) :: lnd2glc_inst type(glc_behavior_type) :: glc_behavior type(topo_type) :: topo_inst + class(hillslope_geomorphology_type), allocatable :: hillslope_inst class(soil_water_retention_curve_type) , allocatable :: soil_water_retention_curve ! CN vegetation types @@ -173,7 +176,8 @@ subroutine clm_instInit(bounds) ! ! !USES: use clm_varpar , only : nlevsno, numpft - use controlMod , only : nlfilename, fsurdat + use clm_varctl , only : fsurdat + use controlMod , only : nlfilename use domainMod , only : ldomain use SoilBiogeochemDecompCascadeBGCMod , only : init_decompcascade_bgc use SoilBiogeochemDecompCascadeCNMod , only : init_decompcascade_cn @@ -181,6 +185,7 @@ subroutine clm_instInit(bounds) use initVerticalMod , only : initVertical use accumulMod , only : print_accum_fields + use HillslopeHydrologyFactoryMod , only : create_and_init_hillslope_geomorphology_type use SoilWaterRetentionCurveFactoryMod , only : create_soil_water_retention_curve use decompMod , only : get_proc_bounds ! @@ -317,6 +322,11 @@ subroutine clm_instInit(bounds) call dust_inst%Init(bounds) + if(use_hillslope) then + allocate(hillslope_inst, & + source=create_and_init_hillslope_geomorphology_type(bounds)) + endif + ! Once namelist options are added to control the soil water retention curve method, ! we'll need to either pass the namelist file as an argument to this routine, or pass ! the namelist value itself (if the namelist is read elsewhere). diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index 4c65293c14..ce9a83f645 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -19,7 +19,6 @@ module initVerticalMod use clm_varctl , only : use_vancouver, use_mexicocity, use_vertsoilc, use_extralakelayers use clm_varctl , only : use_bedrock, soil_layerstruct use clm_varctl , only : use_ed - use clm_varctl , only : nhillslope use clm_varcon , only : zlak, dzlak, zsoi, dzsoi, zisoi, dzsoi_decomp, spval, ispval, grlnd use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, is_hydrologically_active use landunit_varcon , only : istdlak, istice_mec, istsoil @@ -110,8 +109,6 @@ end subroutine ReadNL !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof) use clm_varcon, only : zmin_bedrock, n_melt_glcmec - use clm_varctl, only : use_hillslope - use HillslopeHydrologyMod ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -134,8 +131,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof integer :: ier ! error status real(r8) :: scalez = 0.025_r8 ! Soil layer thickness discretization (m) real(r8) :: thick_equal = 0.2 - real(r8), pointer :: ihillslope_in(:,:) ! read in - integer - real(r8), pointer :: fhillslope_in(:,:) ! read in - float real(r8), pointer :: lakedepth_in(:) ! wall (layer node depth) real(r8), pointer :: zbedrock_in(:) ! read in - float real(r8), allocatable :: zurb_wall(:,:) ! wall (layer node depth) @@ -148,17 +143,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof integer :: begc, endc integer :: begl, endl integer :: jmin_bedrock - integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope - real(r8), allocatable :: hill_alpha(:,:) ! hillslope 'alpha' parameter - real(r8), allocatable :: hill_beta(:,:) ! hillslope 'beta' parameter - real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] - real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] - real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] - real(r8) :: hillslope_area ! total area of hillslope - real(r8) :: column_length ! length of column [m] - real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope - real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope - integer :: ctop, cbottom ! hillslope top and bottom column indices ! Possible values for levgrnd_class. The important thing is that, for a given column, ! layers that are fundamentally different (e.g., soil vs bedrock) have different ! values. This information is used in the vertical interpolation in init_interp. @@ -594,195 +578,6 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof deallocate(zbedrock_in) - !----------------------------------------------- - ! Specify hillslope hydrology characteristics - !----------------------------------------------- - if(use_hillslope) then - allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & - hill_alpha(bounds%begl:bounds%endl,nhillslope), & - hill_beta(bounds%begl:bounds%endl,nhillslope), & - hill_length(bounds%begl:bounds%endl,nhillslope), & - hill_width(bounds%begl:bounds%endl,nhillslope), & - hill_height(bounds%begl:bounds%endl,nhillslope), & - stat=ier) - - allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) - - call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - pct_hillslope(l,:) = ihillslope_in(g,:) - enddo - deallocate(ihillslope_in) - - allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) - call ncd_io(ncid=ncid, varname='h_alpha', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_alpha not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_alpha(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_beta', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_beta not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_beta(l,:) = fhillslope_in(g,:) - enddo - call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_length(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_width(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_height(l,:) = fhillslope_in(g,:) - enddo - deallocate(fhillslope_in) - - ! Set hillslope hydrology column level variables - ! This needs to match how columns set up in subgridMod - do l = begl, endl - g = lun%gridcell(l) - if(lun%itype(l) == istsoil) then - ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost - - if (masterproc .and. 1==2) then - write(iulog,*) 'hillslope parameters' - do nh=1,nhillslope - write(iulog,'(a12,i8,5f16.4)') 'a,b,l,w,h: ', nh, hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), hill_width(l,nh),hill_height(l,nh) - write(iulog,*) ' ' - enddo - endif - - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - ctop = lun%coli(l)+(nh-1)*lun%ncolumns(l)/nhillslope - cbottom = lun%coli(l)+(nh)*lun%ncolumns(l)/nhillslope - 1 - if (masterproc .and. 1==2) then - write(iulog,*) 'hillslope distance columns' - write(iulog,'(a12,3i8,5f16.4)') 'top,c,bot: ', ctop,c,cbottom - write(iulog,*) ' ' - endif - - ! distance of lower edge of column from hillslope bottom - col%hill_distance(c) = hcol_distance(c, & - ctop, cbottom, hill_length(l,nh)) - ! if (masterproc) write(iulog,*) 'hd: ',c,col%hill_distance(c) - - !distance of lower edge of column from hillslope bottom - column_length = hill_length(l,nh)/(lun%ncolumns(l)/nhillslope) - le_distance = col%hill_distance(c) - 0.5_r8*column_length - ue_distance = col%hill_distance(c) + 0.5_r8*column_length - - ! width of lower edge of column from hillslope bottom - col%hill_width(c) = hcol_width(le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'hw: ',c,col%hill_width(c) - - col%hill_area(c) = hcol_area(ue_distance, le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'ha: ',c,col%hill_area(c) - - ! mean elevation of column relative to mean gridcell elevation - col%hill_elev(c) = hcol_elevation(ue_distance, le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'he: ',c,col%hill_elev(c) - - ! mean along-hill slope of column - col%hill_slope(c) = hcol_slope(ue_distance, le_distance, & - hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'hs: ',c,col%hill_slope(c) - - if (masterproc .and. 1==2) then - write(iulog,*) 'hillslope geometry' - write(iulog,'(a12,i4,i10,5f16.4)') 'd,w,a,e,s: ', nh, c, col%hill_distance(c), col%hill_width(c), col%hill_area(c), col%hill_elev(c), col%hill_slope(c) - write(iulog,*) ' ' - endif - - enddo - - ! Now that column areas are determined, column weights can be recalculated - hillslope_area = 0._r8 - ! area weighted by pct_hillslope - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) - enddo - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - col%wtlunit(c) = col%hill_area(c) & - * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area - enddo - - ! Set column bedrock index - !thin soil for non-riparian columns, thick for riparian - do c = lun%coli(l), lun%colf(l) - if(col%cold(c) /= ispval) then - do j = jmin_bedrock,nlevsoi - if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then - col%nbedrock(c) = j - end if - enddo - else - do j = jmin_bedrock,nlevsoi - if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then - col%nbedrock(c) = j - end if - enddo - endif - end do - - endif ! end of istsoil - enddo ! end of loop over landunits - - deallocate(pct_hillslope,hill_alpha,hill_beta,hill_length, & - hill_width,hill_height) - - endif !use_hillslope - !----------------------------------------------- ! Set lake levels and layers (no interfaces) !----------------------------------------------- @@ -991,6 +786,8 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof slopemax = 0.4_r8 slope0 = slopemax**(-1._r8/slopebeta) col%micro_sigma(c) = (col%topo_slope(c) + slope0)**(-slopebeta) +!scs +! col%micro_sigma(c) = 0.05_r8 end do call ncd_pio_closefile(ncid) From 73b2833bdab328b6d682d0920b285f2e5b1d39a9 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 17 Mar 2017 18:31:24 +0000 Subject: [PATCH 006/153] hillslope_hydrology_n06_clm4_5_14_r226 fixed positive drainage in soilhydrologymod --- src/biogeophys/BalanceCheckMod.F90 | 1 - src/biogeophys/SoilHydrologyMod.F90 | 74 +++++------------------------ src/main/clm_instMod.F90 | 10 ++-- src/main/histFileMod.F90 | 20 ++++---- 4 files changed, 26 insertions(+), 79 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 7ff0387460..9731e39e0d 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -229,7 +229,6 @@ subroutine BalanceCheck( bounds, & snow_sinks => waterflux_inst%snow_sinks_col , & ! Output: [real(r8) (:) ] snow sinks (mm H2O /s) qflx_irrig => irrigation_inst%qflx_irrig_col , & ! Input: [real(r8) (:) ] irrigation flux (mm H2O /s) - qflx_net_latflow => waterflux_inst%qflx_net_latflow_col , & ! Output: [real(r8) (:) ] net hillcol lateral flow (mm/s) qflx_glcice_dyn_water_flux => glacier_smb_inst%qflx_glcice_dyn_water_flux_col, & ! Input: [real(r8) (:)] water flux needed for balance check due to glc_dyn_runoff_routing (mm H2O/s) (positive means addition of water to the system) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 4512e1aa4b..484c0d0ca8 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2545,72 +2545,34 @@ subroutine LateralFlowHillslope(bounds, & rsub_top(c) = 0._r8 endif -if(c==c0) then - write(iulog,*) 'rsubtop: ',c,lun%itype(col%landunit(c)),istsoil,col%colu(c),col%cold(c) - write(iulog,'(i4,5f16.4)') col%hillslope_ndx(c),col%hill_distance(c),col%hill_width(c),col%hill_area(c),col%hill_elev(c),col%hill_slope(c) - write(iulog,'(5e16.4)') qflx_latflow_out_vol(c),qflx_latflow_in(c),qflx_latflow_out(c),qflx_net_latflow(c) - write(iulog,'(5e16.4)') qflx_net_latflow(c)*1800., qflx_net_latflow(c)*3600. - write(iulog,'(a12,2i8,2e16.4)') 'transmis: ', jwt(c),nbedrock(c),transmis - write(iulog,*) ' ' - -endif - !-- Now remove water via rsub_top rsub_top_tot = - rsub_top(c) * dtime if(rsub_top_tot > 0.) then !rising water table - do j = jwt(c)+1, nbedrock(c) + do j = jwt(c)+1,1,-1 ! analytical expression for specific yield s_y = watsat(c,j) & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) s_y=max(s_y,0.02_r8) -if(c==c0) then - write(iulog,'(a12,5e16.4)') 's_y: ',s_y,-(s_y*(zi(c,j) - zwt(c))*1.e3) - write(iulog,*) ' ' -endif - rsub_top_layer=max(rsub_top_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) - rsub_top_layer=min(rsub_top_layer,0._r8) + rsub_top_layer=min(rsub_top_tot,(s_y*dz(c,j)*1.e3)) + rsub_top_layer=max(rsub_top_layer,0._r8) h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer -if(c==c0) then - write(iulog,'(a12,5e16.4)') 'negrsub: ',h2osoi_liq(c,jwt(c)+1), (rsub_top(c) * dtime),rsub_top_tot - write(iulog,'(a12,5e16.4)') 'rslayer: ', rsub_top_tot, rsub_top_layer - write(iulog,*) ' ' -endif - rsub_top_tot = rsub_top_tot - rsub_top_layer - -if(c==c0) then - write(iulog,'(a12,5e16.4)') 'newrsubtoptot: ',rsub_top_tot - write(iulog,*) ' ' -endif - if (rsub_top_tot >= 0.) then + + if (rsub_top_tot <= 0.) then zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 exit else - zwt(c) = zi(c,j) + zwt(c) = zi(c,j-1) endif + enddo - !-- remove residual rsub_top --------------------------------------------- - ! make sure no extra water removed from soil column - rsub_top(c) = rsub_top(c) - rsub_top_tot/dtime - -if(c==c0) then - write(iulog,'(a12,5e16.4)') 'posrsub: ',h2osoi_liq(c,jwt(c)+1), (rsub_top(c) * dtime) - write(iulog,*) ' ' -endif - - h2osoi_liq(c,jwt(c)+1) = h2osoi_liq(c,jwt(c)+1) - (rsub_top(c) * dtime) - ! analytical expression for specific yield - s_y = watsat(c,jwt(c)+1) & - * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,jwt(c)+1))**(-1./bsw(c,jwt(c)+1))) - s_y=max(s_y,0.02_r8) - - zwt(c) = zwt(c) - (rsub_top(c) * dtime)/s_y/1000._r8 - rsub_top_tot = 0._r8 - + !-- remove residual rsub_top -------------------------------- + h2osfc(c) = h2osfc(c) + rsub_top_tot + else ! deepening water table do j = jwt(c)+1, nbedrock(c) ! analytical expression for specific yield @@ -2618,26 +2580,12 @@ subroutine LateralFlowHillslope(bounds, & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) s_y=max(s_y,0.02_r8) -if(c==c0) then - write(iulog,'(a12,5e16.4)') 's_y: ',s_y,-(s_y*(zi(c,j) - zwt(c))*1.e3) - write(iulog,*) ' ' -endif rsub_top_layer=max(rsub_top_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) rsub_top_layer=min(rsub_top_layer,0._r8) h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer -if(c==c0) then - write(iulog,'(a12,5e16.4)') 'negrsub: ',h2osoi_liq(c,jwt(c)+1), (rsub_top(c) * dtime),rsub_top_tot - write(iulog,'(a12,5e16.4)') 'rslayer: ', rsub_top_tot, rsub_top_layer - write(iulog,*) ' ' -endif - rsub_top_tot = rsub_top_tot - rsub_top_layer -if(c==c0) then - write(iulog,'(a12,5e16.4)') 'newrsubtoptot: ',rsub_top_tot - write(iulog,*) ' ' -endif if (rsub_top_tot >= 0.) then zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 exit @@ -2748,7 +2696,7 @@ subroutine LateralFlowHillslope(bounds, & ! Sub-surface runoff and drainage qflx_drain(c) = qflx_rsub_sat(c) + rsub_top(c) -if(c==c0)write(iulog,*) 'qdrain: ', qflx_drain(c), qflx_rsub_sat(c), rsub_top(c) + ! Set imbalance for snow capping qflx_qrgwl(c) = qflx_snwcp_liq(c) diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 26d72b3dda..029c8531db 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -279,6 +279,11 @@ subroutine clm_instInit(bounds) call canopystate_inst%Init(bounds) + if(use_hillslope) then + allocate(hillslope_inst, & + source=create_and_init_hillslope_geomorphology_type(bounds)) + endif + call soilstate_inst%Init(bounds) call SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) ! sets hydraulic and thermal soil properties @@ -322,11 +327,6 @@ subroutine clm_instInit(bounds) call dust_inst%Init(bounds) - if(use_hillslope) then - allocate(hillslope_inst, & - source=create_and_init_hillslope_geomorphology_type(bounds)) - endif - ! Once namelist options are added to control the soil water retention curve method, ! we'll need to either pass the namelist file as an argument to this routine, or pass ! the namelist value itself (if the namelist is read elsewhere). diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index c24652d7d8..93d29d7b66 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2325,7 +2325,7 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='levdcmp', xtype=tape(t)%ncprec, dim1name='levdcmp', & long_name='coordinate soil levels', units='m', ncid=nfid(t)) - if (ldomain%isgrid2d) then + if (tape(t)%dov2xy) then !pass else call ncd_defvar(varname='hslp_distance', xtype=ncd_double, & @@ -2371,15 +2371,15 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='levdcmp', data=zsoi_1d, ncid=nfid(t), flag='write') end if - if (.not.ldomain%isgrid2d) then - call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_elev' , data=col%hill_elev, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') - endif + if (.not.tape(t)%dov2xy) then + call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_elev' , data=col%hill_elev, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') + endif if(use_ed)then call ncd_io(varname='levscls',data=levsclass_ed, ncid=nfid(t), flag='write') From 69d35dde9485ef0ab9eb97fcd97a19b4ef1c0b5d Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 4 Apr 2017 18:31:21 +0000 Subject: [PATCH 007/153] hillslope_hydrology_n07_clm4_5_14_r226 fixed patch%column assinment in histfilemod --- src/biogeophys/SoilHydrologyMod.F90 | 14 ++++++-------- src/biogeophys/WaterfluxType.F90 | 14 +++++++------- src/main/histFileMod.F90 | 7 +++++-- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 484c0d0ca8..fb6327d361 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2344,7 +2344,6 @@ subroutine LateralFlowHillslope(bounds, & real(r8) :: dgrad real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 20._r8 - real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) integer :: c0, nstep @@ -2366,7 +2365,7 @@ subroutine LateralFlowHillslope(bounds, & hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) qflx_latflow_out => waterflux_inst%qflx_latflow_out_col , & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) qflx_latflow_in => waterflux_inst%qflx_latflow_in_col , & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) - qflx_net_latflow_in => waterflux_inst%qflx_net_latflow_col , & ! Output: [real(r8) (:) ] net lateral saturated (mm/s) + qdischarge => waterflux_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) @@ -2430,8 +2429,7 @@ subroutine LateralFlowHillslope(bounds, & qflx_latflow_in(c) = 0._r8 qflx_latflow_out(c) = 0._r8 - qflx_net_latflow(c) = 0._r8 - qflx_latflow_out_vol(c) = 0._r8 + qdischarge(c) = 0._r8 end do @@ -2483,7 +2481,7 @@ subroutine LateralFlowHillslope(bounds, & ! kinematic wave approximation if (baseflow_method == 'kinematic') then - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*col%hill_slope(c) + qdischarge(c) = transmis*col%hill_width(c)*col%hill_slope(c) endif ! darcy's law @@ -2497,11 +2495,11 @@ subroutine LateralFlowHillslope(bounds, & !what lower boundary condition to use?? endif - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad + qdischarge(c) = transmis*col%hill_width(c)*dgrad end if ! convert volumetric flow to equivalent flux - qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) + qflx_latflow_out(c) = 1.e3_r8*qdischarge(c)/col%hill_area(c) ! hilltop column has no inflow if (col%colu(c) == ispval) then @@ -2510,7 +2508,7 @@ subroutine LateralFlowHillslope(bounds, & ! current outflow is inflow to downhill column normalized by downhill area if (col%cold(c) /= ispval) then - qflx_latflow_in(col%cold(c)) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) + qflx_latflow_in(col%cold(c)) = 1.e3_r8*qdischarge(c)/col%hill_area(col%cold(c)) endif enddo diff --git a/src/biogeophys/WaterfluxType.F90 b/src/biogeophys/WaterfluxType.F90 index 36d93b8d57..fd8f0a8ddf 100644 --- a/src/biogeophys/WaterfluxType.F90 +++ b/src/biogeophys/WaterfluxType.F90 @@ -75,7 +75,7 @@ module WaterfluxType real(r8), pointer :: qflx_drain_col (:) ! col sub-surface runoff (mm H2O /s) real(r8), pointer :: qflx_latflow_in_col (:) ! col hillslope lateral flow input (mm/s) real(r8), pointer :: qflx_latflow_out_col (:) ! col hillslope lateral flow output (mm/s) - real(r8), pointer :: qflx_net_latflow_col (:) ! col hillslope net lateral flow (mm/s) + real(r8), pointer :: qdischarge_col (:) ! col hillslope discharge (m3/s) real(r8), pointer :: qflx_top_soil_col (:) ! col net water input into soil from top (mm/s) real(r8), pointer :: qflx_h2osfc_to_ice_col (:) ! col conversion of h2osfc to ice real(r8), pointer :: qflx_h2osfc_surf_col (:) ! col surface water runoff @@ -217,7 +217,7 @@ subroutine InitAllocate(this, bounds) allocate(this%qflx_drain_col (begc:endc)) ; this%qflx_drain_col (:) = nan allocate(this%qflx_latflow_in_col (begc:endc)) ; this%qflx_latflow_in_col (:) = 0._r8 allocate(this%qflx_latflow_out_col (begc:endc)) ; this%qflx_latflow_out_col (:) = 0._r8 - allocate(this%qflx_net_latflow_col (begc:endc)) ; this%qflx_net_latflow_col (:) = 0._r8 + allocate(this%qdischarge_col (begc:endc)) ; this%qdischarge_col (:) = 0._r8 allocate(this%qflx_top_soil_col (begc:endc)) ; this%qflx_top_soil_col (:) = nan allocate(this%qflx_h2osfc_to_ice_col (begc:endc)) ; this%qflx_h2osfc_to_ice_col (:) = nan allocate(this%qflx_h2osfc_surf_col (begc:endc)) ; this%qflx_h2osfc_surf_col (:) = nan @@ -310,10 +310,10 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='hillcol lateral outflow', & ptr_col=this%qflx_latflow_out_col, c2l_scale_type='urbanf') - this%qflx_net_latflow_col(begc:endc) = spval - call hist_addfld1d (fname='QLATNET', units='mm/s', & - avgflag='A', long_name='hillcol net lateral flow', & - ptr_col=this%qflx_net_latflow_col, c2l_scale_type='urbanf',& + this%qdischarge_col(begc:endc) = spval + call hist_addfld1d (fname='QDISCHARGE', units='m3/s', & + avgflag='A', long_name='hillslope discharge from column', & + ptr_col=this%qdischarge_col, c2l_scale_type='urbanf',& default='inactive') this%qflx_liq_dynbal_grc(begg:endg) = spval @@ -697,7 +697,7 @@ subroutine InitCold(this, bounds) this%qflx_surf_col(c) = 0._r8 this%qflx_latflow_in_col(c) = 0._r8 this%qflx_latflow_out_col(c) = 0._r8 - this%qflx_net_latflow_col(c) = 0._r8 + this%qdischarge_col(c) = 0._r8 end if end do diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 93d29d7b66..777556facd 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -3048,8 +3048,11 @@ subroutine hfields_1dinfo(t, mode) !call ncd_io(varname='pfts1d_gi' , data=patch%gridcell, dim1name=namep, ncid=ncid, flag='write') !call ncd_io(varname='pfts1d_li' , data=patch%landunit, dim1name=namep, ncid=ncid, flag='write') ! commenting-in for hillslope hydrology - call ncd_io(varname='pfts1d_ci' , data=patch%column , dim1name=namep, ncid=ncid, flag='write') -! + do p=bounds%begp,bounds%endp + iparr(p) = GetGlobalIndex(decomp_index=patch%column(p), clmlevel=namec) + enddo + call ncd_io(varname='pfts1d_ci' , data=iparr , dim1name=namep, ncid=ncid, flag='write') + ! ---------------------------------------------------------------- call ncd_io(varname='pfts1d_wtgcell' , data=patch%wtgcell , dim1name=namep, ncid=ncid, flag='write') call ncd_io(varname='pfts1d_wtlunit' , data=patch%wtlunit , dim1name=namep, ncid=ncid, flag='write') From de6ce31fab7ed853426ee27150275f23e543b929 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 5 Apr 2017 21:24:58 +0000 Subject: [PATCH 008/153] hillslope_hydrology_n08_clm4_5_14_r226 added getglobalindex to histfilemod --- src/biogeophys/SoilHydrologyMod.F90 | 1 + src/main/histFileMod.F90 | 1 + 2 files changed, 2 insertions(+) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index fb6327d361..fd74763615 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2429,6 +2429,7 @@ subroutine LateralFlowHillslope(bounds, & qflx_latflow_in(c) = 0._r8 qflx_latflow_out(c) = 0._r8 + qflx_net_latflow(c) = 0._r8 qdischarge(c) = 0._r8 end do diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 777556facd..175d048346 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -16,6 +16,7 @@ module histFileMod use clm_varcon , only : spval, ispval, dzsoi_decomp use clm_varcon , only : grlnd, nameg, namel, namec, namep, nameCohort use decompMod , only : get_proc_bounds, get_proc_global, bounds_type + use GetGlobalValuesMod , only : GetGlobalIndex use GridcellType , only : grc use LandunitType , only : lun use ColumnType , only : col From 48f09fc0934c6c9c319448cafea9df68c77ccc71 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 19 Dec 2017 17:48:11 +0000 Subject: [PATCH 009/153] hillslope_hydrology_n09_clm4_5_14_r226 update SoilHydrology --- src/biogeophys/SoilHydrologyMod.F90 | 28 +++++++++++++++------------- src/main/atm2lndType.F90 | 6 ++++-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index fd74763615..e94b015263 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2344,6 +2344,7 @@ subroutine LateralFlowHillslope(bounds, & real(r8) :: dgrad real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 20._r8 + real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) integer :: c0, nstep @@ -2400,11 +2401,6 @@ subroutine LateralFlowHillslope(bounds, & dtime = get_step_size() nstep = get_nstep() -!!$ if ( nstep > 800) then -!!$ c0=101298 -!!$ else -!!$ c0=-1000 -!!$ endif ! Convert layer thicknesses from m to mm @@ -2431,7 +2427,8 @@ subroutine LateralFlowHillslope(bounds, & qflx_latflow_out(c) = 0._r8 qflx_net_latflow(c) = 0._r8 qdischarge(c) = 0._r8 - end do + qflx_latflow_out_vol(c) = 0._r8 + end do ! The layer index of the first unsaturated layer, @@ -2467,6 +2464,8 @@ subroutine LateralFlowHillslope(bounds, & transmis = transmis + 1.e-3_r8*hksat(c,j)*dz(c,j) endif end do + ! adjust by 'anisotropy factor' + transmis = k_anisotropic*transmis endif ! constant conductivity based on shallowest saturated layer hk if (transmissivity_method == 'constant') then @@ -2482,8 +2481,7 @@ subroutine LateralFlowHillslope(bounds, & ! kinematic wave approximation if (baseflow_method == 'kinematic') then - qdischarge(c) = transmis*col%hill_width(c)*col%hill_slope(c) - + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*col%hill_slope(c) endif ! darcy's law if (baseflow_method == 'darcy') then @@ -2493,14 +2491,18 @@ subroutine LateralFlowHillslope(bounds, & - (col%hill_elev(c_down)+(zi(c,nbedrock(c))-zwt(c_down))) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(c_down)) else -!what lower boundary condition to use?? - +! assume elev = 0 at channel and zwt = 0 at channel + dgrad = (col%hill_elev(c)-zwt(c)) + dgrad = dgrad / (col%hill_distance(c)) endif - qdischarge(c) = transmis*col%hill_width(c)*dgrad + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad end if +! currently this is redundant to above + qdischarge(c) = qflx_latflow_out_vol(c) + ! convert volumetric flow to equivalent flux - qflx_latflow_out(c) = 1.e3_r8*qdischarge(c)/col%hill_area(c) + qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) ! hilltop column has no inflow if (col%colu(c) == ispval) then @@ -2509,7 +2511,7 @@ subroutine LateralFlowHillslope(bounds, & ! current outflow is inflow to downhill column normalized by downhill area if (col%cold(c) /= ispval) then - qflx_latflow_in(col%cold(c)) = 1.e3_r8*qdischarge(c)/col%hill_area(col%cold(c)) + qflx_latflow_in(col%cold(c)) = qflx_latflow_in(col%cold(c)) + 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) endif enddo diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index 75449486e6..586df9b1d3 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -682,12 +682,14 @@ subroutine InitHistory(this, bounds) this%forc_rain_not_downscaled_grc(begg:endg) = spval call hist_addfld1d (fname='RAIN', units='mm/s', & avgflag='A', long_name='atmospheric rain', & - ptr_lnd=this%forc_rain_not_downscaled_grc) +!scs ptr_lnd=this%forc_rain_not_downscaled_grc) + ptr_col=this%forc_rain_downscaled_col) this%forc_snow_not_downscaled_grc(begg:endg) = spval call hist_addfld1d (fname='SNOW', units='mm/s', & avgflag='A', long_name='atmospheric snow', & - ptr_lnd=this%forc_snow_not_downscaled_grc) +!scs ptr_lnd=this%forc_snow_not_downscaled_grc) + ptr_col=this%forc_snow_downscaled_col) this%forc_rain_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='RAIN_REPARTITIONED', units='mm/s', & From 78096d522090b5125348af9507d3e0f9f5163f6f Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Tue, 2 Jan 2018 21:43:09 +0000 Subject: [PATCH 010/153] hillslope_hydrology_n09_clm4_5_18_r270 Update to clm4_5_18_r270 --- .CLMTrunkChecklist | 57 + .ChangeLog_template | 22 +- SVN_EXTERNAL_DIRECTORIES | 2 + SVN_EXTERNAL_DIRECTORIES.standalone | 10 +- bld/CLMBuildNamelist.pm | 1810 +++-- bld/configure | 10 +- bld/listDefaultNamelist.pl | 21 +- bld/namelist_files/LogMessages.pm | 244 + bld/namelist_files/checkmapfiles.ncl | 2 +- .../namelist_defaults_clm4_0.xml | 31 - .../namelist_defaults_clm4_5.xml | 867 +- .../namelist_defaults_clm4_5_tools.xml | 702 +- bld/namelist_files/namelist_defaults_drv.xml | 9 + .../namelist_defaults_overall.xml | 11 +- .../namelist_definition_clm4_0.xml | 2 +- .../namelist_definition_clm4_5.xml | 278 +- .../namelist_definition_drv.xml | 17 + .../namelist_definition_drv_flds.xml | 131 + .../1850-2100_rcp2.6_glacierMEC_transient.xml | 54 - .../use_cases/1850-2100_rcp2.6_transient.xml | 4 + .../1850-2100_rcp4.5_glacierMEC_transient.xml | 54 - .../use_cases/1850-2100_rcp4.5_transient.xml | 4 + .../1850-2100_rcp6_glacierMEC_transient.xml | 54 - .../use_cases/1850-2100_rcp6_transient.xml | 4 + .../1850-2100_rcp8.5_glacierMEC_transient.xml | 54 - .../use_cases/1850-2100_rcp8.5_transient.xml | 4 + bld/namelist_files/use_cases/1850_control.xml | 3 + .../use_cases/1850_glacierMEC_control.xml | 36 - .../use_cases/2000-2100_rcp8.5_transient.xml | 4 + bld/namelist_files/use_cases/2000_control.xml | 4 + .../use_cases/2000_glacierMEC_control.xml | 36 - .../use_cases/20thC_glacierMEC_transient.xml | 48 - .../use_cases/20thC_transient.xml | 4 + .../use_cases/glacierMEC_pd.xml | 11 - bld/namelist_files/use_cases/stdurbpt_pd.xml | 4 + bld/queryDefaultNamelist.pl | 23 +- .../t/input/namelist_defaults_clm4_5_test.xml | 60 +- .../input/namelist_definition_clm4_5_test.xml | 31 +- bld/test_build_namelist/t/test_do_harvest.pm | 6 +- .../t/test_do_transient_crops.pm | 4 +- .../t/test_do_transient_pfts.pm | 6 +- .../t/{test_ed_mode.pm => test_fates_mode.pm} | 146 +- bld/unit_testers/NMLTest/CompFiles.pm | 2 +- bld/unit_testers/build-namelist_test.pl | 302 +- cime_config/SystemTests/lii.py | 56 + cime_config/SystemTests/lvg.py | 37 + cime_config/SystemTests/ssp.py | 99 + cime_config/buildlib | 10 +- cime_config/buildnml | 31 +- cime_config/config_component.xml | 115 +- cime_config/config_compsets.xml | 557 +- cime_config/config_pes.xml | 201 + cime_config/config_tests.xml | 58 + cime_config/testdefs/ExpectedTestFails.xml | 17 +- cime_config/testdefs/testlist_clm.xml | 1852 ++--- .../testmods_dirs/clm/40ptsRLA/shell_commands | 1 + .../testmods_dirs/clm/40ptsRLB/shell_commands | 1 + .../testmods_dirs/clm/40ptsROA/shell_commands | 1 + .../testmods_dirs/clm/USUMB/shell_commands | 16 +- .../testmods_dirs/clm/USUMB/user_nl_clm | 4 +- .../clm/af_bias_v5/shell_commands | 1 - .../clm/af_bias_v7/shell_commands | 1 + .../{af_bias_v5 => af_bias_v7}/user_nl_clm | 0 .../{af_bias_v5 => af_bias_v7}/user_nl_datm | 0 .../clm/allActive/shell_commands | 13 + .../testmods_dirs/clm/allActive/user_nl_clm | 3 +- .../clm/ciso_bombspike1963/user_nl_clm | 1 + .../clm/ciso_rtmColdSSP/include_user_mods | 2 + .../include_user_mods | 0 .../clm/clm50CMIP6frc/user_nl_clm | 3 + .../clm/clm50KSinkMOut/user_nl_clm | 1 - .../clm/clm50KitchenSink/user_nl_clm | 3 - .../clm50cropIrrigMonth_interp/shell_commands | 1 - .../clm50cropIrrigMonth_interp/user_nl_clm | 6 +- .../testmods_dirs/clm/cmip6/include_user_mods | 1 + .../clm/cropColdStart/shell_commands | 1 + .../clm/cropColdStart/user_nl_clm | 2 - .../clm/cropMonthOutput/user_nl_clm | 2 - .../testmods_dirs/clm/decStart/user_nl_cism | 9 + .../clm/decStart1851_noinitial/README | 4 +- .../clm/decStart1851_noinitial/shell_commands | 1 + .../clm/decStart1851_noinitial/user_nl_clm | 1 - .../clm/edNoFire/include_user_mods | 1 - .../testmods_dirs/clm/edNoFire/user_nl_clm | 2 - .../clm/{edTest => fates}/shell_commands | 1 + .../clm/{edTest => fates}/user_nl_clm | 1 - .../clm/fatesFire/include_user_mods | 1 + .../{edNoFire => fatesFire}/shell_commands | 0 .../testmods_dirs/clm/fatesFire/user_nl_clm | 2 + .../testmods_dirs/clm/glcMEC/user_nl_clm | 3 - .../testmods_dirs/clm/glcMEC_long/user_nl_clm | 4 - .../clm/glcMEC_spunup_1way/README | 27 +- .../clm/glcMEC_spunup_1way/user_nl_clm | 7 +- .../clm/glcMEC_spunup_inc_dec_bgc/README | 7 +- .../clm/glcMEC_spunup_inc_dec_bgc/user_nl_clm | 6 - .../testmods_dirs/clm/interp_f19_crop/README | 7 - .../clm/interp_f19_crop/user_nl_clm | 1 - .../clm/interp_f19_noncrop/user_nl_clm | 2 +- .../clm/irrigOn_reduceOutput/shell_commands | 1 - .../clm/irrigOn_reduceOutput/user_nl_clm | 3 + .../clm/irrig_spunup/shell_commands | 1 - .../clm/irrig_spunup/user_nl_clm | 5 +- .../clm/monthly_noinitial/shell_commands | 4 + .../clm/monthly_noinitial/user_nl_clm | 4 - .../testmods_dirs/clm/no_vector_output/README | 2 + .../clm/no_vector_output/include_user_mods | 1 + .../clm/no_vector_output/user_nl_clm | 1 + .../testmods_dirs/clm/ptsRLA/shell_commands | 1 + .../testmods_dirs/clm/ptsRLB/shell_commands | 1 + .../testmods_dirs/clm/ptsROA/shell_commands | 1 + .../rad_hrly_light_res_half/shell_commands | 1 + .../clm/rad_hrly_light_res_half/user_nl_datm | 1 + .../clm/reseedresetsnow/include_user_mods | 1 + .../clm/reseedresetsnow/user_nl_clm | 8 + .../clm/rtmColdSSP/include_user_mods | 1 + .../testmods_dirs/clm/rtmColdSSP/user_nl_rtm | 4 + .../clm/snowlayers_12/user_nl_clm | 8 - .../testmods_dirs/clm/tropicAtl_subset/README | 7 - .../clm/tropicAtl_subset/shell_commands | 2 - .../clm/tropicAtl_subset/user_nl_clm | 9 - .../clm/tropicAtl_subsetEarly/README | 6 - .../tropicAtl_subsetEarly/include_user_mods | 1 - .../clm/tropicAtl_subsetEarly/shell_commands | 1 - .../clm/tropicAtl_subsetLate/README | 6 - .../tropicAtl_subsetLate/include_user_mods | 1 - .../clm/tropicAtl_subsetLate/shell_commands | 1 - .../clm/tropicAtl_subsetMid/README | 5 - .../clm/tropicAtl_subsetMid/include_user_mods | 1 - .../clm/tropicAtl_subsetMid/shell_commands | 1 - .../testmods_dirs/clm/vrtlay_interp/README | 14 - .../clm/vrtlay_interp/include_user_mods | 1 - .../clm/vrtlay_interp/user_nl_clm | 1 - cime_config/user_nl_clm | 4 +- .../usermods_dirs/cmip6/include_user_mods | 2 + .../usermods_dirs/cmip6_glaciers/user_nl_clm | 5 + cime_config/usermods_dirs/cmip6_output/README | 5 + .../usermods_dirs/cmip6_output/shell_commands | 4 + .../usermods_dirs/cmip6_output/user_nl_clm | 39 + doc/ChangeLog | 6986 +++++++++++++++++ doc/ChangeSum | 50 +- doc/UsersGuide/adding_files.xml | 4 +- parse_cime.cs.status | 74 +- src/CMakeLists.txt | 21 +- src/ED/biogeochem/EDCanopyStructureMod.F90 | 710 -- src/ED/biogeochem/EDCohortDynamicsMod.F90 | 1183 --- src/ED/biogeochem/EDGrowthFunctionsMod.F90 | 384 - src/ED/biogeochem/EDPatchDynamicsMod.F90 | 1516 ---- src/ED/biogeochem/EDPhysiologyMod.F90 | 1651 ---- src/ED/biogeochem/EDSharedParamsMod.F90 | 57 - src/ED/biogeophys/EDAccumulateFluxesMod.F90 | 92 - src/ED/biogeophys/EDBtranMod.F90 | 338 - src/ED/biogeophys/EDPhotosynthesisMod.F90 | 1124 --- src/ED/biogeophys/EDSurfaceAlbedoMod.F90 | 1097 --- src/ED/fire/SFMainMod.F90 | 947 --- src/ED/fire/SFParamsMod.F90 | 212 - src/ED/main/CMakeLists.txt | 9 - src/ED/main/EDCLMLinkMod.F90 | 2371 ------ src/ED/main/EDEcophysConType.F90 | 110 - src/ED/main/EDInitMod.F90 | 297 - src/ED/main/EDMainMod.F90 | 426 - src/ED/main/EDParamsMod.F90 | 150 - src/ED/main/EDPftvarcon.F90 | 143 - src/ED/main/EDRestVectorMod.F90 | 2218 ------ src/ED/main/EDTypesMod.F90 | 591 -- src/ED/main/EDVecCohortType.F90 | 42 - src/ED/main/FatesGlobals.F90 | 38 - src/ED/main/FatesInterfaceMod.F90 | 593 -- src/README.unit_testing | 30 +- src/biogeochem/C14BompbSpikeMod.F90 | 137 - src/biogeochem/CNAnnualUpdateMod.F90 | 86 +- src/biogeochem/CNBalanceCheckMod.F90 | 8 +- src/biogeochem/CNCIsoAtmTimeSeriesReadMod.F90 | 319 + src/biogeochem/CNCIsoFluxMod.F90 | 187 +- src/biogeochem/CNCStateUpdate1Mod.F90 | 57 +- src/biogeochem/CNDVEstablishmentMod.F90 | 7 +- src/biogeochem/CNDriverMod.F90 | 24 +- src/biogeochem/CNFUNMod.F90 | 2 +- src/biogeochem/CNFireBaseMod.F90 | 56 +- src/biogeochem/CNFireLi2016Mod.F90 | 2 +- src/biogeochem/CNMRespMod.F90 | 2 +- src/biogeochem/CNPhenologyMod.F90 | 152 +- src/biogeochem/CNPrecisionControlMod.F90 | 21 +- src/biogeochem/CNProductsMod.F90 | 27 +- src/biogeochem/CNSharedParamsMod.F90 | 5 +- src/biogeochem/CNVegCarbonFluxType.F90 | 84 +- src/biogeochem/CNVegCarbonStateType.F90 | 522 +- src/biogeochem/CNVegNitrogenFluxType.F90 | 6 +- src/biogeochem/CNVegNitrogenStateType.F90 | 146 +- src/biogeochem/CNVegStateType.F90 | 49 +- src/biogeochem/CNVegetationFacade.F90 | 163 +- src/biogeochem/CropType.F90 | 42 +- src/biogeochem/DryDepVelocity.F90 | 97 +- src/biogeochem/EDBGCDynMod.F90 | 47 +- src/biogeochem/FireEmisFactorsMod.F90 | 15 +- .../NutrientCompetitionFlexibleCNMod.F90 | 20 +- src/biogeochem/SpeciesIsotopeType.F90 | 4 +- src/biogeochem/SpeciesNonIsotopeType.F90 | 6 +- src/biogeochem/ch4FInundatedStreamType.F90 | 393 + src/biogeochem/ch4Mod.F90 | 92 +- src/biogeochem/ch4varcon.F90 | 75 +- src/biogeochem/dynConsBiogeochemMod.F90 | 48 +- src/biogeochem/dynHarvestMod.F90 | 27 +- src/biogeophys/AerosolMod.F90 | 61 +- src/biogeophys/BalanceCheckMod.F90 | 131 +- src/biogeophys/BareGroundFluxesMod.F90 | 6 +- src/biogeophys/CMakeLists.txt | 3 + src/biogeophys/CanopyFluxesMod.F90 | 177 +- src/biogeophys/CanopyHydrologyMod.F90 | 4 +- src/biogeophys/CanopyStateType.F90 | 24 +- src/biogeophys/CanopyTemperatureMod.F90 | 42 +- src/biogeophys/EnergyFluxType.F90 | 35 +- src/biogeophys/FrictionVelocityMod.F90 | 10 +- .../GlacierSurfaceMassBalanceMod.F90 | 154 +- src/biogeophys/HumanIndexMod.F90 | 64 +- src/biogeophys/HydrologyDrainageMod.F90 | 103 +- src/biogeophys/HydrologyNoDrainageMod.F90 | 32 +- src/biogeophys/IrrigationMod.F90 | 2 +- src/biogeophys/LakeHydrologyMod.F90 | 25 +- src/biogeophys/LakeStateType.F90 | 11 +- src/biogeophys/LakeTemperatureMod.F90 | 13 +- src/biogeophys/OzoneMod.F90 | 49 +- src/biogeophys/PhotosynthesisMod.F90 | 421 +- src/biogeophys/RootBiophysMod.F90 | 12 +- src/biogeophys/SnowHydrologyMod.F90 | 214 +- src/biogeophys/SnowSnicarMod.F90 | 72 +- src/biogeophys/SoilFluxesMod.F90 | 6 +- .../SoilHydrologyInitTimeConstMod.F90 | 11 +- src/biogeophys/SoilHydrologyMod.F90 | 10 +- src/biogeophys/SoilHydrologyType.F90 | 2 +- src/biogeophys/SoilMoistStressMod.F90 | 19 +- src/biogeophys/SoilStateInitTimeConstMod.F90 | 16 +- src/biogeophys/SoilStateType.F90 | 20 +- src/biogeophys/SoilTemperatureMod.F90 | 40 +- src/biogeophys/SoilWaterMovementMod.F90 | 315 +- src/biogeophys/SoilWaterPlantSinkMod.F90 | 444 ++ src/biogeophys/SolarAbsorbedType.F90 | 4 +- src/biogeophys/SurfaceAlbedoMod.F90 | 14 +- src/biogeophys/SurfaceRadiationMod.F90 | 19 +- src/biogeophys/SurfaceResistanceMod.F90 | 10 +- src/biogeophys/TemperatureType.F90 | 131 +- src/biogeophys/TotalWaterAndHeatMod.F90 | 909 +++ src/biogeophys/UrbanAlbedoMod.F90 | 38 +- src/biogeophys/UrbanParamsType.F90 | 2 +- src/biogeophys/WaterStateType.F90 | 107 +- src/biogeophys/WaterfluxType.F90 | 157 +- src/biogeophys/test/CMakeLists.txt | 3 +- .../test/SnowHydrology_test/CMakeLists.txt | 3 +- .../test_SnowHydrology_SnowCappingExcess.pf | 230 + .../test_SnowHydrology_newSnowBulkDensity.pf | 57 +- .../TotalWaterAndHeat_test/CMakeLists.txt | 12 + .../test_total_water_and_heat.pf | 189 + src/cpl/clm_cpl_indices.F90 | 74 +- src/cpl/lnd_comp_mct.F90 | 21 +- src/cpl/lnd_import_export.F90 | 109 +- src/dyn_subgrid/dynColumnStateUpdaterMod.F90 | 268 +- src/dyn_subgrid/dynConsBiogeophysMod.F90 | 427 +- src/dyn_subgrid/dynEDMod.F90 | 2 +- src/dyn_subgrid/dynInitColumnsMod.F90 | 52 +- src/dyn_subgrid/dynLandunitAreaMod.F90 | 6 +- src/dyn_subgrid/dynSubgridControlMod.F90 | 51 +- src/dyn_subgrid/dynSubgridDriverMod.F90 | 40 +- src/dyn_subgrid/dynVarMod.F90.in | 6 +- .../test_column_state_updater.pf | 88 +- .../dynInitColumns_test/test_init_columns.pf | 22 +- .../test_update_landunit_weights.pf | 2 +- .../test_update_landunit_weights_one_gcell.pf | 10 +- src/main/ColumnType.F90 | 16 +- src/main/GetGlobalValuesMod.F90 | 4 +- src/main/GridcellType.F90 | 3 + src/main/LandunitType.F90 | 2 +- src/main/PatchType.F90 | 26 +- src/main/TopoMod.F90 | 17 +- src/main/accumulMod.F90 | 697 +- src/main/atm2lndMod.F90 | 4 +- src/main/atm2lndType.F90 | 148 +- src/main/clm_driver.F90 | 136 +- src/main/clm_initializeMod.F90 | 99 +- src/main/clm_instMod.F90 | 96 +- src/main/clm_varcon.F90 | 4 +- src/main/clm_varctl.F90 | 20 +- src/main/clm_varpar.F90 | 4 +- src/main/column_varcon.F90 | 4 + src/main/controlMod.F90 | 109 +- src/main/decompInitMod.F90 | 24 +- src/main/decompMod.F90 | 8 +- src/main/filterColMod.F90 | 42 + src/main/filterMod.F90 | 9 +- src/main/glc2lndMod.F90 | 427 +- src/main/glcBehaviorMod.F90 | 99 +- src/main/histFileMod.F90 | 420 +- src/main/initGridCellsMod.F90 | 87 +- src/main/initSubgridMod.F90 | 10 +- src/main/initVerticalMod.F90 | 10 +- src/main/init_hydrology.F90 | 2 + src/main/landunit_varcon.F90 | 5 +- src/main/lnd2atmMod.F90 | 161 +- src/main/lnd2atmType.F90 | 138 +- src/main/lnd2glcMod.F90 | 42 +- src/main/ncdio_pio.F90.in | 5 +- src/main/ndepStreamMod.F90 | 115 +- src/main/paramUtilMod.F90 | 160 + src/main/pftconMod.F90 | 34 +- src/main/readParamsMod.F90 | 21 +- src/main/restFileMod.F90 | 15 +- src/main/subgridAveMod.F90 | 44 +- src/main/subgridMod.F90 | 47 +- src/main/subgridRestMod.F90 | 6 +- src/main/subgridWeightsMod.F90 | 69 +- src/main/surfrdMod.F90 | 270 +- src/main/surfrdUtilsMod.F90 | 80 +- src/main/test/CMakeLists.txt | 2 + src/main/test/accumul_test/CMakeLists.txt | 7 + src/main/test/accumul_test/test_accumul.pf | 720 ++ src/main/test/filter_test/test_filter_col.pf | 32 + .../test/glcBehavior_test/test_glcBehavior.pf | 56 +- src/main/test/surfrdUtils_test/CMakeLists.txt | 4 + .../test/surfrdUtils_test/test_surfrdUtils.pf | 217 + src/main/test/topo_test/test_topo.pf | 33 +- .../SoilBiogeochemCarbonFluxType.F90 | 75 +- .../SoilBiogeochemCarbonStateType.F90 | 143 +- .../SoilBiogeochemCompetitionMod.F90 | 5 +- .../SoilBiogeochemDecompCascadeBGCMod.F90 | 43 +- .../SoilBiogeochemDecompCascadeCNMod.F90 | 29 +- .../SoilBiogeochemDecompCascadeConType.F90 | 2 + .../SoilBiogeochemDecompMod.F90 | 6 +- .../SoilBiogeochemLittVertTranspMod.F90 | 4 +- .../SoilBiogeochemNitrogenFluxType.F90 | 17 +- .../SoilBiogeochemNitrogenStateType.F90 | 100 +- .../SoilBiogeochemPotentialMod.F90 | 6 +- .../SoilBiogeochemPrecisionControlMod.F90 | 50 +- .../SoilBiogeochemStateType.F90 | 17 +- src/unit_test_shr/unittestSubgridMod.F90 | 65 +- .../csm_share/mct_mod_stub.F90 | 8 +- .../csm_share/seq_comm_mct.F90 | 2 +- .../main/ncdio_pio_fake.F90.in | 67 + src/unit_test_stubs/utils/CMakeLists.txt | 1 + .../utils/clmfates_paraminterfaceMod_stub.F90 | 11 + src/utils/clmfates_interfaceMod.F90 | 1657 +++- src/utils/clmfates_paraminterfaceMod.F90 | 238 + src/utils/quadraticMod.F90 | 15 +- src/utils/restUtilMod.F90.in | 61 +- src_clm40/main/GetGlobalValuesMod.F90 | 2 +- src_clm40/main/ncdio_pio.F90.in | 4 +- test/tools/TCBCFGtools.sh | 1 + test/tools/TSMCFGtools.sh | 5 +- test/tools/TSMscript_tools.sh | 2 +- test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 | 2 +- test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 | 2 +- test/tools/nl_files/PTCLM_USUMB_clm4_5 | 2 +- test/tools/nl_files/gen_domain.T31.runoptions | 2 +- .../tools/nl_files/gen_domain.ne30.runoptions | 2 +- .../nl_files/mkprocdata_ne30_to_f19_I2000 | 2 +- test/tools/nl_files/mksrfdt_10x15_1850 | 2 +- .../nl_files/mksrfdt_1x1_vancouverCAN_2000 | 2 +- test/tools/test_driver.sh | 75 +- test/tools/tests_pretag_cheyenne_nompi | 15 + tools/SVN_EXTERNAL_DIRECTORIES | 1 - tools/mkmapdata/mkmapdata.sh | 83 +- tools/mkmapdata/regridbatch.sh | 8 +- tools/mkprocdata_map/README.filedescriptions | 25 + tools/mkprocdata_map/mkprocdata_map_in | 6 - tools/mkprocdata_map/mkprocdata_map_wrap | 14 +- tools/mksurfdata_map/Makefile.data | 128 +- ..._timeseries_hist_78pfts_simyr1850-2015.txt | 664 +- tools/mksurfdata_map/mksurfdata.pl | 39 +- tools/mksurfdata_map/mksurfdata_map.namelist | 28 +- tools/mksurfdata_map/src/CMakeLists.txt | 19 +- tools/mksurfdata_map/src/README.unit_testing | 5 +- tools/mksurfdata_map/src/mkfileMod.F90 | 56 +- .../mksurfdata_map/src/mkglacierregionMod.F90 | 16 +- tools/mksurfdata_map/src/mkglcmecMod.F90 | 16 +- tools/mksurfdata_map/src/mkgridmapMod.F90 | 245 +- tools/mksurfdata_map/src/mkharvestMod.F90 | 20 +- tools/mksurfdata_map/src/mkindexmapMod.F90 | 79 +- tools/mksurfdata_map/src/mkncdio.F90 | 1 + tools/mksurfdata_map/src/mkpftMod.F90 | 15 +- tools/mksurfdata_map/src/mksurfdat.F90 | 80 +- tools/mksurfdata_map/src/test/CMakeLists.txt | 2 + .../src/test/mkgridmap_test/CMakeLists.txt | 4 + .../src/test/mkgridmap_test/test_mkgridmap.pf | 114 + .../src/test/mkindexmap_test/CMakeLists.txt | 4 + .../test/mkindexmap_test/test_mkindexmap.pf | 251 + .../src/unit_test_stubs/mkncdio.F90 | 167 + 383 files changed, 25079 insertions(+), 25103 deletions(-) create mode 100644 .CLMTrunkChecklist create mode 100644 SVN_EXTERNAL_DIRECTORIES create mode 100755 bld/namelist_files/LogMessages.pm create mode 100644 bld/namelist_files/namelist_defaults_drv.xml create mode 100644 bld/namelist_files/namelist_definition_drv.xml create mode 100644 bld/namelist_files/namelist_definition_drv_flds.xml delete mode 100644 bld/namelist_files/use_cases/1850-2100_rcp2.6_glacierMEC_transient.xml delete mode 100644 bld/namelist_files/use_cases/1850-2100_rcp4.5_glacierMEC_transient.xml delete mode 100644 bld/namelist_files/use_cases/1850-2100_rcp6_glacierMEC_transient.xml delete mode 100644 bld/namelist_files/use_cases/1850-2100_rcp8.5_glacierMEC_transient.xml delete mode 100644 bld/namelist_files/use_cases/1850_glacierMEC_control.xml delete mode 100644 bld/namelist_files/use_cases/2000_glacierMEC_control.xml delete mode 100644 bld/namelist_files/use_cases/20thC_glacierMEC_transient.xml delete mode 100644 bld/namelist_files/use_cases/glacierMEC_pd.xml rename bld/test_build_namelist/t/{test_ed_mode.pm => test_fates_mode.pm} (54%) create mode 100644 cime_config/SystemTests/lii.py create mode 100644 cime_config/SystemTests/lvg.py create mode 100644 cime_config/SystemTests/ssp.py create mode 100644 cime_config/config_tests.xml delete mode 100644 cime_config/testdefs/testmods_dirs/clm/af_bias_v5/shell_commands create mode 100644 cime_config/testdefs/testmods_dirs/clm/af_bias_v7/shell_commands rename cime_config/testdefs/testmods_dirs/clm/{af_bias_v5 => af_bias_v7}/user_nl_clm (100%) rename cime_config/testdefs/testmods_dirs/clm/{af_bias_v5 => af_bias_v7}/user_nl_datm (100%) create mode 100644 cime_config/testdefs/testmods_dirs/clm/allActive/shell_commands create mode 100644 cime_config/testdefs/testmods_dirs/clm/ciso_rtmColdSSP/include_user_mods rename cime_config/testdefs/testmods_dirs/clm/{snowlayers_12 => clm50CMIP6frc}/include_user_mods (100%) create mode 100644 cime_config/testdefs/testmods_dirs/clm/clm50CMIP6frc/user_nl_clm delete mode 100755 cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/shell_commands create mode 100644 cime_config/testdefs/testmods_dirs/clm/cmip6/include_user_mods create mode 100755 cime_config/testdefs/testmods_dirs/clm/cropColdStart/shell_commands delete mode 100644 cime_config/testdefs/testmods_dirs/clm/cropColdStart/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/decStart/user_nl_cism delete mode 100644 cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/user_nl_clm delete mode 100644 cime_config/testdefs/testmods_dirs/clm/edNoFire/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/edNoFire/user_nl_clm rename cime_config/testdefs/testmods_dirs/clm/{edTest => fates}/shell_commands (56%) mode change 100755 => 100644 rename cime_config/testdefs/testmods_dirs/clm/{edTest => fates}/user_nl_clm (94%) create mode 100644 cime_config/testdefs/testmods_dirs/clm/fatesFire/include_user_mods rename cime_config/testdefs/testmods_dirs/clm/{edNoFire => fatesFire}/shell_commands (100%) create mode 100644 cime_config/testdefs/testmods_dirs/clm/fatesFire/user_nl_clm delete mode 100755 cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/shell_commands delete mode 100755 cime_config/testdefs/testmods_dirs/clm/irrig_spunup/shell_commands create mode 100755 cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/shell_commands delete mode 100644 cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/no_vector_output/README create mode 100644 cime_config/testdefs/testmods_dirs/clm/no_vector_output/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/no_vector_output/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/shell_commands create mode 100644 cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/user_nl_datm create mode 100644 cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm delete mode 100644 cime_config/testdefs/testmods_dirs/clm/snowlayers_12/user_nl_clm delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/README delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/shell_commands delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/user_nl_clm delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/README delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/shell_commands delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/README delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/shell_commands delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/README delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/shell_commands delete mode 100644 cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/README delete mode 100644 cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/user_nl_clm create mode 100644 cime_config/usermods_dirs/cmip6/include_user_mods create mode 100644 cime_config/usermods_dirs/cmip6_glaciers/user_nl_clm create mode 100644 cime_config/usermods_dirs/cmip6_output/README create mode 100644 cime_config/usermods_dirs/cmip6_output/shell_commands create mode 100644 cime_config/usermods_dirs/cmip6_output/user_nl_clm delete mode 100755 src/ED/biogeochem/EDCanopyStructureMod.F90 delete mode 100755 src/ED/biogeochem/EDCohortDynamicsMod.F90 delete mode 100755 src/ED/biogeochem/EDGrowthFunctionsMod.F90 delete mode 100755 src/ED/biogeochem/EDPatchDynamicsMod.F90 delete mode 100755 src/ED/biogeochem/EDPhysiologyMod.F90 delete mode 100644 src/ED/biogeochem/EDSharedParamsMod.F90 delete mode 100644 src/ED/biogeophys/EDAccumulateFluxesMod.F90 delete mode 100644 src/ED/biogeophys/EDBtranMod.F90 delete mode 100644 src/ED/biogeophys/EDPhotosynthesisMod.F90 delete mode 100644 src/ED/biogeophys/EDSurfaceAlbedoMod.F90 delete mode 100755 src/ED/fire/SFMainMod.F90 delete mode 100644 src/ED/fire/SFParamsMod.F90 delete mode 100644 src/ED/main/CMakeLists.txt delete mode 100755 src/ED/main/EDCLMLinkMod.F90 delete mode 100644 src/ED/main/EDEcophysConType.F90 delete mode 100755 src/ED/main/EDInitMod.F90 delete mode 100755 src/ED/main/EDMainMod.F90 delete mode 100644 src/ED/main/EDParamsMod.F90 delete mode 100644 src/ED/main/EDPftvarcon.F90 delete mode 100755 src/ED/main/EDRestVectorMod.F90 delete mode 100755 src/ED/main/EDTypesMod.F90 delete mode 100644 src/ED/main/EDVecCohortType.F90 delete mode 100644 src/ED/main/FatesGlobals.F90 delete mode 100644 src/ED/main/FatesInterfaceMod.F90 delete mode 100644 src/biogeochem/C14BompbSpikeMod.F90 create mode 100644 src/biogeochem/CNCIsoAtmTimeSeriesReadMod.F90 create mode 100644 src/biogeochem/ch4FInundatedStreamType.F90 create mode 100644 src/biogeophys/SoilWaterPlantSinkMod.F90 create mode 100644 src/biogeophys/TotalWaterAndHeatMod.F90 create mode 100644 src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_SnowCappingExcess.pf create mode 100644 src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt create mode 100644 src/biogeophys/test/TotalWaterAndHeat_test/test_total_water_and_heat.pf create mode 100644 src/main/test/accumul_test/CMakeLists.txt create mode 100644 src/main/test/accumul_test/test_accumul.pf create mode 100644 src/main/test/surfrdUtils_test/CMakeLists.txt create mode 100644 src/main/test/surfrdUtils_test/test_surfrdUtils.pf create mode 100644 src/unit_test_stubs/utils/clmfates_paraminterfaceMod_stub.F90 create mode 100644 src/utils/clmfates_paraminterfaceMod.F90 create mode 100644 test/tools/tests_pretag_cheyenne_nompi delete mode 100644 tools/SVN_EXTERNAL_DIRECTORIES create mode 100644 tools/mkprocdata_map/README.filedescriptions delete mode 100644 tools/mkprocdata_map/mkprocdata_map_in create mode 100644 tools/mksurfdata_map/src/test/mkgridmap_test/CMakeLists.txt create mode 100644 tools/mksurfdata_map/src/test/mkgridmap_test/test_mkgridmap.pf create mode 100644 tools/mksurfdata_map/src/test/mkindexmap_test/CMakeLists.txt create mode 100644 tools/mksurfdata_map/src/test/mkindexmap_test/test_mkindexmap.pf create mode 100644 tools/mksurfdata_map/src/unit_test_stubs/mkncdio.F90 diff --git a/.CLMTrunkChecklist b/.CLMTrunkChecklist new file mode 100644 index 0000000000..6d76a47a12 --- /dev/null +++ b/.CLMTrunkChecklist @@ -0,0 +1,57 @@ +Checklist of steps to do to make a CLM Trunk Tag Mar/7th/2017 + +CLM Code Management team. + +(1) Do all testing on the branch – i.e., on a sandbox that is just a clean checkout of +the branch (save to next tag name) + + 1a -- make sure any new failing tests are either fixed or approved as a new expected + fail + 1b -- update the ExpectedFails list if expected fails changes in 1a + $EDITOR components/clm/cime_config/testdefs/ExpectedTestFails.xml + 1c -- make sure you understand any changes to the baselines -- to document in ChangeLog + +(2) Use diff and status to make sure any new files are in the repo and only the correct +changes are on the branch + + 2a -- 'svn status' to check that you've added any new files and haven't + added any non source files that aren't needed in the repository + 2b -- 'svn diff' to check that your changes are correct and you didn't accidentally + add something unintentionally + 2c -- you could also update the content of the changelog here on the branch + +(3) Tag the branch + +(4) Merge branch tag to trunk and update to get any new externals + +(5) Commit to trunk + +(6) Compare trunk to branch show that they are identical + +svn diff --ignore-properties https://svn-ccsm-models.cgd.ucar.edu/clm2/trunk +https://svn-ccsm-models.cgd.ucar.edu/clm2/branches/BRANCHNAME + +This should show no diffs + +(7) Update ChangeLog + 7a -- if you didn't update the content in 2c do it now + (Increment the science minor number if answers change in an important way) + 7b -- update date stamp on ChangeLog + ./UpDateChangeLog.pl -update + 7c -- commit new change files + +(8) Make the trunk tag + + +NOTES: + +(1) -- Always test on a branch so that we can change tag order if needed. Put baselines +in the next tag name, as we can easily change afterwards if needed. +(2) -- This provides a final self code review of your changes. Having someone else review your +code is also useful, but making sure you review it careful is also important. This step makes +sure you don't commit changes you shouldn't and makes sure you don't neglect to add new files +that need to be added to the repository. It's easy for either of those problems to happen without +doing this step. +(7) or 2c -- Updating the ChangeLog needs to happen on the trunk shortly before the new +trunk tag is made. There is a cronjob that emails errors when the ChangeLog was updated +but the new trunk tag wasn't made. diff --git a/.ChangeLog_template b/.ChangeLog_template index 7219b46a20..8041e07938 100644 --- a/.ChangeLog_template +++ b/.ChangeLog_template @@ -41,6 +41,8 @@ Changes to tests or testing: Code reviewed by: +Did you follow the steps in .CLMTrunkChecklist: + CLM testing: [... Remove before making trunk_tag. Available test levels: @@ -59,26 +61,30 @@ CLM testing: build-namelist tests: - yellowstone - + cheyenne - unit-tests (components/clm/src): - yellowstone - + cheyenne - tools-tests (components/clm/test/tools): - yellowstone - + cheyenne - PTCLM testing (components/clm/tools/shared/PTCLM/test): - yellowstone - + cheyenne - - regular tests (aux_clm40, aux_clm45): + regular tests (aux_clm): yellowstone_intel - - yellowstone_pgi - - yellowstone_gnu (clm45 only) - - hobart_nag - + yellowstone_pgi --- + yellowstone_gnu --- + cheyenne_intel ---- + cheyenne_gnu ------ + hobart_nag -------- + hobart_pgi -------- + hobart_intel ------ CLM tag used for the baseline comparisons: diff --git a/SVN_EXTERNAL_DIRECTORIES b/SVN_EXTERNAL_DIRECTORIES new file mode 100644 index 0000000000..40ac793f7f --- /dev/null +++ b/SVN_EXTERNAL_DIRECTORIES @@ -0,0 +1,2 @@ +src/fates https://github.com/NCAR/fates-release/tags/fates_s1.3.0_a1.0.0_rev3 +tools/PTCLM https://github.com/ESCOMP/ptclm/tags/PTCLM2_171216c diff --git a/SVN_EXTERNAL_DIRECTORIES.standalone b/SVN_EXTERNAL_DIRECTORIES.standalone index 5b15c80852..ff91f394af 100644 --- a/SVN_EXTERNAL_DIRECTORIES.standalone +++ b/SVN_EXTERNAL_DIRECTORIES.standalone @@ -1,5 +1,5 @@ -cime https://github.com/CESM-Development/cime/tags/cime5.2.0-alpha.25 -components/clm/tools/gen_domain https://github.com/CESM-Development/cime/tags/cime5.2.0-alpha.25/tools/mapping/gen_domain_files -components/cism https://svn-ccsm-models.cgd.ucar.edu/glc/trunk_tags/cism2_1_29 -components/rtm https://svn-ccsm-models.cgd.ucar.edu/rivrtm/trunk_tags/rtm1_0_59 -components/mosart https://svn-ccsm-models.cgd.ucar.edu/mosart/trunk_tags/mosart1_0_20 +cime https://github.com/CESM-Development/cime/tags/billsacks/always_glcmec_n01 +components/clm/tools/gen_domain https://github.com/CESM-Development/cime/tags/billsacks/always_glcmec_n01/tools/mapping/gen_domain_files +components/cism https://svn-ccsm-models.cgd.ucar.edu/glc/trunk_tags/cism2_1_40 +components/rtm https://github.com/ESCOMP/rtm/tags/rtm1_0_63 +components/mosart https://github.com/ESCOMP/mosart/tags/mosart1_0_28 diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index e5cdb258b2..8bdbedc8a4 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -47,17 +47,8 @@ use File::Glob ':glob'; my $ProgDir = $1; $ProgName = "CLM " . "$ProgName"; -my $cwd = abs_path(getcwd()); # absolute path of the current working directory - -my $verbosity = 1; # Define print level -my $print_verbose = 2; - -# Some regular expressions... -###my $TRUE = qr/\.true\./i; -###my $FALSE = qr/\.false\./i; -# **N.B.** the use of qr// for precompiling regexps isn't supported until perl 5.005. -my $TRUE = '\.true\.'; -my $FALSE = '\.false\.'; +my $cwd = abs_path(getcwd()); # absolute path of the current working directory +my $log; # Log messages object -- will be set in main, declaring it global here means it can be used everywhere #------------------------------------------------------------------------------- @@ -81,13 +72,13 @@ REQUIRED OPTIONS dlatxdlon for fv grids (dlat and dlon are the grid cell size in degrees for latitude and longitude respectively) "-res list" to list valid resolutions. - (default: 1.9x2.5) + (default: 0.9x1.25) -sim_year "year" Year to simulate for input datasets (i.e. 1850, 2000, 1850-2000, 1850-2100) "-sim_year list" to list valid simulation years (default 2000) OPTIONS - -bgc "value" Build CLM with BGC package [ sp | cn | bgc | ed ] + -bgc "value" Build CLM with BGC package [ sp | cn | bgc | fates ] (default is sp). CLM Biogeochemistry mode sp = Satellite Phenology (SP) @@ -100,17 +91,18 @@ OPTIONS (or CLM45BGC if phys=clm4_5/clm5_0) This toggles on the namelist variables: use_cn, use_lch4, use_nitrif_denitrif, use_vertsoilc, use_century_decomp - ed = Ecosystem Demography with below ground BGC + fates = FATES/Ecosystem Demography with below ground BGC This toggles on the namelist variables: - use_ed, use_vertsoilc, use_century_decomp + use_fates, use_vertsoilc, use_century_decomp + (Only for CLM4.5/CLM5.0) -[no-]chk_res Also check [do NOT check] to make sure the resolution and land-mask is valid. -clm_accelerated_spinup "on|off" Setup in a configuration to run as fast as possible for doing a throw-away simulation in order to get the model to a spun-up state. So do things like turn off expensive options and setup for a low level of history output. - + If CLM4.5/CLM5.0 and bgc it also includes a prognostic Carbon model (cn or bgc) - , also by default turn on Accelerated Decomposition mode which + , also by default turn on Accelerated Decomposition mode which is controlled by the namelist variable spinup_state. BGC Spinup for CLM4.5/5.0 Only (for CLM4.0 BGC spinup is controlled from configure) @@ -129,14 +121,14 @@ OPTIONS mode. The spinup state is saved to the restart file. - If the values match between the model and the restart - file it proceeds as directed. + If the values match between the model and the restart + file it proceeds as directed. If the restart file is in spinup mode and the model is in - normal mode, then it performs the exit spinup step - and proceeds in normal mode after that. + normal mode, then it performs the exit spinup step + and proceeds in normal mode after that. - If the restart file has normal mode and the model is in + If the restart file has normal mode and the model is in spinup, then it enters spinup. This is useful if you change a parameter and want to rapidly re-equilibrate without doing a cold start. @@ -172,9 +164,6 @@ OPTIONS -fire_emis Produce a fire_emis_nl namelist that will go into the "drv_flds_in" file for the driver to pass fire emissions to the atm. (Note: buildnml copies the file for use by the driver) - -glc_present Set to true if the glc model is present (not sglc). - This is used for error-checking, to make sure other options are - set appropriately. -glc_nec Glacier number of elevation classes [0 | 3 | 5 | 10 | 36] (default is 0) (standard option with land-ice model is 10) -help [or -h] Print usage to STDOUT. @@ -183,6 +172,8 @@ OPTIONS when determining what input initial condition file to use. -ignore_ic_year Ignore just the year part of the date on the initial condition files when determining what input initial condition file to use. + -ignore_warnings Allow build-namelist to continue, rather than stopping on + warnings -infile "filepath" Specify a file (or list of files) containing namelists to read values from. @@ -197,10 +188,9 @@ OPTIONS form \$CASEDIR/user_nl_clm/user_nl_clm_????) -inputdata "filepath" Writes out a list containing pathnames for required input datasets in file specified. - -irrig "value" If .true. turn irrigation on with namelist logical irrigate (for CLM4.5 physics) - (requires use_crop to be true in the clm configuration) - Seek surface datasets with irrigation turned on. (for CLM4.0 physics) + -irrig "value" If .true. week surface datasets with irrigation turned on. (only allowed for CLM4.0 physics) Default: .false. + (for CLM4.5/CLM5.0 physics set the namelist flag irrigate=.true.) -l_ncpl "LND_NCPL" Number of CLM coupling time-steps in a day. -lnd_tuning_mode "value" Use the parameters tuned for the given configuration (CLM version and atmospheric forcing) -mask "landmask" Type of land-mask (default, navy, gx3v5, gx1v5 etc.) @@ -263,7 +253,6 @@ sub process_commandline { clm_demand => "null", help => 0, glc_nec => "default", - glc_present => 0, light_res => "default", l_ncpl => undef, lnd_tuning_mode => "default", @@ -281,6 +270,7 @@ sub process_commandline { irrig => "default", res => "default", silent => 0, + ignore_warnings => 0, mask => "default", test => 0, bgc => "default", @@ -301,11 +291,11 @@ sub process_commandline { "envxml_dir=s" => \$opts{'envxml_dir'}, "drydep!" => \$opts{'drydep'}, "fire_emis!" => \$opts{'fire_emis'}, + "ignore_warnings!" => \$opts{'ignore_warnings'}, "chk_res!" => \$opts{'chk_res'}, "note!" => \$opts{'note'}, "megan!" => \$opts{'megan'}, "glc_nec=i" => \$opts{'glc_nec'}, - "glc_present!" => \$opts{'glc_present'}, "light_res=s" => \$opts{'light_res'}, "irrig=s" => \$opts{'irrig'}, "d:s" => \$opts{'dir'}, @@ -329,7 +319,7 @@ sub process_commandline { "test" => \$opts{'test'}, "use_case=s" => \$opts{'use_case'}, "bgc=s" => \$opts{'bgc'}, - "crop" => \$opts{'crop'}, + "crop!" => \$opts{'crop'}, "dynamic_vegetation" => \$opts{'dynamic_vegetation'}, "vichydro" => \$opts{'vichydro'}, "maxpft=i" => \$opts{'maxpft'}, @@ -350,59 +340,53 @@ sub process_commandline { #------------------------------------------------------------------------------- -sub set_print_level { - # Define print levels: - # 0 - only issue fatal error messages - # 1 - only informs what files are created (default) - # 2 - verbose - my %opts = %{shift()}; - if ($opts{'silent'}) { $verbosity = 0; } - if ($opts{'verbose'}) { $verbosity = 2; } -} - -#------------------------------------------------------------------------------- - sub check_for_perl_utils { my $cfgdir = shift; + my $opts_ref = shift; # Determine CESM root directory and perl5lib root directory my $cesmroot = abs_path( "$cfgdir/../../../"); my $perl5lib_dir = "$cesmroot/cime/utils/perl5lib"; + #----------------------------------------------------------------------------- + # Add $perl5lib_dir to the list of paths that Perl searches for modules + my @dirs = ( $ProgDir, $cfgdir, "$perl5lib_dir"); + unshift @INC, @dirs; + + require config_files::clm_phys_vers; + require namelist_files::LogMessages; + + my $locallog = namelist_files::LogMessages->new( $ProgName, $opts_ref ); # The XML::Lite module is required to parse the XML files. (-f "$perl5lib_dir/XML/Lite.pm") or - fatal_error("Cannot find perl module \"XML/Lite.pm\" in directory\n" . + $locallog->fatal_error("Cannot find perl module \"XML/Lite.pm\" in directory\n" . "\"$perl5lib_dir\""); # The Build::Config module provides utilities to access the configuration information # in the config_cache.xml file (-f "$perl5lib_dir/Build/Config.pm") or - fatal_error("Cannot find perl module \"Build/Config.pm\" in directory\n" . + $locallog->fatal_error("Cannot find perl module \"Build/Config.pm\" in directory\n" . "\"$perl5lib_dir\""); # The Build::NamelistDefinition module provides utilities to validate that the output # namelists are consistent with the namelist definition file (-f "$perl5lib_dir/Build/NamelistDefinition.pm") or - fatal_error("Cannot find perl module \"Build/NamelistDefinition.pm\" in directory\n" . + $locallog->fatal_error("Cannot find perl module \"Build/NamelistDefinition.pm\" in directory\n" . "\"$perl5lib_dir\""); # The Build::NamelistDefaults module provides a utility to obtain default values of namelist # variables based on finding a best fit with the attributes specified in the defaults file. (-f "$perl5lib_dir/Build/NamelistDefaults.pm") or - fatal_error("Cannot find perl module \"Build/NamelistDefaults.pm\" in directory\n" . + $locallog->fatal_error("Cannot find perl module \"Build/NamelistDefaults.pm\" in directory\n" . "\"$perl5lib_dir\""); # The Build::Namelist module provides utilities to parse input namelists, to query and modify # namelists, and to write output namelists. (-f "$perl5lib_dir/Build/Namelist.pm") or - fatal_error("Cannot find perl module \"Build/Namelist.pm\" in directory\n" . + $locallog->fatal_error("Cannot find perl module \"Build/Namelist.pm\" in directory\n" . "\"$perl5lib_dir\""); - #----------------------------------------------------------------------------- - # Add $perl5lib_dir to the list of paths that Perl searches for modules - my @dirs = ( $ProgDir, $cfgdir, "$perl5lib_dir"); - unshift @INC, @dirs; # required cesm perl modules require XML::Lite; @@ -410,7 +394,6 @@ sub check_for_perl_utils { require Build::NamelistDefinition; require Build::NamelistDefaults; require Build::Namelist; - require config_files::clm_phys_vers; require Config::SetupTools; } @@ -421,7 +404,7 @@ sub read_configure_definition { # configure are the build-time settings for CLM my ($cfgdir, $opts) = @_; - verbose_message("Setting CLM configuration script directory to $cfgdir"); + $log->verbose_message("Setting CLM configuration script directory to $cfgdir"); # Create a configuration object from the default config_definition file my $configfile; @@ -432,9 +415,9 @@ sub read_configure_definition { } # Check that configuration cache file exists. - verbose_message("Using CLM configuration cache file $opts->{'config'}"); + $log->verbose_message("Using CLM configuration cache file $opts->{'config'}"); if ( $configfile ne $opts->{'config'} ) { - fatal_error("Cannot find configuration cache file: \"$opts->{'config'}\"\n"); + $log->fatal_error("Cannot find configuration cache file: \"$opts->{'config'}\""); } my $cfg = Build::Config->new("$configfile"); @@ -445,19 +428,18 @@ sub read_configure_definition { #----------------------------------------------------------------------------------------------- sub read_namelist_definition { - my ($drvblddir, $opts, $nl_flags, $physv) = @_; + my ($cfgdir, $opts, $nl_flags, $physv) = @_; # The namelist definition file contains entries for all namelist # variables that can be output by build-namelist. my $phys = $physv->as_filename( ); - my @nl_definition_files = ( "$drvblddir/namelist_files/namelist_definition_drv.xml", - "$drvblddir/namelist_files/namelist_definition_modio.xml", - "$drvblddir/namelist_files/namelist_definition_drv_flds.xml", - "$nl_flags->{'cfgdir'}/namelist_files/namelist_definition_$phys.xml" ); + my @nl_definition_files = ( "$cfgdir/namelist_files/namelist_definition_drv.xml", + "$cfgdir/namelist_files/namelist_definition_drv_flds.xml", + "$cfgdir/namelist_files/namelist_definition_$phys.xml" ); foreach my $nl_defin_file ( @nl_definition_files ) { - (-f "$nl_defin_file") or fatal_error("Cannot find namelist definition file \"$nl_defin_file\"\n"); + (-f "$nl_defin_file") or $log->fatal_error("Cannot find namelist definition file \"$nl_defin_file\""); - verbose_message("Using namelist definition file $nl_defin_file"); + $log->verbose_message("Using namelist definition file $nl_defin_file"); } # Create a namelist definition object. This object provides a @@ -476,14 +458,14 @@ sub read_namelist_definition { sub read_envxml_case_files { # read the contents of the env*.xml files in the case directory my ($opts) = @_; - + my %envxml = (); if ( defined($opts->{'envxml_dir'}) ) { - (-d $opts->{'envxml_dir'}) or fatal_error( "envxml_dir is not a directory" ); + (-d $opts->{'envxml_dir'}) or $log->fatal_error( "envxml_dir is not a directory" ); my @files = glob( $opts->{'envxml_dir'}."/env_*xml" ); - ($#files >= 0) or fatal_error( "there are no env_*xml files in the envxml_dir" ); + ($#files >= 0) or $log->fatal_error( "there are no env_*xml files in the envxml_dir" ); foreach my $file (@files) { - verbose_message( "Open env.xml file: $file" ); + $log->verbose_message( "Open env.xml file: $file" ); my $xml = XML::Lite->new( "$file" ); my @e = $xml->elements_by_name('entry'); while ( my $e = shift @e ) { @@ -497,7 +479,7 @@ sub read_envxml_case_files { } } } else { - fatal_error( "The -envxml_dir option was NOT given and it is a REQUIRED option" ); + $log->fatal_error( "The -envxml_dir option was NOT given and it is a REQUIRED option" ); } return( %envxml ); } @@ -505,18 +487,18 @@ sub read_envxml_case_files { #----------------------------------------------------------------------------------------------- sub read_namelist_defaults { - my ($drvblddir, $opts, $nl_flags, $cfg, $physv) = @_; + my ($cfgdir, $opts, $nl_flags, $cfg, $physv) = @_; my $phys = $physv->as_filename( ); # The namelist defaults file contains default values for all required namelist variables. - my @nl_defaults_files = ( "$nl_flags->{'cfgdir'}/namelist_files/namelist_defaults_overall.xml", - "$nl_flags->{'cfgdir'}/namelist_files/namelist_defaults_$phys.xml", - "$drvblddir/namelist_files/namelist_defaults_drv.xml", - "$nl_flags->{'cfgdir'}/namelist_files/namelist_defaults_fire_emis.xml", - "$nl_flags->{'cfgdir'}/namelist_files/namelist_defaults_drydep.xml" ); + my @nl_defaults_files = ( "$cfgdir/namelist_files/namelist_defaults_overall.xml", + "$cfgdir/namelist_files/namelist_defaults_$phys.xml", + "$cfgdir/namelist_files/namelist_defaults_drv.xml", + "$cfgdir/namelist_files/namelist_defaults_fire_emis.xml", + "$cfgdir/namelist_files/namelist_defaults_drydep.xml" ); # Add the location of the use case defaults files to the options hash - $opts->{'use_case_dir'} = "$nl_flags->{'cfgdir'}/namelist_files/use_cases"; + $opts->{'use_case_dir'} = "$cfgdir/namelist_files/use_cases"; if (defined $opts->{'use_case'}) { if ( $opts->{'use_case'} ne "list" ) { @@ -525,9 +507,9 @@ sub read_namelist_defaults { } foreach my $nl_defaults_file ( @nl_defaults_files ) { - (-f "$nl_defaults_file") or fatal_error("Cannot find namelist defaults file \"$nl_defaults_file\"\n"); + (-f "$nl_defaults_file") or $log->fatal_error("Cannot find namelist defaults file \"$nl_defaults_file\""); - verbose_message("Using namelist defaults file $nl_defaults_file"); + $log->verbose_message("Using namelist defaults file $nl_defaults_file"); } # Create a namelist defaults object. This object provides default @@ -557,18 +539,18 @@ sub check_cesm_inputdata { $nl_flags->{'inputdata_rootdir'} = $ENV{'CSMDATA'}; } else { - fatal_error("CESM inputdata root directory must be specified by either -csmdata\n" . - "argument or by the CSMDATA environment variable.\n"); + $log->fatal_error("CESM inputdata root directory must be specified by either -csmdata\n" . + "argument or by the CSMDATA environment variable."); } if ( ! defined($ENV{'DIN_LOC_ROOT'}) ) { $ENV{'DIN_LOC_ROOT'} = $nl_flags->{'inputdata_rootdir'}; } if ($opts->{'test'}) { - (-d $nl_flags->{'inputdata_rootdir'}) or fatal_error("CESM inputdata root is not a directory: \"$nl_flags->{'inputdata_rootdir'}\"\n"); + (-d $nl_flags->{'inputdata_rootdir'}) or $log->fatal_error("CESM inputdata root is not a directory: \"$nl_flags->{'inputdata_rootdir'}\""); } - verbose_message("CESM inputdata root directory: $nl_flags->{'inputdata_rootdir'}"); + $log->verbose_message("CESM inputdata root directory: $nl_flags->{'inputdata_rootdir'}"); } #------------------------------------------------------------------------------- @@ -617,7 +599,7 @@ sub process_namelist_user_input { process_namelist_commandline_use_case($opts, $nl_flags, $definition, $defaults, $nl, $cfg, $envxml_ref, $physv); # Set the start_type by the command line setting for clm_start_type - process_namelist_commandline_clm_start_type($opts->{'test'}, $nl_flags, $definition, $defaults, $nl); + process_namelist_commandline_clm_start_type($opts, $nl_flags, $definition, $defaults, $nl); } @@ -647,10 +629,10 @@ sub process_namelist_commandline_options { setup_cmdl_irrigation($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_cmdl_rcp($opts, $nl_flags, $definition, $defaults, $nl); setup_cmdl_simulation_year($opts, $nl_flags, $definition, $defaults, $nl); - setup_cmdl_run_type($opts, $nl_flags, $definition, $defaults, $nl); setup_cmdl_dynamic_vegetation($opts, $nl_flags, $definition, $defaults, $nl, $physv); - setup_cmdl_ed_mode($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_cmdl_fates_mode($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_cmdl_vichydro($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_cmdl_run_type($opts, $nl_flags, $definition, $defaults, $nl); setup_cmdl_output_reals($opts, $nl_flags, $definition, $defaults, $nl, $physv); } @@ -678,14 +660,14 @@ sub setup_cmdl_resolution { } $nl_flags->{'res'} = $val; - verbose_message("CLM atm resolution is $nl_flags->{'res'}"); + $log->verbose_message("CLM atm resolution is $nl_flags->{'res'}"); $opts->{$var} = $val; if ( $opts->{'chk_res'} ) { $val = "e_string( $nl_flags->{'res'} ); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); if ( ! defined($opts->{'clm_usr_name'}) || $nl_flags->{'res'} ne $opts->{'clm_usr_name'} ) { - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } } @@ -714,14 +696,14 @@ sub setup_cmdl_mask { $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } - verbose_message("CLM land mask is $nl_flags->{'mask'}"); + $log->verbose_message("CLM land mask is $nl_flags->{'mask'}"); } #------------------------------------------------------------------------------- -sub setup_cmdl_ed_mode { +sub setup_cmdl_fates_mode { # # call this at least after crop check is called # @@ -731,35 +713,35 @@ sub setup_cmdl_ed_mode { my $var = "bgc_mode"; if ( $physv->as_long() == $physv->as_long("clm4_0") || $nl_flags->{'crop'} eq "on" ) { - if ( $nl_flags->{$var} eq "ed" ) { + if ( $nl_flags->{$var} eq "fates" ) { # ED is not a clm4_0 option and should not be used with crop and not with clm4_0 - fatal_error("** Cannot turn ed mode on with crop or with clm4_0 physics.\n" ); + $log->fatal_error("** Cannot turn fates mode on with crop or with clm4_0 physics." ); } - } elsif ($nl_flags->{"bgc_mode"} eq "ed" && $nl_flags->{"use_ed"} ne ".true.") { - fatal_error("DEV_ERROR: internal logic error: bgc_mode = ed and use_ed = false.\n"); - + } elsif ($nl_flags->{"bgc_mode"} eq "fates" && ! &value_is_true($nl_flags->{"use_fates"}) ) { + $log->fatal_error("DEV_ERROR: internal logic error: bgc_mode = fates and use_fates = false."); + } else { - $var = "use_ed"; - if ( $nl_flags->{$var} eq ".true." ) { + $var = "use_fates"; + if ( &value_is_true($nl_flags->{$var}) ) { # This section is a place-holder to test for modules that are not allowed with ED # the defaults which are set in the logic section of the namelist builder will # automatically set these correctly (well that is the assumption), but here we # want to set a catch to fail and warn users if they explicitly set incompatible user namelist # options - + # my $var = "use_somevar"; # $val = $nl_flags->{$var}; # if ( defined($nl->get_value($var)) ) { -# if ( $nl->get_value($var) == ".true." ) { -# fatal_error("$var was set to .true., which is incompatible when -bgc ed option is used.\n"); +# if ( &value_is_true($nl->get_value($var)) ) { +# $log->fatal_error("$var was set to .true., which is incompatible when -bgc fates option is used."); # } # } - - # The following variables may be set by the user and are compatible with use_ed + + # The following variables may be set by the user and are compatible with use_fates # no need to set defaults, covered in a different routine - my @list = ( "use_ed_spit_fire", "use_vertsoilc", "use_century_decomp", "use_lch4" ); + my @list = ( "use_fates_spitfire", "use_vertsoilc", "use_century_decomp", "use_lch4" ); foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { $nl_flags->{$var} = $nl->get_value($var); @@ -768,19 +750,19 @@ sub setup_cmdl_ed_mode { $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } } -# add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_vertsoilc', 'use_ed'=>$nl_flags->{'use_ed'} ); +# add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_vertsoilc', 'use_fates'=>$nl_flags->{'use_fates'} ); } else { - # we only dis-allow ed_spit_fire with non-ed runs - $var = "use_ed_spit_fire"; + # we only dis-allow fates_spit_fire with non-fates runs + $var = "use_fates_spitfire"; if ( defined($nl->get_value($var)) ) { - fatal_error("$var is being set, but can ONLY be set when -bgc ed option is used.\n"); + $log->fatal_error("$var is being set, but can ONLY be set when -bgc fates option is used."); } } } @@ -800,7 +782,7 @@ sub setup_cmdl_bgc { if ( $physv->as_long() == $physv->as_long("clm4_0") ) { if ( $nl_flags->{'bgc_mode'} ne "default" ) { - fatal_error("-bgc option used with clm4_0 physics. -bgc can ONLY be used with clm4_5/clm5_0 physics"); + $log->fatal_error("-bgc option used with clm4_0 physics. -bgc can ONLY be used with clm4_5/clm5_0 physics"); } $nl_flags->{'bgc_mode'} = $cfg->get($var); } else { @@ -812,29 +794,29 @@ sub setup_cmdl_bgc { $nl->set_variable_value($group, $var, quote_string( $nl_flags->{$var} ) ); if ( ! $definition->is_valid_value( $var, quote_string( $nl_flags->{$var}) ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values"); } - verbose_message("Using $nl_flags->{$var} for bgc."); + $log->verbose_message("Using $nl_flags->{$var} for bgc."); # now set the actual name list variables based on the bgc alias if ($nl_flags->{$var} eq "cn" ) { $nl_flags->{'use_cn'} = ".true."; - $nl_flags->{'use_ed'} = ".false."; + $nl_flags->{'use_fates'} = ".false."; } elsif ($nl_flags->{$var} eq "bgc" ) { $nl_flags->{'use_cn'} = ".true."; - $nl_flags->{'use_ed'} = ".false."; - } elsif ($nl_flags->{$var} eq "ed" ) { + $nl_flags->{'use_fates'} = ".false."; + } elsif ($nl_flags->{$var} eq "fates" ) { $nl_flags->{'use_cn'} = ".false."; - $nl_flags->{'use_ed'} = ".true."; + $nl_flags->{'use_fates'} = ".true."; } else { $nl_flags->{'use_cn'} = ".false."; - $nl_flags->{'use_ed'} = ".false."; + $nl_flags->{'use_fates'} = ".false."; } if ( defined($nl->get_value("use_cn")) && ($nl_flags->{'use_cn'} ne $nl->get_value("use_cn")) ) { - fatal_error("The namelist variable use_cn is inconsistent with the -bgc option"); + $log->fatal_error("The namelist variable use_cn is inconsistent with the -bgc option"); } - if ( defined($nl->get_value("use_ed")) && ($nl_flags->{'use_ed'} ne $nl->get_value("use_ed")) ) { - fatal_error("The namelist variable use_ed is inconsistent with the -bgc option"); + if ( defined($nl->get_value("use_fates")) && ($nl_flags->{'use_fates'} ne $nl->get_value("use_fates")) ) { + $log->fatal_error("The namelist variable use_fates is inconsistent with the -bgc option"); } { @@ -857,35 +839,35 @@ sub setup_cmdl_bgc { $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } # If all the variables are different report it as an error if ( $ndiff == ($#list + 1) ) { - fatal_error("You are contradicting the -bgc setting with the namelist variables: @list" ); + $log->fatal_error("You are contradicting the -bgc setting with the namelist variables: @list" ); } } - # Now set use_cn and use_ed - foreach $var ( "use_cn", "use_ed" ) { + # Now set use_cn and use_fates + foreach $var ( "use_cn", "use_fates" ) { $val = $nl_flags->{$var}; $group = $definition->get_group_name($var); $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } } if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { my $var = "use_fun"; if ( ! defined($nl->get_value($var)) ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'use_nitrif_denitrif'=>$nl_flags->{'use_nitrif_denitrif'} ); } - if ( (! value_is_true($nl_flags->{'use_nitrif_denitrif'}) ) && value_is_true($nl->get_value('use_fun')) ) { - fatal_error("When FUN is on, use_nitrif_denitrif MUST also be on!\n"); + if ( (! &value_is_true($nl_flags->{'use_nitrif_denitrif'}) ) && &value_is_true($nl->get_value('use_fun')) ) { + $log->fatal_error("When FUN is on, use_nitrif_denitrif MUST also be on!"); } } } # end bgc @@ -901,7 +883,7 @@ sub setup_cmdl_fire_light_res { my $val = $opts->{$var}; if ( $physv->as_long() == $physv->as_long("clm4_0") ) { if ( $val !~ /default|none/ ) { - fatal_error("-$var option used with clm4_0 physics. -$var can ONLY be used with clm4_5/clm5_0 physics"); + $log->fatal_error("-$var option used with clm4_0 physics. -$var can ONLY be used with clm4_5/clm5_0 physics"); } } else { if ( $val eq "default" ) { @@ -910,15 +892,18 @@ sub setup_cmdl_fire_light_res { my $fire_method = remove_leading_and_trailing_quotes( $nl->get_value('fire_method') ); if ( defined($fire_method) && $val ne "none" ) { if ( $fire_method eq "nofire" ) { - fatal_error("-$var option used with fire_method='nofire'. -$var can ONLY be used without the nofire option"); + $log->fatal_error("-$var option used with fire_method='nofire'. -$var can ONLY be used without the nofire option"); } } my $stream_fldfilename_lightng = remove_leading_and_trailing_quotes( $nl->get_value('stream_fldfilename_lightng') ); if ( defined($stream_fldfilename_lightng) && $val ne "none" ) { - fatal_error("-$var option used while also explicitly setting stream_fldfilename_lightng filename which is a contradiction. Use one or the other not both."); + $log->fatal_error("-$var option used while also explicitly setting stream_fldfilename_lightng filename which is a contradiction. Use one or the other not both."); } if ( ! &value_is_true($nl->get_value('use_cn')) ) { - fatal_error("-$var option used CN is NOT on. -$var can only be used when CN is on (with bgc: cn or bgc)"); + $log->fatal_error("-$var option used CN is NOT on. -$var can only be used when CN is on (with bgc: cn or bgc)"); + } + if ( &value_is_true($nl->get_value('use_cn')) && $val eq "none" ) { + $log->fatal_error("-$var option is set to none, but CN is on (with bgc: cn or bgc) which is a contradiction"); } $nl_flags->{$var} = $val; } @@ -926,19 +911,19 @@ sub setup_cmdl_fire_light_res { $nl->set_variable_value($group, $var, quote_string($nl_flags->{$var}) ); if ( ! $definition->is_valid_value( $var, $nl_flags->{$var}, 'noquotes'=>1 ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values"); } - verbose_message("Using $nl_flags->{$var} for $var."); + $log->verbose_message("Using $nl_flags->{$var} for $var."); # # Set flag if cn-fires are on or not # $var = "cnfireson"; if ( $physv->as_long() >= $physv->as_long("clm4_5") && &value_is_true($nl->get_value('use_cn')) ) { - add_default($opts->{'test_files'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_method'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_method'); } my $fire_method = remove_leading_and_trailing_quotes( $nl->get_value('fire_method') ); - if ( defined($fire_method) && ! value_is_true($nl_flags->{'use_cn'}) ) { - fatal_error("fire_method is being set even though bgc is NOT cn or bgc.\n"); + if ( defined($fire_method) && ! &value_is_true($nl_flags->{'use_cn'}) ) { + $log->fatal_error("fire_method is being set even though bgc is NOT cn or bgc."); } if ( defined($fire_method) && $fire_method eq "nofire" ) { $nl_flags->{$var} = ".false."; @@ -970,14 +955,14 @@ sub setup_cmdl_crop { $nl_flags->{'use_crop'} = ".true."; } if ( defined($nl->get_value("use_crop")) && ($nl_flags->{'use_crop'} ne $nl->get_value("use_crop")) ) { - fatal_error("Namelist item use_crop contradicts the command-line option -crop, use the command line option"); + $log->fatal_error("Namelist item use_crop contradicts the command-line option -crop, use the command line option"); } if ( ($nl_flags->{'crop'} eq 1 ) && ($nl_flags->{'bgc_mode'} eq "sp") ) { - fatal_error("** Cannot turn crop mode on mode bgc=sp\n" . + $log->fatal_error("** Cannot turn crop mode on mode bgc=sp\n" . "**\n" . "** Set the bgc mode to 'cn' or 'bgc' by the following means from highest to lowest precedence:\n" . "** * by the command-line options -bgc cn\n" . - "** * by a default configuration file, specified by -defaults\n"); + "** * by a default configuration file, specified by -defaults"); } $var = "use_crop"; @@ -989,7 +974,7 @@ sub setup_cmdl_crop { $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } } @@ -1016,27 +1001,27 @@ sub setup_cmdl_maxpft { $nl_flags->{'maxpft'} = $val; if ( ($nl_flags->{'bgc_mode'} ne "sp") && ($nl_flags->{'maxpft'} != $maxpatchpft{$nl_flags->{'use_crop'}}) ) { - fatal_error("** For CN or BGC mode you MUST set max patch PFT's to $maxpatchpft{$nl_flags->{'use_crop'}}\n" . + $log->fatal_error("** For CN or BGC mode you MUST set max patch PFT's to $maxpatchpft{$nl_flags->{'use_crop'}}\n" . "**\n" . "** When the crop model is on then it must be set to $maxpatchpft{'crop'} otherwise to $maxpatchpft{'nocrop'}\n" . "** Set the bgc mode, crop and maxpft by the following means from highest to lowest precedence:\n" . "** * by the command-line options -bgc, -crop and -maxpft\n" . "** * by a default configuration file, specified by -defaults\n" . - "**\n"); + "**"); } if ( $nl_flags->{'maxpft'} > $maxpatchpft{$nl_flags->{'use_crop'}} ) { - fatal_error("** Max patch PFT's can NOT exceed $maxpatchpft{$nl_flags->{'use_crop'}}\n" . + $log->fatal_error("** Max patch PFT's can NOT exceed $maxpatchpft{$nl_flags->{'use_crop'}}\n" . "**\n" . "** Set maxpft by the following means from highest to lowest precedence:\n" . "** * by the command-line options -maxpft\n" . "** * by a default configuration file, specified by -defaults\n" . - "**\n"); + "**"); } if ( $nl_flags->{'maxpft'} != $maxpatchpft{$nl_flags->{'use_crop'}} ) { - warning("running with maxpft NOT equal to $maxpatchpft{$nl_flags->{'use_crop'}} is " . - "NOT validated / scientifically supported.\n"); + $log->warning("running with maxpft NOT equal to $maxpatchpft{$nl_flags->{'use_crop'}} is " . + "NOT validated / scientifically supported." ); } - verbose_message("Using $nl_flags->{'maxpft'} for maxpft."); + $log->verbose_message("Using $nl_flags->{'maxpft'} for maxpft."); $var = "maxpatch_pft"; $val = $nl_flags->{'maxpft'}; @@ -1044,7 +1029,7 @@ sub setup_cmdl_maxpft { $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } } @@ -1069,9 +1054,9 @@ sub setup_cmdl_glc_nec { $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } - verbose_message("Glacier number of elevation classes is $val"); + $log->verbose_message("Glacier number of elevation classes is $val"); } #------------------------------------------------------------------------------- @@ -1083,37 +1068,31 @@ sub setup_cmdl_irrigation { my $var = "irrig"; if ( $opts->{$var} eq "default" ) { - $nl_flags->{$var} = $defaults->get_value($var); + my %settings; + $settings{'use_crop'} = $nl_flags->{'use_crop'}; + $nl_flags->{$var} = $defaults->get_value($var, \%settings); } else { $nl_flags->{$var} = $opts->{$var}; } my $val = $nl_flags->{$var}; - my $group = $definition->get_group_name($var); - $nl->set_variable_value($group, $var, $val); - if ( ! $definition->is_valid_value( $var, $val ) ) { - my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); - } - verbose_message("Irrigation $val"); if ( $physv->as_long() == $physv->as_long("clm4_0") ) { - if ( $nl_flags->{'irrig'} =~ /$TRUE/i && $nl_flags->{'use_crop'} eq ".true." ) { - fatal_error("You've turned on both irrigation and crop.\n" . + my $group = $definition->get_group_name($var); + $nl->set_variable_value($group, $var, $val); + if ( ! $definition->is_valid_value( $var, $val ) ) { + my @valid_values = $definition->get_valid_values( $var ); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); + } + $log->verbose_message("Irrigation $val"); + if ( &value_is_true($nl_flags->{'irrig'}) && &value_is_true($nl_flags->{'use_crop'}) ) { + $log->fatal_error("You've turned on both irrigation and crop.\n" . "Irrigation is only applied to generic crop currently,\n" . "which negates it's practical usage.\n." . "We also have a known problem when both are on " . "(see bug 1326 in the components/clm/doc/KnownBugs file)\n" . - "both irrigation and crop can NOT be on.\n"); - } - } else { - if ( $nl_flags->{'irrig'} =~ /$TRUE/i && $nl_flags->{'use_crop'} =~ /$FALSE/i ) { - fatal_error("The -irrig=.true. option requires -crop"); - } - if ( defined($nl->get_value("irrigate")) && $nl->get_value("irrigate") ne $nl_flags->{'irrig'} ) { - my $irrigate = $nl->get_value("irrigate"); - fatal_error("The namelist value 'irrigate=$irrigate' contradicts the command line option '-irrig=$val'\n." . - "Please set 'irrigate' in user_nl_clm AND '-irrig' in env_run.xml CLM_BLDNML_OPTS to the same value ('.true.' or '.false.')!\n"); - + "both irrigation and crop can NOT be on."); } + } elsif ( $opts->{$var} ne "default" ) { + $log->fatal_error("The -irrig option can ONLY be used with clm4_0 physics"); } } @@ -1136,9 +1115,9 @@ sub setup_cmdl_rcp { $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } - verbose_message("CLM future scenario representative concentration is $nl_flags->{'rcp'}"); + $log->verbose_message("CLM future scenario representative concentration is $nl_flags->{'rcp'}"); } #------------------------------------------------------------------------------- @@ -1162,25 +1141,26 @@ sub setup_cmdl_spinup { $nl->set_variable_value($group, $var, quote_string($val) ); if ( ! $definition->is_valid_value( $var, $val , 'noquotes' => 1) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has an invalid value ($val). Valid values are: @valid_values\n"); + $log->fatal_error("$var has an invalid value ($val). Valid values are: @valid_values"); } - verbose_message("CLM accelerated spinup mode is $val"); + $log->verbose_message("CLM accelerated spinup mode is $val"); if ( $physv->as_long() == $physv->as_long("clm4_0") ) { $nl_flags->{'spinup'} = $cfg->get('spinup'); } elsif ( $physv->as_long() >= $physv->as_long("clm4_5")) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "spinup_state", clm_accelerated_spinup=>$nl_flags->{$var}, - use_cn=>$nl_flags->{'use_cn'}, use_ed=>$nl_flags->{'use_ed'} ); + use_cn=>$nl_flags->{'use_cn'}, use_fates=>$nl_flags->{'use_fates'} ); if ( $nl->get_value("spinup_state") ne 0 ) { $nl_flags->{'bgc_spinup'} = "on"; if ( $nl_flags->{'bgc_mode'} eq "sp" ) { - fatal_error("spinup_state is accelerated (=1 or 2) which is for a BGC mode of CN or BGC," . - " but the BGC mode is Satellite Phenology, change one or the other\n"); + $log->fatal_error("spinup_state is accelerated (=1 or 2) which is for a BGC mode of CN or BGC," . + " but the BGC mode is Satellite Phenology, change one or the other"); } if ( $nl_flags->{'clm_accelerated_spinup'} eq "off" ) { - fatal_error("spinup_state is accelerated, but clm_accelerated_spinup is off, change one or the other\n"); + $log->fatal_error("spinup_state is accelerated, but clm_accelerated_spinup is off, change one or the other"); } } else { + $nl_flags->{'bgc_spinup'} = "off"; $val = $defaults->get_value($var); } $nl_flags->{$var} = $val; @@ -1188,16 +1168,16 @@ sub setup_cmdl_spinup { $nl->set_variable_value($group, $var, quote_string($val) ); if ( ! $definition->is_valid_value( $var, $val , 'noquotes' => 1) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has an invalid value ($val). Valid values are: @valid_values\n"); + $log->fatal_error("$var has an invalid value ($val). Valid values are: @valid_values"); } - if ( $nl_flags->{'bgc_spinup'} eq "on" && (not value_is_true( $nl_flags->{'use_cn'} )) && (not value_is_true($nl_flags->{'use_ed'})) ) { - fatal_error("$var can not be '$nl_flags->{'bgc_spinup'}' if neither CN nor ED is turned on (use_cn=$nl_flags->{'use_cn'}, use_ed=$nl_flags->{'use_ed'})."); + if ( $nl_flags->{'bgc_spinup'} eq "on" && (not &value_is_true( $nl_flags->{'use_cn'} )) && (not &value_is_true($nl_flags->{'use_fates'})) ) { + $log->fatal_error("$var can not be '$nl_flags->{'bgc_spinup'}' if neither CN nor ED is turned on (use_cn=$nl_flags->{'use_cn'}, use_fates=$nl_flags->{'use_fates'})."); } if ( $nl->get_value("spinup_state") eq 0 && $nl_flags->{'bgc_spinup'} eq "on" ) { - fatal_error("Namelist spinup_state contradicts the command line option bgc_spinup" ); + $log->fatal_error("Namelist spinup_state contradicts the command line option bgc_spinup" ); } if ( $nl->get_value("spinup_state") eq 1 && $nl_flags->{'bgc_spinup'} eq "off" ) { - fatal_error("Namelist spinup_state contradicts the command line option bgc_spinup" ); + $log->fatal_error("Namelist spinup_state contradicts the command line option bgc_spinup" ); } } @@ -1206,7 +1186,7 @@ sub setup_cmdl_spinup { } else { $val = $nl_flags->{'bgc_spinup'}; } - verbose_message("CLM CN bgc_spinup mode is $val"); + $log->verbose_message("CLM CN bgc_spinup mode is $val"); } #------------------------------------------------------------------------------- @@ -1233,10 +1213,10 @@ sub setup_cmdl_simulation_year { $nl->set_variable_value($group, $var, $val ); if ( ! $definition->is_valid_value( $var, $val, 'noquotes'=>1 ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var of $val is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var of $val is NOT valid. Valid values are: @valid_values"); } $nl->set_variable_value($group, $var, $val ); - verbose_message("CLM sim_year is $nl_flags->{'sim_year'}"); + $log->verbose_message("CLM sim_year is $nl_flags->{'sim_year'}"); $var = "sim_year_range"; $val = $nl_flags->{'sim_year_range'}; @@ -1246,11 +1226,11 @@ sub setup_cmdl_simulation_year { $nl->set_variable_value($group, $var, $val ); if ( ! $definition->is_valid_value( $var, $val, 'noquotes'=>1 ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var of $val is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var of $val is NOT valid. Valid values are: @valid_values"); } $val = "'".$defaults->get_value($var)."'"; $nl->set_variable_value($group, $var, $val ); - verbose_message("CLM sim_year_range is $nl_flags->{'sim_year_range'}"); + $log->verbose_message("CLM sim_year_range is $nl_flags->{'sim_year_range'}"); } } @@ -1263,13 +1243,15 @@ sub setup_cmdl_run_type { my $var = "clm_start_type"; if (defined $opts->{$var}) { if ($opts->{$var} eq "default" ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'use_cndv'=>$nl_flags->{'use_cndv'} ); } else { my $group = $definition->get_group_name($var); $nl->set_variable_value($group, $var, quote_string( $opts->{$var} ) ); } } else { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'use_cndv'=>$nl_flags->{'use_cndv'} ); } $nl_flags->{'clm_start_type'} = $nl->get_value($var); } @@ -1286,13 +1268,13 @@ sub setup_cmdl_dynamic_vegetation { if ( $physv->as_long() == $physv->as_long("clm4_0") ) { # not applicable if ( $nl_flags->{'dynamic_vegetation'}eq 1) { - fatal_error("** Turn dynamic_vegetation mode on with CLM_CONFIG_OPTS (-bgc cndv) for clm4_0 physics.\n" ); + $log->fatal_error("** Turn dynamic_vegetation mode on with CLM_CONFIG_OPTS (-bgc cndv) for clm4_0 physics." ); } } else { if ( ($nl_flags->{'dynamic_vegetation'} eq 1 ) && ($nl_flags->{'bgc_mode'} eq "sp") ) { - fatal_error("** Cannot turn dynamic_vegetation mode on with bgc=sp.\n" . + $log->fatal_error("** Cannot turn dynamic_vegetation mode on with bgc=sp.\n" . "**\n" . - "** Set the bgc mode to 'cn' or 'bgc' by the following means from highest to lowest precedence:\n" . + "** Set the bgc mode to 'cn' or 'bgc' by the following means from highest to lowest precedence:" . "** * by the command-line options -bgc cn\n"); } @@ -1303,14 +1285,14 @@ sub setup_cmdl_dynamic_vegetation { $nl_flags->{$var} = $val; } if ( defined($nl->get_value($var)) && $nl->get_value($var) ne $val ) { - fatal_error("$var is inconsistent with the commandline setting of -dynamic_vegetation"); + $log->fatal_error("$var is inconsistent with the commandline setting of -dynamic_vegetation"); } - if ( $nl_flags->{$var} eq ".true." ) { + if ( &value_is_true($nl_flags->{$var}) ) { my $group = $definition->get_group_name($var); $nl->set_variable_value($group, $var, $val); if ( ! $definition->is_valid_value( $var, $val ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } } @@ -1324,7 +1306,7 @@ sub setup_cmdl_output_reals { my $file = $opts->{$var}; if ( defined($file) ) { # Make sure can open file and if not die with an error - my $fh = IO::File->new($file, '>') or fatal_error("can't create real parameter filename: $file"); + my $fh = IO::File->new($file, '>') or $log->fatal_error("can't create real parameter filename: $file"); $fh->close(); } } @@ -1341,11 +1323,11 @@ sub setup_cmdl_vichydro { if ( $physv->as_long() == $physv->as_long("clm4_0") ) { # not relevant in clm4_0 if ( $nl_flags->{'vichydro'}eq 1) { - fatal_error("** Cannot turn vichydro on with clm4_0 physics.\n" ); + $log->fatal_error("** Cannot turn vichydro on with clm4_0 physics." ); } } else { if ($nl_flags->{'vichydro'} eq 1) { - message("Using VIC hydrology for runoff calculations."); + $log->verbose_message("Using VIC hydrology for runoff calculations."); } $var = "use_vichydro"; @@ -1354,12 +1336,12 @@ sub setup_cmdl_vichydro { my $group = $definition->get_group_name($var); my $set = ".true."; if ( defined($val) && $set ne $val ) { - fatal_error("$var contradicts the command-line -vichydro option" ); + $log->fatal_error("$var contradicts the command-line -vichydro option" ); } $nl->set_variable_value($group, $var, $set); if ( ! $definition->is_valid_value($var, $val) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value ($val) that is NOT valid. Valid values are: @valid_values"); } } } @@ -1380,7 +1362,7 @@ sub process_namelist_commandline_namelist { my $nl_arg_valid; eval { $nl_arg_valid = $definition->validate($nl_arg); }; if ($@) { - fatal_error("Invalid namelist variable in commandline arg '-namelist'.\n $@"); + $log->fatal_error("Invalid namelist variable in commandline arg '-namelist'.\n $@"); } # Go through all variables and expand any XML env settings in them expand_xml_variables_in_namelist( $nl_arg_valid, $envxml_ref ); @@ -1404,7 +1386,7 @@ sub process_namelist_commandline_infile { if ( -f "$infile" ) { # Otherwise abort as a valid file doesn't exist } else { - fatal_error("input namelist file does NOT exist $infile.\n $@"); + $log->fatal_error("input namelist file does NOT exist $infile.\n $@"); } # Parse namelist input from the next file my $nl_infile = Build::Namelist->new($infile); @@ -1413,7 +1395,7 @@ sub process_namelist_commandline_infile { my $nl_infile_valid; eval { $nl_infile_valid = $definition->validate($nl_infile); }; if ($@) { - fatal_error("Invalid namelist variable in '-infile' $infile.\n $@"); + $log->fatal_error("Invalid namelist variable in '-infile' $infile.\n $@"); } # Go through all variables and expand any XML env settings in them expand_xml_variables_in_namelist( $nl_infile_valid, $envxml_ref ); @@ -1461,13 +1443,13 @@ sub process_namelist_commandline_clm_usr_name { my $val = $uf_defaults->get_usr_file($var, $definition, \%settings); if ($val) { - message("adding clm user file defaults for var $var with val $val"); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl_usrfile, $var, 'val'=>$val); + $log->message("adding clm user file defaults for var $var with val $val"); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl_usrfile, $var, 'val'=>$val); $nvars++; } } if ( $nvars == 0 ) { - warning("setting clm_usr_name -- but did NOT find any user datasets: $opts->{'clm_usr_name'}\n"); + $log->message("setting clm_usr_name -- but did NOT find any user datasets: $opts->{'clm_usr_name'}", $opts); } # Go through all variables and expand any XML env settings in them expand_xml_variables_in_namelist( $nl_usrfile, $envxml_ref ); @@ -1498,6 +1480,8 @@ sub process_namelist_commandline_use_case { $settings{'phys'} = $nl_flags->{'phys'}; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { $settings{'use_cn'} = $nl_flags->{'use_cn'}; + $settings{'use_cndv'} = $nl_flags->{'use_cndv'}; + $settings{'use_crop'} = $nl_flags->{'use_crop'}; $settings{'cnfireson'} = $nl_flags->{'cnfireson'}; } else { $settings{'bgc'} = $nl_flags->{'bgc_mode'}; @@ -1510,9 +1494,9 @@ sub process_namelist_commandline_use_case { my $val = $uc_defaults->get_value($var, \%settings ); if ( defined($val) ) { - message("CLM adding use_case $opts->{'use_case'} defaults for var '$var' with val '$val'"); + $log->message("CLM adding use_case $opts->{'use_case'} defaults for var '$var' with val '$val'"); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl_usecase, $var, 'val'=>$val); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl_usecase, $var, 'val'=>$val); } } # Go through all variables and expand any XML env settings in them @@ -1529,16 +1513,16 @@ sub process_namelist_commandline_use_case { sub process_namelist_commandline_clm_start_type { # Set the start_type according to the command line clm_start_type option - my ($test_files, $nl_flags, $definition, $defaults, $nl) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; # Run type for driver namelist - note that arb_ic implies that the run is startup my $var = "start_type"; if ($nl_flags->{'clm_start_type'} eq "'cold'" || $nl_flags->{'clm_start_type'} eq "'arb_ic'") { # Add default is used here, but the value is explicitly set - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>'startup' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>'startup' ); } else { # Add default is used here, but the value is explicitly set - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$nl_flags->{'clm_start_type'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$nl_flags->{'clm_start_type'} ); } } @@ -1558,75 +1542,80 @@ sub process_namelist_inline_logic { setup_logic_lnd_frac($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref); setup_logic_co2_type($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_irrigate($opts, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_start_type($nl_flags, $nl); + setup_logic_start_type($opts, $nl_flags, $nl); setup_logic_delta_time($opts, $nl_flags, $definition, $defaults, $nl); - setup_logic_decomp_performance($opts->{'test'}, $nl_flags, $definition, $defaults, $nl); - setup_logic_snow($opts->{'test_files'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_decomp_performance($opts, $nl_flags, $definition, $defaults, $nl); + setup_logic_snow($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_glacier($opts, $nl_flags, $definition, $defaults, $nl, $envxml_ref, $physv); - setup_logic_dynamic_plant_nitrogen_alloc($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_luna($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_hillslope($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_hydrstress($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_dynamic_roots($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_params_file($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_create_crop_landunit($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_fertilizer($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_grainproduct($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_soilstate($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_dynamic_plant_nitrogen_alloc($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_luna($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_hillslope($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_hydrstress($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_dynamic_roots($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_params_file($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_create_crop_landunit($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_fertilizer($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_grainproduct($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_soilstate($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_demand($opts, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_surface_dataset($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_surface_dataset($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_initial_conditions($opts, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_dynamic_subgrid($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_spinup($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_supplemental_nitrogen($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_snowpack($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_ed($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_dynamic_subgrid($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_spinup($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_supplemental_nitrogen($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_snowpack($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_fates($opts, $nl_flags, $definition, $defaults, $nl, $physv); ######################################### # namelist group: atm2lnd_inparm ######################################### - setup_logic_atm_forcing($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_atm_forcing($opts, $nl_flags, $definition, $defaults, $nl, $physv); + + ######################################### + # namelist group: lnd2atm_inparm + ######################################### + setup_logic_lnd2atm($opts, $nl_flags, $definition, $defaults, $nl, $physv); ######################################### # namelist group: clm_humanindex_inparm # ######################################### - setup_logic_humanindex($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_humanindex($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################# # namelist group: cnfire_inparm # ################################# - setup_logic_cnfire($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_cnfire($opts, $nl_flags, $definition, $defaults, $nl, $physv); ###################################### # namelist group: cnprecision_inparm # ###################################### - setup_logic_cnprec($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_cnprec($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################### # namelist group: clmu_inparm # ############################### - setup_logic_urban($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_urban($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################### # namelist group: crop # ############################### - setup_logic_crop($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_crop($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################### # namelist group: ch4par_in # ############################### - setup_logic_methane($opts->{'test'}, $nl_flags, $definition, $defaults, $nl); - setup_logic_c_isotope($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_methane($opts, $nl_flags, $definition, $defaults, $nl); + setup_logic_c_isotope($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################### # namelist group: ndepdyn_nml # ############################### - setup_logic_nitrogen_deposition($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_nitrogen_deposition($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################## # namelist group: cnmresp_inparm # ################################## - setup_logic_cnmresp($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_cnmresp($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################# # namelist group: nitrif_inparm # @@ -1636,22 +1625,22 @@ sub process_namelist_inline_logic { #################################### # namelist group: photosyns_inparm # #################################### - setup_logic_photosyns($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_photosyns($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################# # namelist group: popd_streams # ################################# - setup_logic_popd_streams($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_popd_streams($opts, $nl_flags, $definition, $defaults, $nl, $physv); #################################### # namelist group: urbantv_streams # #################################### - setup_logic_urbantv_streams($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_urbantv_streams($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################## # namelist group: light_streams # ################################## - setup_logic_lightning_streams($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_lightning_streams($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################# # namelist group: drydep_inparm # @@ -1671,67 +1660,72 @@ sub process_namelist_inline_logic { ################################## # namelist group: lai_streams # ################################## - setup_logic_lai_streams($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_lai_streams($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################## # namelist group: bgc_shared ################################## - setup_logic_bgc_shared($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_bgc_shared($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################################# # namelist group: soilwater_movement_inparm # ############################################# - setup_logic_soilwater_movement($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_soilwater_movement($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################################# # namelist group: rooting_profile_inparm # ############################################# - setup_logic_rooting_profile($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_rooting_profile($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################################# # namelist group: friction_velocity # ############################################# - setup_logic_friction_vel($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_friction_vel($opts, $nl_flags, $definition, $defaults, $nl, $physv); ################################################ # namelist group: century_soilbgcdecompcascade # ################################################ - setup_logic_century_soilbgcdecompcascade($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_century_soilbgcdecompcascade($opts, $nl_flags, $definition, $defaults, $nl, $physv); + + #################################### + # namelist group: cnvegcarbonstate # + #################################### + setup_logic_cnvegcarbonstate($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################################# # namelist group: soil_resis_inparm # ############################################# - setup_logic_soil_resis($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_soil_resis($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################################# # namelist group: hillslope_hydrology_inparm # ############################################# - setup_logic_hillslope_hydrology($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_hillslope_hydrology($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################################# # namelist group: canopyfluxes_inparm # ############################################# - setup_logic_canopyfluxes($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_canopyfluxes($opts, $nl_flags, $definition, $defaults, $nl, $physv); ############################################# # namelist group: canopyhydrology_inparm # ############################################# - setup_logic_canopyhydrology($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_canopyhydrology($opts, $nl_flags, $definition, $defaults, $nl, $physv); ##################################### # namelist group: clm_canopy_inparm # ##################################### - setup_logic_canopy($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_canopy($opts, $nl_flags, $definition, $defaults, $nl, $physv); ######################################## # namelist group: soilhydrology_inparm # ######################################## - setup_logic_hydrology_params($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_hydrology_params($opts, $nl_flags, $definition, $defaults, $nl, $physv); ##################################### # namelist group: irrigation_inparm # ##################################### - setup_logic_irrigation_parameters($opts->{'test'}, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_irrigation_parameters($opts, $nl_flags, $definition, $defaults, $nl, $physv); ####################################################################### # namelist groups: clm_hydrology1_inparm and clm_soilhydrology_inparm # @@ -1769,14 +1763,14 @@ sub setup_logic_site_specific { } if ( $physv->as_long() >= $physv->as_long("clm4_5") && $nl_flags->{'res'} eq "1x1_smallvilleIA") { - if ($nl_flags->{'use_cn'} ne ".true." || $nl_flags->{'use_crop'} ne ".true.") { - fatal_error("1x1_smallvilleIA grids must use a compset with CN and CROP turned on.\n"); + if (! &value_is_true($nl_flags->{'use_cn'}) || ! &value_is_true($nl_flags->{'use_crop'})) { + $log->fatal_error("1x1_smallvilleIA grids must use a compset with CN and CROP turned on."); } } if ( $physv->as_long() >= $physv->as_long("clm4_5") && $nl_flags->{'res'} eq "1x1_numaIA") { - if ($nl_flags->{'use_cn'} ne ".true." || $nl_flags->{'use_crop'} ne ".true.") { - fatal_error("1x1_numaIA grids must use a compset with CN and CROP turned on.\n"); + if (! &value_is_true($nl_flags->{'use_cn'}) || ! &value_is_true($nl_flags->{'use_crop'})) { + $log->fatal_error("1x1_numaIA grids must use a compset with CN and CROP turned on."); } } } @@ -1799,12 +1793,12 @@ sub setup_logic_lnd_tuning { $nl->set_variable_value($group, $var, quote_string( $nl_flags->{$var} ) ); if ( ! $definition->is_valid_value( $var, quote_string( $nl_flags->{$var}) ) ) { my @valid_values = $definition->get_valid_values( $var ); - fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values\n"); + $log->fatal_error("$var has a value (".$nl_flags->{$var}.") that is NOT valid. Valid values are: @valid_values"); } - verbose_message("Using $nl_flags->{$var} for lnd_tuning_mode"); + $log->verbose_message("Using $nl_flags->{$var} for lnd_tuning_mode"); my $phys = $physv->as_string(); if ( $nl_flags->{$var} !~ /^${phys}_/ ) { - fatal_error("First part of lnd_tuning_mode MUST match the CLM version you are using.\n"); + $log->fatal_error("First part of lnd_tuning_mode MUST match the CLM version you are using."); } } @@ -1818,18 +1812,18 @@ sub setup_logic_lnd_frac { my $var = "lnd_frac"; if ( defined($opts->{$var}) ) { if ( defined($nl->get_value('fatmlndfrc')) ) { - fatal_error("Can NOT set both -lnd_frac option (set via LND_DOMAIN_PATH/LND_DOMAIN_FILE " . - "env variables) AND fatmlndfrac on namelist\n"); + $log->fatal_error("Can NOT set both -lnd_frac option (set via LND_DOMAIN_PATH/LND_DOMAIN_FILE " . + "env variables) AND fatmlndfrac on namelist"); } my $lnd_frac = SetupTools::expand_xml_var( $opts->{$var}, $envxml_ref); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fatmlndfrc','val'=>$lnd_frac ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fatmlndfrc','val'=>$lnd_frac ); } # Get the fraction file if (defined $nl->get_value('fatmlndfrc')) { # do nothing - use value provided by config_grid.xml and clm.cpl7.template } else { - fatal_error("fatmlndfrc was NOT sent into CLM build-namelist.\n"); + $log->fatal_error("fatmlndfrc was NOT sent into CLM build-namelist."); } } @@ -1841,22 +1835,22 @@ sub setup_logic_co2_type { my $var = "co2_type"; if ( defined($opts->{$var}) ) { if ( ! defined($nl->get_value($var)) ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'co2_type','val'=>"$opts->{'co2_type'}"); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'co2_type','val'=>"$opts->{'co2_type'}"); } else { - fatal_error("co2_type set on namelist as well as -co2_type option.\n"); + $log->fatal_error("co2_type set on namelist as well as -co2_type option."); } } - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'co2_type'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'co2_type'); if ( $nl->get_value('co2_type') =~ /constant/ ) { my $var = 'co2_ppmv'; if ( defined($opts->{$var}) ) { if ( $opts->{$var} <= 0.0 ) { - fatal_error("co2_ppmv can NOT be less than or equal to zero."); + $log->fatal_error("co2_ppmv can NOT be less than or equal to zero."); } my $group = $definition->get_group_name($var); $nl->set_variable_value($group, $var, $opts->{$var}); } else { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'sim_year'=>$nl_flags->{'sim_year'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'sim_year'=>$nl_flags->{'sim_year'} ); } } } @@ -1867,14 +1861,8 @@ sub setup_logic_irrigate { my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - if ( $nl_flags->{'use_crop'} eq ".true." ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'irrigate', 'val'=>$nl_flags->{'irrig'}); - } - elsif ( defined($nl->get_value('irrigate')) ) { - if ($nl->get_value('irrigate') =~ /$TRUE/i ) { - fatal_error("irrigate TRUE needs crop TRUE but it is not\n"); - } - } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'irrigate', + 'use_crop'=>$nl_flags->{'use_crop'}, 'use_cndv'=>$nl_flags->{'use_cndv'} ); $nl_flags->{'irrigate'} = lc($nl->get_value('irrigate')); } } @@ -1882,7 +1870,7 @@ sub setup_logic_irrigate { #------------------------------------------------------------------------------- sub setup_logic_start_type { - my ($nl_flags, $nl) = @_; + my ($opts, $nl_flags, $nl) = @_; my $var = "start_type"; my $drv_start_type = $nl->get_value($var); @@ -1894,20 +1882,20 @@ sub setup_logic_start_type { if ( $nsrest == 1 ) { $my_start_type = "continue"; } if ( $nsrest == 3 ) { $my_start_type = "branch"; } if ( "$my_start_type" eq "$drv_start_type" ) { - fatal_error("no need to set override_nsrest to same as start_type.\n"); + $log->fatal_error("no need to set override_nsrest to same as start_type."); } if ( "$drv_start_type" !~ /startup/ ) { - fatal_error("can NOT set override_nsrest if driver is NOT a startup type.\n"); + $log->fatal_error("can NOT set override_nsrest if driver is NOT a startup type."); } } if ( $my_start_type =~ /branch/ ) { if (not defined $nl->get_value('nrevsn')) { - fatal_error("nrevsn is required for a branch type.\n"); + $log->fatal_error("nrevsn is required for a branch type."); } } else { if (defined $nl->get_value('nrevsn')) { - fatal_error("nrevsn should ONLY be set for a branch type.\n"); + $log->fatal_error("nrevsn should ONLY be set for a branch type."); } } } @@ -1920,39 +1908,39 @@ sub setup_logic_delta_time { if ( defined($opts->{'l_ncpl'}) ) { my $l_ncpl = $opts->{'l_ncpl'}; if ( $l_ncpl <= 0 ) { - fatal_error("bad value for -l_ncpl option.\n"); + $log->fatal_error("bad value for -l_ncpl option."); } my $val = ( 3600 * 24 ) / $l_ncpl; my $dtime = $nl->get_value('dtime'); if ( ! defined($dtime) ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dtime', 'val'=>$val); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dtime', 'val'=>$val); } elsif ( $dtime ne $val ) { - fatal_error("can NOT set both -l_ncpl option (via LND_NCPL env variable) AND dtime namelist variable.\n"); + $log->fatal_error("can NOT set both -l_ncpl option (via LND_NCPL env variable) AND dtime namelist variable."); } } else { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dtime', 'hgrid'=>$nl_flags->{'res'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dtime', 'hgrid'=>$nl_flags->{'res'}); } } #------------------------------------------------------------------------------- sub setup_logic_decomp_performance { - my ($test_files, $nl_flags, $definition, $defaults, $nl) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; # Set the number of segments per clump - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nsegspc', 'hgrid'=>$nl_flags->{'res'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nsegspc', 'hgrid'=>$nl_flags->{'res'}); } #------------------------------------------------------------------------------- sub setup_logic_snow { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snowveg_flag', 'phys'=>$nl_flags->{'phys'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snowveg_flag', 'phys'=>$nl_flags->{'phys'} ); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsnowoptics' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsnowaging' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsnowoptics' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsnowaging' ); } #------------------------------------------------------------------------------- @@ -1972,78 +1960,64 @@ sub setup_logic_glacier { # shared xml variable and not overriding it) my $var = "glc_do_dynglacier"; my $val = logical_to_fortran($envxml_ref->{$clm_upvar}); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$val); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$val); if (lc($nl->get_value($var)) ne lc($val)) { - fatal_error("glc_do_dynglacier can only be set via the env variable $clm_upvar: it can NOT be set in user_nl_clm\n"); + $log->fatal_error("glc_do_dynglacier can only be set via the env variable $clm_upvar: it can NOT be set in user_nl_clm"); } } else { # Otherwise if CLM4.0 physics and GLC_TWO_WAY_COUPLING is TRUE -- trigger an error - if ( logical_to_fortran($envxml_ref->{$clm_upvar}) =~ /$TRUE/i ) { - fatal_error( "clm4_0 physics are being used, but $clm_upvar variable is set to true. $clm_upvar can ONLY be set for physics after clm4_5" ); + if ( &value_is_true(logical_to_fortran($envxml_ref->{$clm_upvar})) ) { + $log->fatal_error( "clm4_0 physics are being used, but $clm_upvar variable is set to true. $clm_upvar can ONLY be set for physics after clm4_5" ); } } my $var = "maxpatch_glcmec"; - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$nl_flags->{'glc_nec'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>$nl_flags->{'glc_nec'} ); my $val = $nl->get_value($var); if ( $val != $nl_flags->{'glc_nec'} ) { - fatal_error("$var set to $val does NOT agree with -glc_nec argument of $nl_flags->{'glc_nec'} (set with GLC_NEC env variable)\n"); + $log->fatal_error("$var set to $val does NOT agree with -glc_nec argument of $nl_flags->{'glc_nec'} (set with GLC_NEC env variable)"); } - if ( $nl_flags->{'glc_nec'} > 0 ) { - if (! $opts->{'glc_present'}) { - fatal_error("glc_nec is non-zero, but glc_present is not set (probably due to trying to use a stub glc model)"); - } - if ( $physv->as_long() < $physv->as_long("clm4_5")) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'flndtopo' , 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'} ); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fglcmask' , 'hgrid'=>$nl_flags->{'res'}); - } + if ( $physv->as_long >= $physv->as_long("clm4_5") ) { + if ( $nl_flags->{'glc_nec'} < 1 ) { + $log->fatal_error("For clm4_5 and later, GLC_NEC must be at least 1."); + } - if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glc_snow_persistence_max_days'); - } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glc_snow_persistence_max_days'); } else { - if ($opts->{'glc_present'}) { - fatal_error("glc_present is set (e.g., due to use of CISM), but glc_nec is zero"); - } - - # Error checking for glacier multiple elevation class options when glc_mec off - # Make sure various glc_mec-specific logicals are not true, and fglcmask is not set - my $create_glcmec = $nl->get_value('create_glacier_mec_landunit'); - if ( defined($create_glcmec) ) { - if ( $create_glcmec =~ /$TRUE/i ) { - fatal_error("create_glacer_mec_landunit is true, but glc_nec is equal to zero"); - } - } - my $glc_dyntopo= $nl->get_value('glc_dyntopo'); - if ( defined($glc_dyntopo) ) { - if ( $glc_dyntopo =~ /$TRUE/i ) { - fatal_error("glc_dyntopo is true, but glc_nec is equal to zero"); - } - } - my $glc_do_dynglacier= $nl->get_value('glc_do_dynglacier'); - if ( defined($glc_do_dynglacier) ) { - if ( $glc_do_dynglacier =~ /$TRUE/i ) { - fatal_error("glc_do_dynglacier (set from GLC_TWO_WAY_COUPLING env variable) is true, but glc_nec is equal to zero"); - } - } - my $fglcmask = $nl->get_value('fglcmask'); - if ( defined($fglcmask) ) { - fatal_error("fglcmask is set, but glc_nec is equal to zero"); - } + # clm4_0 + if ( $nl_flags->{'glc_nec'} > 0 ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'flndtopo' , 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fglcmask' , 'hgrid'=>$nl_flags->{'res'}); + + } else { + # glc_nec == 0 + + # Error checking for glacier multiple elevation class options when glc_mec off + # Make sure various glc_mec-specific logicals are not true, and fglcmask is not set + my $glc_dyntopo= $nl->get_value('glc_dyntopo'); + if ( defined($glc_dyntopo) ) { + if ( &value_is_true($glc_dyntopo) ) { + $log->fatal_error("glc_dyntopo is true, but glc_nec is equal to zero"); + } + } + my $fglcmask = $nl->get_value('fglcmask'); + if ( defined($fglcmask) ) { + $log->fatal_error("fglcmask is set, but glc_nec is equal to zero"); + } + } } # Dependence of albice on glc_nec has gone away starting in CLM4_5. Thus, we # can remove glc_nec from the following call once we ditch CLM4_0. - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'albice', 'glc_nec'=>$nl_flags->{'glc_nec'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'albice', 'glc_nec'=>$nl_flags->{'glc_nec'}); if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - # These controls over glacier region behavior are needed even when running without glc_mec in order to satisfy some error checks in the code - # (And since we'll eventually move to always having glc_mec, it's not worth adding some complex logic to determine when they're really needed.) - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_behavior'); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_melt_behavior'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_behavior'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_melt_behavior'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glacier_region_ice_runoff_behavior'); } } @@ -2053,14 +2027,14 @@ sub setup_logic_params_file { # get param data. For 4_0, pft-physiology, for 4_5 old # pft-physiology was used but now now includes CN and BGC century # parameters. - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'paramfile', - 'use_ed'=>$nl_flags->{'use_ed'}, 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'paramfile', + 'phys'=>$nl_flags->{'phys'}, 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); } else { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fpftcon'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fpftcon'); } } @@ -2068,40 +2042,47 @@ sub setup_logic_params_file { sub setup_logic_create_crop_landunit { # Create crop land unit - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my $var = 'create_crop_landunit'; if ( $physv->as_long() == $physv->as_long("clm4_0") ) { if ( $nl_flags->{'crop'} eq "on" ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'create_crop_landunit' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var ); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'create_crop_landunit', 'irrig'=>$nl_flags->{'irrig'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'irrig'=>$nl_flags->{'irrig'} ); } else { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'create_crop_landunit', 'use_crop'=>$nl_flags->{'use_crop'}); + + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + 'use_fates'=>$nl_flags->{'use_fates'} ); + if ( &value_is_true($nl_flags->{'use_fates'}) && &value_is_true($nl->get_value($var)) ) { + $log->fatal_error( "$var is true and yet use_fates is being set, which contradicts that (use_fates requires $var to be .false." ); + } } } #------------------------------------------------------------------------------- sub setup_logic_cnfire { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - my @fire_consts = ( "rh_low", "rh_hgh", "bt_min", "bt_max", "cli_scale", "boreal_peatfire_c", "non_boreal_peatfire_c", - "pot_hmn_ign_counts_alpha", "cropfire_a1", "occur_hi_gdp_tree" ); + my @fire_consts = ( "rh_low", "rh_hgh", "bt_min", "bt_max", "cli_scale", "boreal_peatfire_c", "non_boreal_peatfire_c", + "pot_hmn_ign_counts_alpha", "cropfire_a1", "occur_hi_gdp_tree", "lfuel", "ufuel", "cmb_cmplt_fact" ); if ( $physv->as_long() >= $physv->as_long("clm4_5") && &value_is_true($nl->get_value('use_cn')) ) { foreach my $item ( @fire_consts ) { - if ( ! value_is_true($nl_flags->{'cnfireson'} ) ) { + if ( ! &value_is_true($nl_flags->{'cnfireson'} ) ) { if ( defined($nl->get_value($item)) ) { - fatal_error( "fire_method is no_fire and yet $item is being set, which contradicts that" ); + $log->fatal_error( "fire_method is no_fire and yet $item is being set, which contradicts that" ); } } else { my $fire_method = remove_leading_and_trailing_quotes( $nl->get_value('fire_method') ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $item, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $item, + 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'}, 'fire_method'=>$fire_method ); } } } elsif ( $physv->as_long() >= $physv->as_long("clm4_5") ) { foreach my $item ( @fire_consts ) { if ( defined($nl->get_value($item)) ) { - fatal_error( "CN is off which implies that cnfire is off and yet a fire constant ($item) is being set, which contradicts that" ); + $log->fatal_error( "CN is off which implies that cnfire is off and yet a fire constant ($item) is being set, which contradicts that" ); } } } @@ -2110,23 +2091,27 @@ sub setup_logic_cnfire { #------------------------------------------------------------------------------- sub setup_logic_cnprec { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm5_0") && &value_is_true($nl->get_value('use_cn')) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ncrit', 'use_cn'=>$nl_flags->{'use_cn'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + $nl, 'cnegcrit', 'use_cn'=>$nl_flags->{'use_cn'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + $nl, 'nnegcrit', 'use_cn'=>$nl_flags->{'use_cn'}); } } #------------------------------------------------------------------------------- sub setup_logic_humanindex { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'calc_human_stress_indices'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'calc_human_stress_indices'); } else { if ( defined($nl->get_value('calc_human_stress_indices')) ) { - fatal_error( "calc_human_stress_indices can NOT be set, for physics versions less than clm4_5" ); + $log->fatal_error( "calc_human_stress_indices can NOT be set, for physics versions less than clm4_5" ); } } } @@ -2134,35 +2119,35 @@ sub setup_logic_humanindex { #------------------------------------------------------------------------------- sub setup_logic_urban { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'building_temp_method'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'building_temp_method'); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urban_hac'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urban_traffic'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urban_hac'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urban_traffic'); } #------------------------------------------------------------------------------- sub setup_logic_crop { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - if ( value_is_true($nl->get_value('use_crop')) ) { + if ( &value_is_true($nl->get_value('use_crop')) ) { my $maptype = 'baset_mapping'; - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $maptype, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $maptype, 'use_crop'=>$nl->get_value('use_crop') ); my $baset_mapping = remove_leading_and_trailing_quotes( $nl->get_value($maptype) ); if ( $baset_mapping eq "varytropicsbylat" ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "baset_latvary_slope", + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "baset_latvary_slope", 'use_crop'=>$nl->get_value('use_crop'), $maptype=>$baset_mapping ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "baset_latvary_intercept", + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "baset_latvary_intercept", 'use_crop'=>$nl->get_value('use_crop'), $maptype=>$baset_mapping ); } else { error_if_set( $nl, "Can only be set if $maptype == varytropicsbylat", "baset_latvary_slope", "baset_latvary_intercept" ); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "initial_seed_at_planting", + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "initial_seed_at_planting", 'use_crop'=>$nl->get_value('use_crop') ); } else { error_if_set( $nl, "Can NOT be set without crop on", "baset_mapping", "baset_latvary_slope", "baset_latvary_intercept" ); @@ -2176,7 +2161,7 @@ sub error_if_set { my ($nl, $error, @list) = @_; foreach my $var ( @list ) { if ( defined($nl->get_value($var)) ) { - fatal_error( "$var $error" ); + $log->fatal_error( "$var $error" ); } } } @@ -2185,12 +2170,13 @@ sub error_if_set { #------------------------------------------------------------------------------- sub setup_logic_soilstate { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'organic_frac_squared' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soil_layerstruct' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_bedrock' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'organic_frac_squared' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soil_layerstruct' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_bedrock', + 'use_fates'=>$nl_flags->{'use_fates'}, 'vichydro'=>$nl_flags->{'vichydro'} ); } } @@ -2208,12 +2194,12 @@ sub setup_logic_demand { $settings{'sim_year_range'} = $nl_flags->{'sim_year_range'}; $settings{'mask'} = $nl_flags->{'mask'}; $settings{'crop'} = $nl_flags->{'crop'}; - $settings{'irrig'} = $nl_flags->{'irrig'}; $settings{'rcp'} = $nl_flags->{'rcp'}; $settings{'glc_nec'} = $nl_flags->{'glc_nec'}; if ( $physv->as_long() >= $physv->as_long("clm4_5")) { # necessary for demand to be set correctly (flanduse_timeseries requires # use_crop, maybe other options require other flags?)! + $settings{'irrigate'} = $nl_flags->{'irrigate'}; $settings{'use_cn'} = $nl_flags->{'use_cn'}; $settings{'use_cndv'} = $nl_flags->{'use_cndv'}; $settings{'use_lch4'} = $nl_flags->{'use_lch4'}; @@ -2221,6 +2207,8 @@ sub setup_logic_demand { $settings{'use_vertsoilc'} = $nl_flags->{'use_vertsoilc'}; $settings{'use_century_decomp'} = $nl_flags->{'use_century_decomp'}; $settings{'use_crop'} = $nl_flags->{'use_crop'}; + } elsif ( $physv->as_long() == $physv->as_long("clm4_0")) { + $settings{'irrig'} = $nl_flags->{'irrig'}; } my $demand = $nl->get_value('clm_demand'); @@ -2244,7 +2232,10 @@ sub setup_logic_demand { if ( $item eq "null" ) { next; } - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $item, %settings ); + if ( $item eq "finidat" ) { + $log->fatal_error( "Do NOT put findat in the clm_demand list, set the clm_start_type=startup so initial conditions are required"); + } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $item, %settings ); } } @@ -2256,7 +2247,7 @@ sub setup_logic_surface_dataset { # consistent with it # MUST BE AFTER: setup_logic_demand which is where flanduse_timeseries is set # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; $nl_flags->{'flanduse_timeseries'} = "null"; my $flanduse_timeseries = $nl->get_value('flanduse_timeseries'); @@ -2272,23 +2263,23 @@ sub setup_logic_surface_dataset { if ( $physv->as_long() == $physv->as_long("clm4_0") ) { if ($flanduse_timeseries ne "null" && $nl_flags->{'bgc_mode'} eq "cndv" ) { - fatal_error( "dynamic PFT's (setting flanduse_timeseries) are incompatible with dynamic vegetation ('-bgc cndv' in CLM_CONFIG_OPTS)." ); + $log->fatal_error( "dynamic PFT's (setting flanduse_timeseries) are incompatible with dynamic vegetation ('-bgc cndv' in CLM_CONFIG_OPTS)." ); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsurdat', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsurdat', 'hgrid'=>$nl_flags->{'res'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'irrig'=>$nl_flags->{'irrig'}, 'crop'=>$nl_flags->{'crop'}, 'glc_nec'=>$nl_flags->{'glc_nec'}); } else{ - if ($flanduse_timeseries ne "null" && value_is_true($nl_flags->{'use_cndv'}) ) { - fatal_error( "dynamic PFT's (setting flanduse_timeseries) are incompatible with dynamic vegetation (use_cndv=.true)." ); + if ($flanduse_timeseries ne "null" && &value_is_true($nl_flags->{'use_cndv'}) ) { + $log->fatal_error( "dynamic PFT's (setting flanduse_timeseries) are incompatible with dynamic vegetation (use_cndv=.true)." ); } - if ($flanduse_timeseries ne "null" && value_is_true($nl_flags->{'use_ed'}) ) { - fatal_error( "dynamic PFT's (setting flanduse_timeseries) are incompatible with ecosystem dynamics (use_ed=.true)." ); + if ($flanduse_timeseries ne "null" && &value_is_true($nl_flags->{'use_fates'}) ) { + $log->fatal_error( "dynamic PFT's (setting flanduse_timeseries) are incompatible with ecosystem dynamics (use_fates=.true)." ); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsurdat', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fsurdat', 'hgrid'=>$nl_flags->{'res'}, - 'sim_year'=>$nl_flags->{'sim_year'}, 'irrig'=>$nl_flags->{'irrig'}, + 'sim_year'=>$nl_flags->{'sim_year'}, 'irrigate'=>$nl_flags->{'irrigate'}, 'use_crop'=>$nl_flags->{'use_crop'}, 'glc_nec'=>$nl_flags->{'glc_nec'}); } } @@ -2302,92 +2293,138 @@ sub setup_logic_initial_conditions { # or just ignore the year of the initial date via the -ignore_ic_year option. # # MUST BE AFTER: setup_logic_demand which is where flanduse_timeseries is set - # AFTER: setup_logic_irrigate which is where irrigate is set + # AFTER: setup_logic_irrigate which is where irrig (or irrigate) is set my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my $var = "finidat"; + my $finidat = $nl->get_value($var); if ( $nl_flags->{'clm_start_type'} =~ /cold/ ) { - if (defined $nl->get_value('finidat')) { - fatal_error("setting finidat is incomptable with using start_type=cold."); + if (defined $finidat ) { + $log->warning("setting $var (either explicitly in your user_nl_clm or by doing a hybrid or branch RUN_TYPE)\n is incomptable with using a cold start" . + " (by setting CLM_FORCE_COLDSTART=on)." ); + $log->warning("Overridding input $var file with one specifying that this is a cold start from arbitrary initial conditions." ); + my $group = $definition->get_group_name($var); + $nl->set_variable_value($group, $var, "' '" ); + } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + $var, 'val'=>"' '", 'no_abspath'=>1); + $finidat = $nl->get_value($var); + } elsif ( defined $finidat ) { + if ( string_is_undef_or_empty($finidat) ) { + print "You are setting $var to blank which signals arbitrary initial conditions.\n"; + print "But, CLM_FORCE_COLDSTART is off which is a contradiction. For arbitrary initial conditions just use the CLM_FORCE_COLDSTART option\n"; + $log->fatal_error("To do a cold-start set ./xmlchange CLM_FORCE_COLDSTART=on, and remove the setting of $var in the user_nl_clm file"); } - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, - 'finidat', 'val'=>"' '", 'no_abspath'=>1); } + my $useinitvar = "use_init_interp"; - if (not defined $nl->get_value('finidat')) { + if (not defined $finidat ) { my $ic_date = $nl->get_value('start_ymd'); + my $st_year = int( $ic_date / 10000); my $nofail = 1; - my $var = "finidat"; - if ( $nl_flags->{'clm_start_type'} =~ /startup/ ) { $nofail = 0; } + my %settings; + $settings{'hgrid'} = $nl_flags->{'res'}; + $settings{'phys'} = $physv->as_string(); + $settings{'nofail'} = $nofail; + my $fsurdat = $nl->get_value('fsurdat'); + $fsurdat =~ s!(.*)/!!; + $settings{'fsurdat'} = $fsurdat; + # + # If not transient use sim_year, otherwise use date + # + if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) { + $settings{'sim_year'} = $nl_flags->{'sim_year'}; + $opts->{'ignore_ic_year'} = 1; + } else { + delete( $settings{'sim_year'} ); + } + if ( $physv->as_long() == $physv->as_long("clm4_0") ) { + $settings{'bgc'} = $nl_flags->{'bgc_mode'}; + foreach my $item ( "mask", "maxpft", "irrig", "glc_nec", "crop" ) { + $settings{$item} = $nl_flags->{$item}; + } + } else { + foreach my $item ( "mask", "maxpft", "irrigate", "glc_nec", "use_crop", "use_cn", "use_cndv", + "use_nitrif_denitrif", "use_vertsoilc", "use_century_decomp" + ) { + $settings{$item} = $nl_flags->{$item}; + } + } if ($opts->{'ignore_ic_date'}) { - if ( $nl_flags->{'use_crop'} eq ".true." ) { - fatal_error("using ignore_ic_date is incompatable with crop!"); - } - if ( $physv->as_long() == $physv->as_long("clm4_0") ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'}, - 'nofail'=>$nofail, 'flanduse_timeseries'=>$nl_flags->{'flanduse_timeseries'}, - 'sim_year'=>$nl_flags->{'sim_year'}, 'maxpft'=>$nl_flags->{'maxpft'}, - 'irrig'=>$nl_flags->{'irrig'}, 'glc_nec'=>$nl_flags->{'glc_nec'}, - 'crop'=>$nl_flags->{'crop'}, 'bgc'=>$nl_flags->{'bgc_mode'} ); - } else { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'}, - 'nofail'=>$nofail, 'flanduse_timeseries'=>$nl_flags->{'flanduse_timeseries'}, - 'use_cn'=>$nl_flags->{'use_cn'}, 'use_cndv'=>$nl_flags->{'use_cndv'}, - 'use_nitrif_denitrif'=>$nl_flags->{'use_nitrif_denitrif'}, - 'use_vertsoilc'=>$nl_flags->{'use_vertsoilc'}, - 'use_century_decomp'=>$nl_flags->{'use_century_decomp'}, - 'sim_year'=>$nl_flags->{'sim_year'}, 'maxpft'=>$nl_flags->{'maxpft'}, - 'glc_nec'=>$nl_flags->{'glc_nec'}, 'use_crop'=>$nl_flags->{'use_crop'}, - 'irrigate'=>$nl_flags->{'irrigate'}, 'phys'=>$nl_flags->{'phys'} ); + if ( &value_is_true($nl_flags->{'use_crop'}) ) { + $log->fatal_error("using ignore_ic_date is incompatable with crop!"); } } elsif ($opts->{'ignore_ic_year'}) { - if ( $physv->as_long() == $physv->as_long("clm4_0") ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'}, - 'ic_md'=>$ic_date, 'nofail'=>$nofail, 'flanduse_timeseries'=>$nl_flags->{'flanduse_timeseries'}, - 'sim_year'=>$nl_flags->{'sim_year'}, 'maxpft'=>$nl_flags->{'maxpft'}, - 'irrig'=>$nl_flags->{'irrig'}, 'glc_nec'=>$nl_flags->{'glc_nec'}, - 'crop'=>$nl_flags->{'crop'}, 'bgc'=>$nl_flags->{'bgc_mode'} ); - } else { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'}, - 'ic_md'=>$ic_date, 'nofail'=>$nofail, 'flanduse_timeseries'=>$nl_flags->{'flanduse_timeseries'}, - 'use_cn'=>$nl_flags->{'use_cn'}, 'use_cndv'=>$nl_flags->{'use_cndv'}, - 'use_nitrif_denitrif'=>$nl_flags->{'use_nitrif_denitrif'}, - 'use_vertsoilc'=>$nl_flags->{'use_vertsoilc'}, - 'use_century_decomp'=>$nl_flags->{'use_century_decomp'}, - 'sim_year'=>$nl_flags->{'sim_year'}, 'maxpft'=>$nl_flags->{'maxpft'}, - 'glc_nec'=>$nl_flags->{'glc_nec'}, 'use_crop'=>$nl_flags->{'use_crop'}, - 'irrigate'=>$nl_flags->{'irrigate'}, 'phys'=>$nl_flags->{'phys'} ); - } + $settings{'ic_md'} = $ic_date; } else { - if ( $physv->as_long() == $physv->as_long("clm4_0") ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'}, - 'ic_ymd'=>$ic_date, 'nofail'=>$nofail, 'flanduse_timeseries'=>$nl_flags->{'flanduse_timeseries'}, - 'sim_year'=>$nl_flags->{'sim_year'}, 'maxpft'=>$nl_flags->{'maxpft'}, - 'irrig'=>$nl_flags->{'irrig'}, 'glc_nec'=>$nl_flags->{'glc_nec'}, - 'crop'=>$nl_flags->{'crop'}, 'bgc'=>$nl_flags->{'bgc_mode'} ); - } else { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'hgrid'=>$nl_flags->{'res'}, 'mask'=>$nl_flags->{'mask'}, - 'ic_ymd'=>$ic_date, 'nofail'=>$nofail, 'flanduse_timeseries'=>$nl_flags->{'flanduse_timeseries'}, - 'use_cn'=>$nl_flags->{'use_cn'}, 'use_cndv'=>$nl_flags->{'use_cndv'}, - 'use_nitrif_denitrif'=>$nl_flags->{'use_nitrif_denitrif'}, - 'use_vertsoilc'=>$nl_flags->{'use_vertsoilc'}, - 'use_century_decomp'=>$nl_flags->{'use_century_decomp'}, - 'sim_year'=>$nl_flags->{'sim_year'}, 'maxpft'=>$nl_flags->{'maxpft'}, - 'glc_nec'=>$nl_flags->{'glc_nec'}, 'use_crop'=>$nl_flags->{'use_crop'}, - 'irrigate'=>$nl_flags->{'irrigate'}, 'phys'=>$nl_flags->{'phys'} ); - } - } - my $finidat = $nl->get_value($var); - if ( (not defined $finidat ) || $finidat =~ /null/ ) { + $settings{'ic_ymd'} = $ic_date; + } + my $try = 0; + my $done = 2; + my $use_init_interp_default = $nl->get_value($useinitvar); + if ( string_is_undef_or_empty( $use_init_interp_default ) ) { + $use_init_interp_default = ".false."; + } + $settings{$useinitvar} = $use_init_interp_default; + do { + $try++; + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, %settings ); + # If couldn't find a matching finidat file, check if can turn on interpolation and try to find one again + $finidat = $nl->get_value($var); + if ( (not defined $finidat ) && ($physv->as_long() >= $physv->as_long("clm4_5")) ) { + # Delete any date settings, except for crop + delete( $settings{'ic_ymd'} ); + delete( $settings{'ic_md'} ); + if ( &value_is_true($nl_flags->{'use_crop'}) ) { + $settings{'ic_md'} = $ic_date; + } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "init_interp_sim_years" ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "init_interp_how_close" ); + foreach my $sim_yr ( split( /,/, $nl->get_value("init_interp_sim_years") )) { + if ( abs($st_year - $sim_yr) < $nl->get_value("init_interp_how_close") ) { + $settings{'sim_year'} = $sim_yr; + } + } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $useinitvar, + 'use_cndv'=>$nl_flags->{'use_cndv'}, 'phys'=>$physv->as_string(), + 'sim_year'=>$settings{'sim_year'}, 'nofail'=>1 ); + $settings{$useinitvar} = $nl->get_value($useinitvar); + if ( $try > 1 ) { + my $group = $definition->get_group_name($useinitvar); + $nl->set_variable_value($group, $useinitvar, $use_init_interp_default ); + } + if ( &value_is_true($nl->get_value($useinitvar) ) ) { + + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "init_interp_attributes", + 'sim_year'=>$settings{'sim_year'}, 'use_cndv'=>$nl_flags->{'use_cndv'}, + 'use_cn'=>$nl_flags->{'use_cn'}, 'nofail'=>1 ); + my $attributes_string = remove_leading_and_trailing_quotes($nl->get_value("init_interp_attributes")); + foreach my $pair ( split( /\s/, $attributes_string) ) { + if ( $pair =~ /^([a-z_]+)=([a-z._0-9]+)$/ ) { + $settings{$1} = $2; + } else { + $log->fatal_error("Problem interpreting init_interp_attributes"); + } + } + } else { + if ( $nl_flags->{'clm_start_type'} =~ /startup/ ) { + $log->fatal_error("clm_start_type is startup so an initial conditions ($var) file is required, but can't find one without $useinitvar being set to true"); + } + $try = $done; + } + } else { + $try = $done + } + } while( ($try < $done) && (not defined $finidat ) ); + if ( not defined $finidat ) { my $group = $definition->get_group_name($var); $nl->set_variable_value($group, $var, "' '" ); } } + $finidat = $nl->get_value($var); + if ( &value_is_true($nl->get_value($useinitvar) ) && string_is_undef_or_empty($finidat) ) { + $log->fatal_error("$useinitvar is set BUT $var is NOT, need to set both" ); + } } # end initial conditions #------------------------------------------------------------------------------- @@ -2396,12 +2433,12 @@ sub setup_logic_dynamic_subgrid { # # Options controlling which parts of flanduse_timeseries to use # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + + setup_logic_do_transient_pfts($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_do_transient_crops($opts, $nl_flags, $definition, $defaults, $nl, $physv); + setup_logic_do_harvest($opts, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_do_transient_pfts($test_files, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_do_transient_crops($test_files, $nl_flags, $definition, $defaults, $nl, $physv); - setup_logic_do_harvest($test_files, $nl_flags, $definition, $defaults, $nl, $physv); - } sub setup_logic_do_transient_pfts { @@ -2412,12 +2449,12 @@ sub setup_logic_do_transient_pfts { # for them to be unset if that will be their final state): # - flanduse_timeseries # - use_cndv - # - use_ed - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # - use_fates + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; my $var = 'do_transient_pfts'; - + if ($physv->as_long() >= $physv->as_long("clm4_5")) { # Start by assuming a default value of '.true.'. Then check a number of # conditions under which do_transient_pfts cannot be true. Under these @@ -2435,13 +2472,13 @@ sub setup_logic_do_transient_pfts { if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) { $cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)"; } - elsif (value_is_true($nl->get_value('use_cndv'))) { + elsif (&value_is_true($nl->get_value('use_cndv'))) { $cannot_be_true = "$var cannot be combined with use_cndv"; } - elsif (value_is_true($nl->get_value('use_ed'))) { - $cannot_be_true = "$var cannot be combined with use_ed"; + elsif (&value_is_true($nl->get_value('use_fates'))) { + $cannot_be_true = "$var cannot be combined with use_fates"; } - + if ($cannot_be_true) { $default_val = ".false."; } @@ -2450,14 +2487,14 @@ sub setup_logic_do_transient_pfts { # Note that, if the variable cannot be true, we don't call add_default # - so that we don't clutter up the namelist with variables that don't # matter for this case - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val); } # Make sure the value is false when it needs to be false - i.e., that the # user hasn't tried to set a true value at an inappropriate time. - if (value_is_true($nl->get_value($var)) && $cannot_be_true) { - fatal_error($cannot_be_true); + if (&value_is_true($nl->get_value($var)) && $cannot_be_true) { + $log->fatal_error($cannot_be_true); } } @@ -2471,9 +2508,9 @@ sub setup_logic_do_transient_crops { # for them to be unset if that will be their final state): # - flanduse_timeseries # - use_crop - # - use_ed - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # - use_fates + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; my $var = 'do_transient_crops'; @@ -2494,11 +2531,11 @@ sub setup_logic_do_transient_crops { if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) { $cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)"; } - elsif (!value_is_true($nl->get_value('use_crop'))) { + elsif (!&value_is_true($nl->get_value('use_crop'))) { $cannot_be_true = "$var can only be set to true when running with use_crop = true"; } - elsif (value_is_true($nl->get_value('use_ed'))) { - # In principle, use_ed should be compatible with + elsif (&value_is_true($nl->get_value('use_fates'))) { + # In principle, use_fates should be compatible with # do_transient_crops. However, this hasn't been tested, so to be safe, # we are not allowing this combination for now. $cannot_be_true = "$var has not been tested with ED, so for now these two options cannot be combined"; @@ -2512,14 +2549,14 @@ sub setup_logic_do_transient_crops { # Note that, if the variable cannot be true, we don't call add_default # - so that we don't clutter up the namelist with variables that don't # matter for this case - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val); } # Make sure the value is false when it needs to be false - i.e., that the # user hasn't tried to set a true value at an inappropriate time. - if (value_is_true($nl->get_value($var)) && $cannot_be_true) { - fatal_error($cannot_be_true); + if (&value_is_true($nl->get_value($var)) && $cannot_be_true) { + $log->fatal_error($cannot_be_true); } } @@ -2533,10 +2570,10 @@ sub setup_logic_do_harvest { # for them to be unset if that will be their final state): # - flanduse_timeseries # - use_cn - # - use_ed + # - use_fates # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my $var = 'do_harvest'; if ($physv->as_long() >= $physv->as_long("clm4_5")) { @@ -2555,10 +2592,10 @@ sub setup_logic_do_harvest { if (string_is_undef_or_empty($nl->get_value('flanduse_timeseries'))) { $cannot_be_true = "$var can only be set to true when running a transient case (flanduse_timeseries non-blank)"; } - elsif (!value_is_true($nl->get_value('use_cn'))) { + elsif (!&value_is_true($nl->get_value('use_cn'))) { $cannot_be_true = "$var can only be set to true when running with CN (use_cn = true)"; } - elsif (value_is_true($nl->get_value('use_ed'))) { + elsif (&value_is_true($nl->get_value('use_fates'))) { $cannot_be_true = "$var currently doesn't work with ED"; } @@ -2570,33 +2607,33 @@ sub setup_logic_do_harvest { # Note that, if the variable cannot be true, we don't call add_default # - so that we don't clutter up the namelist with variables that don't # matter for this case - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, val=>$default_val); } # Make sure the value is false when it needs to be false - i.e., that the # user hasn't tried to set a true value at an inappropriate time. - if (value_is_true($nl->get_value($var)) && $cannot_be_true) { - fatal_error($cannot_be_true); + if (&value_is_true($nl->get_value($var)) && $cannot_be_true) { + $log->fatal_error($cannot_be_true); } - + } } #------------------------------------------------------------------------------- sub setup_logic_spinup { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5")) { if ( $nl_flags->{'bgc_mode'} eq "sp" && defined($nl->get_value('override_bgc_restart_mismatch_dump'))) { - fatal_error("CN must be on if override_bgc_restart_mismatch_dump is set.\n"); + $log->fatal_error("CN must be on if override_bgc_restart_mismatch_dump is set."); } } if ( $nl_flags->{'clm_accelerated_spinup'} eq "on" ) { foreach my $var ( "hist_nhtfrq", "hist_fincl1", "hist_empty_htapes", "hist_mfilt" ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, - $var, use_cn=>$nl_flags->{'use_cn'}, use_ed=>$nl_flags->{'use_ed'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + $var, use_cn=>$nl_flags->{'use_cn'}, use_fates=>$nl_flags->{'use_fates'}, use_cndv=>$nl_flags->{'use_cndv'} ); } } @@ -2605,17 +2642,17 @@ sub setup_logic_spinup { #------------------------------------------------------------------------------- sub setup_logic_bgc_shared { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5")) { if ( $nl_flags->{'bgc_mode'} ne "sp" ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'constrain_stress_deciduous_onset', 'phys'=>$physv->as_string() ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'constrain_stress_deciduous_onset', 'phys'=>$physv->as_string() ); } - # FIXME(bja, 201606) the logic around ed / bgc_mode / + # FIXME(bja, 201606) the logic around fates / bgc_mode / # use_century_decomp is confusing and messed up. This is a hack # workaround. - if ($nl_flags->{'use_century_decomp'} == '.true.') { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'decomp_depth_efolding', 'phys'=>$physv->as_string() ); + if ( &value_is_true($nl_flags->{'use_century_decomp'}) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'decomp_depth_efolding', 'phys'=>$physv->as_string() ); } } @@ -2627,10 +2664,10 @@ sub setup_logic_supplemental_nitrogen { # # Supplemental Nitrogen for prognostic crop cases # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - if ( $nl_flags->{'bgc_mode'} ne "sp" && $nl_flags->{'bgc_mode'} ne "ed" && $nl_flags->{'use_crop'} eq ".true." ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + if ( $nl_flags->{'bgc_mode'} ne "sp" && $nl_flags->{'bgc_mode'} ne "fates" && &value_is_true($nl_flags->{'use_crop'}) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'suplnitro', 'use_cn'=>$nl_flags->{'use_cn'}, 'use_crop'=>$nl_flags->{'use_crop'}); } @@ -2640,19 +2677,19 @@ sub setup_logic_supplemental_nitrogen { my $suplnitro = $nl->get_value('suplnitro'); if ( defined($suplnitro) ) { if ( $nl_flags->{'bgc_mode'} eq "sp" ) { - fatal_error("supplemental Nitrogen (suplnitro) is set, but neither CN nor CNDV is active!\n"); + $log->fatal_error("supplemental Nitrogen (suplnitro) is set, but neither CN nor CNDV is active!"); } - if ( $nl_flags->{'use_crop'} ne ".true." && $suplnitro =~ /PROG_CROP_ONLY/i ) { - fatal_error("supplemental Nitrogen is set to run over prognostic crops, but prognostic crop is NOT active!\n"); + if ( ! &value_is_true($nl_flags->{'use_crop'}) && $suplnitro =~ /PROG_CROP_ONLY/i ) { + $log->fatal_error("supplemental Nitrogen is set to run over prognostic crops, but prognostic crop is NOT active!"); } - + if ( $suplnitro =~ /ALL/i ) { if ( $physv->as_long() == $physv->as_long("clm4_0") && $nl_flags->{'spinup'} ne "normal" ) { - fatal_error("There is no need to use a spinup mode when supplemental Nitrogen is on for all PFT's, as these modes spinup Nitrogen\n" . - "when spinup != normal you can NOT set supplemental Nitrogen (suplnitro) to ALL\n"); + $log->fatal_error("There is no need to use a spinup mode when supplemental Nitrogen is on for all PFT's, as these modes spinup Nitrogen\n" . + "when spinup != normal you can NOT set supplemental Nitrogen (suplnitro) to ALL"); } if ( $physv->as_long() >= $physv->as_long("clm4_5") && $nl_flags->{'bgc_spinup'} ne "off" ) { - warning("There is no need to use a bgc_spinup mode when supplemental Nitrogen is on for all PFT's, as these modes spinup Nitrogen\n"); + $log->warning("There is no need to use a bgc_spinup mode when supplemental Nitrogen is on for all PFT's, as these modes spinup Nitrogen" ); } } } @@ -2664,19 +2701,19 @@ sub setup_logic_hydrology_params { # # Logic for hydrology parameters # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5")) { my $lower = $nl->get_value( 'lower_boundary_condition' ); my $var = "baseflow_scalar"; if ( $lower == 1 || $lower == 2 ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'lower_boundary_condition' => $lower ); } my $val = $nl->get_value( $var ); if ( defined($val) ) { if ( $lower != 1 && $lower != 2 ) { - fatal_error("baseflow_scalar is only used for lower_boundary_condition of flux or zero-flux"); + $log->fatal_error("baseflow_scalar is only used for lower_boundary_condition of flux or zero-flux"); } } } @@ -2685,22 +2722,22 @@ sub setup_logic_hydrology_params { #------------------------------------------------------------------------------- sub setup_logic_irrigation_parameters { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5")) { my $var; foreach $var ("irrig_min_lai", "irrig_start_time", "irrig_length", "irrig_target_smp", "irrig_depth", "irrig_threshold_fraction", "limit_irrigation_if_rof_enabled") { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); } $var = "irrig_river_volume_threshold"; - if ( $nl->get_value("limit_irrigation_if_rof_enabled") =~ /$TRUE/i ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); + if ( &value_is_true($nl->get_value("limit_irrigation_if_rof_enabled")) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); } else { if (defined($nl->get_value($var))) { - fatal_error("$var can only be set if limit_irrigation_if_rof_enabled is true"); + $log->fatal_error("$var can only be set if limit_irrigation_if_rof_enabled is true"); } } } @@ -2714,12 +2751,12 @@ sub setup_logic_nitrif_params { # my ($nl_flags, $definition, $defaults, $nl) = @_; - if ( ! value_is_true($nl_flags->{'use_nitrif_denitrif'}) ) { + if ( ! &value_is_true($nl_flags->{'use_nitrif_denitrif'}) ) { my @vars = ( "k_nitr_max", "denitrif_respiration_coefficient", "denitrif_respiration_exponent", "denitrif_nitrateconc_coefficient", "denitrif_nitrateconc_exponent" ); foreach my $var ( @vars ) { if ( defined($nl->get_value( $var ) ) ) { - fatal_error("$var is only used when use_nitrif_denitrif is turned on"); + $log->fatal_error("$var is only used when use_nitrif_denitrif is turned on"); } } } @@ -2737,17 +2774,17 @@ sub setup_logic_hydrology_switches { my $origflag = $nl->get_value('origflag' ); my $h2osfcflag = $nl->get_value('h2osfcflag' ); if ( $origflag == 1 && $subgrid == 1 ) { - fatal_error("if origflag is ON, subgridflag can NOT also be on!"); + $log->fatal_error("if origflag is ON, subgridflag can NOT also be on!"); } if ( $h2osfcflag == 1 && $subgrid != 1 ) { - fatal_error("if h2osfcflag is ON, subgridflag can NOT be off!"); + $log->fatal_error("if h2osfcflag is ON, subgridflag can NOT be off!"); } # These should NOT be set for CLM5.0 and beyond if ( $physv->as_long() > $physv->as_long("clm4_5") ) { foreach my $var ( "origflag", "h2osfcflag", "oldfflag" ) { my $val = $nl->get_value($var); if ( defined($val) ) { - fatal_error( "ERROR:: $val is deprecated and can only be used with CLM4.5" ); + $log->fatal_error( "ERROR:: $var=$val is deprecated and can only be used with CLM4.5" ); } } } @@ -2758,19 +2795,22 @@ sub setup_logic_hydrology_switches { my $use_bed = $nl->get_value( 'use_bedrock' ); my $soilmtd = $nl->get_value( 'soilwater_movement_method' ); if ( defined($soilmtd) && defined($lower) && $soilmtd == 0 && $lower != 4 ) { - fatal_error( "If soil water movement method is zeng-decker -- lower_boundary_condition can only be aquifer" ); + $log->fatal_error( "If soil water movement method is zeng-decker -- lower_boundary_condition can only be aquifer" ); } - if ( defined($use_bed) && defined($lower) && (value_is_true($use_bed)) && $lower != 2 ) { - fatal_error( "If use_bedrock is on -- lower_boundary_condition can only be flux" ); + if ( defined($soilmtd) && defined($lower) && $soilmtd == 1 && $lower == 4 ) { + $log->fatal_error( "If soil water movement method is adaptive -- lower_boundary_condition can NOT be aquifer" ); } - if ( defined($use_vic) && defined($lower) && (value_is_true($use_vic)) && $lower != 3 && $lower != 4) { - fatal_error( "If use_vichydro is on -- lower_boundary_condition can only be table or aquifer" ); + if ( defined($use_bed) && defined($lower) && (&value_is_true($use_bed)) && $lower != 2 ) { + $log->fatal_error( "If use_bedrock is on -- lower_boundary_condition can only be flux" ); } - if ( defined($origflag) && defined($use_vic) && (value_is_true($use_vic)) && $origflag == 1 ) { - fatal_error( "If use_vichydro is on -- origflag can NOT be equal to 1" ); + if ( defined($use_vic) && defined($lower) && (&value_is_true($use_vic)) && $lower != 3 && $lower != 4) { + $log->fatal_error( "If use_vichydro is on -- lower_boundary_condition can only be table or aquifer" ); + } + if ( defined($origflag) && defined($use_vic) && (&value_is_true($use_vic)) && $origflag == 1 ) { + $log->fatal_error( "If use_vichydro is on -- origflag can NOT be equal to 1" ); } if ( defined($h2osfcflag) && defined($lower) && $h2osfcflag == 0 && $lower != 4 ) { - fatal_error( "If h2osfcflag is 0 lower_boundary_condition can only be aquifer" ); + $log->fatal_error( "If h2osfcflag is 0 lower_boundary_condition can only be aquifer" ); } } } @@ -2781,58 +2821,69 @@ sub setup_logic_methane { # # CH4 model if bgc=CN or CNDV # - my ($test_files, $nl_flags, $definition, $defaults, $nl) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; - if ( $nl_flags->{'use_lch4'} eq '.true.' ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fin_use_fsat', - 'use_cn'=>$nl_flags->{'use_cn'}, 'use_ed'=>$nl_flags->{'use_ed'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_aereoxid_prog', - 'use_cn'=>$nl_flags->{'use_cn'}, 'use_ed'=>$nl_flags->{'use_ed'} ); + if ( &value_is_true($nl_flags->{'use_lch4'}) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'finundation_method', + 'use_cn'=>$nl_flags->{'use_cn'}, 'use_fates'=>$nl_flags->{'use_fates'} ); + # + # Get resolution to read streams file for + # + my $finundation_method = remove_leading_and_trailing_quotes($nl->get_value('finundation_method' )); + if ( $finundation_method eq "TWS_inversion" ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'finundation_res', + 'finundation_method'=>$finundation_method ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_ch4finundated', + 'finundation_method'=>$finundation_method, + 'finundation_res'=>$nl->get_value('finundation_res') ); + } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_aereoxid_prog', + 'use_cn'=>$nl_flags->{'use_cn'}, 'use_fates'=>$nl_flags->{'use_fates'} ); # # Check if use_aereoxid_prog is set. If no, then read value of aereoxid from # parameters file # my $use_aereoxid_prog = $nl->get_value('use_aereoxid_prog'); - if ( defined($use_aereoxid_prog) && $use_aereoxid_prog =~ /$FALSE/i ) { - warning("Using aereoxid value from parameters file.\n"); + if ( defined($use_aereoxid_prog) && ! &value_is_true($use_aereoxid_prog) ) { + $log->warning("Using aereoxid value from parameters file." ); } } else { my @vars = $nl->get_variable_names('ch4par_in'); if ( $#vars >= 0 ) { - fatal_error("ch4par_in namelist variables were set, but Methane model NOT defined in the configuration (use_lch4)"); + $log->fatal_error("ch4par_in namelist variables were set, but Methane model NOT defined in the configuration (use_lch4)"); } } # # Ch4 namelist checking # - if ( $nl_flags->{'use_lch4'} eq ".true." ) { + if ( &value_is_true($nl_flags->{'use_lch4'}) ) { my $allowlakeprod = $nl->get_value('allowlakeprod'); if ( ! defined($allowlakeprod) || - (defined($allowlakeprod) && $allowlakeprod =~ /$FALSE/i) ) { + (defined($allowlakeprod) && ! &value_is_true($allowlakeprod)) ) { if ( defined($nl->get_value('lake_decomp_fact')) ) { - fatal_error("lake_decomp_fact set without allowlakeprod=.true.\n"); + $log->fatal_error("lake_decomp_fact set without allowlakeprod=.true."); } } my $anoxia = $nl->get_value('anoxia'); if ( ! defined($anoxia) || - (defined($anoxia) && $anoxia =~ /$FALSE/i) ) { + (defined($anoxia) && ! &value_is_true($anoxia)) ) { if ( defined($nl->get_value('anoxia_wtsat')) ) { - fatal_error("anoxia_wtsat set without anoxia=.true.\n"); + $log->fatal_error("anoxia_wtsat set without anoxia=.true."); } } my $pftspec_rootprof = $nl->get_value('pftspecific_rootingprofile'); if ( ! defined($pftspec_rootprof) || - (defined($pftspec_rootprof) && $pftspec_rootprof =~ /$TRUE/i) ) { + (defined($pftspec_rootprof) && &value_is_true($pftspec_rootprof) ) ) { if ( defined($nl->get_value('rootprof_exp')) ) { - fatal_error("rootprof_exp set without pftspecific_rootingprofile=.false.\n"); + $log->fatal_error("rootprof_exp set without pftspecific_rootingprofile=.false."); } } } else { my @vars = ( "allowlakeprod", "anoxia", "anoxia_wtsat", "pftspecific_rootingprofile" ); foreach my $var ( @vars ) { if ( defined($nl->get_value($var)) ) { - fatal_error("$var set without methane model configuration on (use_lch4)\n"); + $log->fatal_error("$var set without methane model configuration on (use_lch4)"); } } } @@ -2844,49 +2895,49 @@ sub setup_logic_dynamic_plant_nitrogen_alloc { # # dynamic plant nitrogen allocation model, bgc=bgc # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") && - value_is_true($nl_flags->{'use_cn'}) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_flexibleCN', + &value_is_true($nl_flags->{'use_cn'}) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_flexibleCN', 'phys'=>$physv->as_string(), 'use_cn'=>$nl_flags->{'use_cn'} ); $nl_flags->{'use_flexibleCN'} = $nl->get_value('use_flexibleCN'); - if ( $nl_flags->{'use_flexibleCN'} eq '.true.' ) { + if ( &value_is_true($nl_flags->{'use_flexibleCN'}) ) { # TODO(bja, 2015-04) make this depend on > clm 5.0 and bgc mode at some point. - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'MM_Nuptake_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'MM_Nuptake_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'downreg_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'downreg_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'plant_ndemand_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'plant_ndemand_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'substrate_term_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'substrate_term_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nscalar_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nscalar_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'temp_scalar_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'temp_scalar_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CNratio_floating', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CNratio_floating', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reduce_dayl_factor', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reduce_dayl_factor', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'vcmax_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'vcmax_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CN_residual_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CN_residual_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CN_partition_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CN_partition_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CN_evergreen_phenology_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'CN_evergreen_phenology_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'carbon_resp_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'carbon_resp_opt', 'use_flexibleCN'=>$nl_flags->{'use_flexibleCN'}, 'use_fun'=>$nl->get_value('use_fun') ); - if ( $nl->get_value('carbon_resp_opt') == 1 && value_is_true($nl->get_value('use_fun')) ) { - fatal_error("carbon_resp_opt should NOT be set to 1 when FUN is also on\n"); + if ( $nl->get_value('carbon_resp_opt') == 1 && &value_is_true($nl->get_value('use_fun')) ) { + $log->fatal_error("carbon_resp_opt should NOT be set to 1 when FUN is also on"); } } - } elsif ( $physv->as_long() >= $physv->as_long("clm4_5") && ! value_is_true($nl_flags->{'use_cn'}) ) { - if ( value_is_true($nl->get_value('use_flexibleCN')) ) { - fatal_error("use_flexibleCN can ONLY be set if CN is on\n"); + } elsif ( $physv->as_long() >= $physv->as_long("clm4_5") && ! &value_is_true($nl_flags->{'use_cn'}) ) { + if ( &value_is_true($nl->get_value('use_flexibleCN')) ) { + $log->fatal_error("use_flexibleCN can ONLY be set if CN is on"); } } } @@ -2897,37 +2948,37 @@ sub setup_logic_luna { # # LUNA model to calculate photosynthetic capacities based on environmental conditions # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_luna', - 'phys'=>$physv->as_string(), 'use_cn'=>$nl_flags->{'use_cn'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_luna', + 'phys'=>$physv->as_string(), 'use_cn'=>$nl_flags->{'use_cn'}, 'use_fates'=>$nl_flags->{'use_fates'}, 'use_nitrif_denitrif'=>$nl_flags->{'use_nitrif_denitrif'} ); - if ( value_is_true( $nl_flags->{'use_cn'} ) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_nguardrail', + if ( &value_is_true( $nl_flags->{'use_cn'} ) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_nguardrail', 'use_cn'=>$nl_flags->{'use_cn'} ); } $nl_flags->{'use_luna'} = $nl->get_value('use_luna'); my $vcmax_opt= $nl->get_value('vcmax_opt'); # lnc_opt only applies if luna is on or for vcmax_opt=3/4 - if ( value_is_true( $nl_flags->{'use_luna'} ) || $vcmax_opt == 3 || $vcmax_opt == 4 ) { + if ( &value_is_true( $nl_flags->{'use_luna'} ) || $vcmax_opt == 3 || $vcmax_opt == 4 ) { # lnc_opt can be set for both CN on and off - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lnc_opt', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lnc_opt', 'use_cn'=>$nl_flags->{'use_cn'} ); } - if ( value_is_true($nl->get_value('lnc_opt') ) && not value_is_true( $nl_flags->{'use_cn'}) ) { - fatal_error("Cannot turn lnc_opt to true when bgc=sp\n" ); + if ( &value_is_true($nl->get_value('lnc_opt') ) && not &value_is_true( $nl_flags->{'use_cn'}) ) { + $log->fatal_error("Cannot turn lnc_opt to true when bgc=sp" ); } my $var = "jmaxb1"; - if ( $physv->as_long() >= $physv->as_long("clm5_0") && value_is_true( $nl_flags->{'use_luna'} ) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, + if ( $physv->as_long() >= $physv->as_long("clm5_0") && &value_is_true( $nl_flags->{'use_luna'} ) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'use_luna'=>$nl_flags->{'use_luna'} ); } my $val = $nl->get_value($var); - if ( $physv->as_long() >= $physv->as_long("clm4_5") && ! value_is_true( $nl_flags->{'use_luna'} ) ) { + if ( $physv->as_long() >= $physv->as_long("clm4_5") && ! &value_is_true( $nl_flags->{'use_luna'} ) ) { if ( defined($val) ) { - fatal_error("Cannot set $var when use_luna is NOT on\n" ); + $log->fatal_error("Cannot set $var when use_luna is NOT on" ); } } } @@ -2939,10 +2990,10 @@ sub setup_logic_hillslope { # # Hillslope hydrology model # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); } } @@ -2952,15 +3003,15 @@ sub setup_logic_hydrstress { # # Plant hydraulic stress model # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { # TODO(kwo, 2015-09) make this depend on > clm 5.0 at some point. - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hydrstress', - 'use_ed'=>$nl_flags->{'use_ed'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hydrstress', + 'use_fates'=>$nl_flags->{'use_fates'} ); $nl_flags->{'use_hydrstress'} = $nl->get_value('use_hydrstress'); - if ( value_is_true( $nl_flags->{'use_ed'} ) && value_is_true( $nl_flags->{'use_hydrstress'} ) ) { - fatal_error("Cannot turn use_hydrstress on when use_ed is on\n" ); + if ( &value_is_true( $nl_flags->{'use_fates'} ) && &value_is_true( $nl_flags->{'use_hydrstress'} ) ) { + $log->fatal_error("Cannot turn use_hydrstress on when use_fates is on" ); } } } @@ -2969,13 +3020,13 @@ sub setup_logic_hydrstress { sub setup_logic_fertilizer { # - # Flags to control fertilizer application + # Flags to control fertilizer application # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { $nl_flags->{'use_crop'} = $nl->get_value('use_crop'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fertilizer', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fertilizer', 'use_crop'=>$nl_flags->{'use_crop'} ); } } @@ -2984,13 +3035,13 @@ sub setup_logic_fertilizer { sub setup_logic_grainproduct { # - # Flags to control 1-year grain product pool + # Flags to control 1-year grain product pool # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { $nl_flags->{'use_crop'} = $nl->get_value('use_crop'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_grainproduct', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_grainproduct', 'use_crop'=>$nl_flags->{'use_crop'}, 'phys'=>$physv->as_string() ); } } @@ -3001,17 +3052,17 @@ sub setup_logic_dynamic_roots { # # dynamic root model # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_dynroot', 'phys'=>$physv->as_string(), 'bgc_mode'=>$nl_flags->{'bgc_mode'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_dynroot', 'phys'=>$physv->as_string(), 'bgc_mode'=>$nl_flags->{'bgc_mode'}); my $use_dynroot = $nl->get_value('use_dynroot'); - if ( ($use_dynroot eq ".true.") && ($nl_flags->{'bgc_mode'} eq "sp") ) { - fatal_error("Cannot turn dynroot mode on mode bgc=sp\n" . - "Set the bgc mode to 'cn' or 'bgc'.\n"); + if ( &value_is_true($use_dynroot) && ($nl_flags->{'bgc_mode'} eq "sp") ) { + $log->fatal_error("Cannot turn dynroot mode on mode bgc=sp\n" . + "Set the bgc mode to 'cn' or 'bgc'."); } - if ( value_is_true( $use_dynroot ) && value_is_true( $nl_flags->{'use_hydrstress'} ) ) { - fatal_error("Cannot turn use_dynroot on when use_hydrstress is on\n" ); + if ( &value_is_true( $use_dynroot ) && &value_is_true( $nl_flags->{'use_hydrstress'} ) ) { + $log->fatal_error("Cannot turn use_dynroot on when use_hydrstress is on" ); } } # else - not relevant in clm4_0, not part of namelist definition, will not run. } @@ -3022,52 +3073,65 @@ sub setup_logic_c_isotope { # # Error checking for C-isotope options # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; my $use_c13 = $nl->get_value('use_c13'); my $use_c14 = $nl->get_value('use_c14'); - if ( $nl_flags->{'bgc_mode'} ne "sp" && $nl_flags->{'bgc_mode'} ne "ed" ) { - if ( $nl_flags->{'use_crop'} eq ".true." ) { - if ( defined($use_c13) || - defined($use_c14) || - defined($nl->get_value('use_c14_bombspike')) || - defined($nl->get_value('atm_c14_filename')) ) { - fatal_error("CROP is on and C isotope namelist variables were set, both can't be used at the same time"); - } - } + if ( $nl_flags->{'bgc_mode'} ne "sp" && $nl_flags->{'bgc_mode'} ne "fates" ) { if ( $nl_flags->{'bgc_mode'} ne "bgc" ) { - if ( defined($use_c13) && $use_c13 =~ /$TRUE/i ) { - warning("use_c13 is ONLY scientifically validated with the bgc=BGC configuration\n"); + if ( defined($use_c13) && &value_is_true($use_c13) ) { + $log->warning("use_c13 is ONLY scientifically validated with the bgc=BGC configuration" ); } - if ( defined($use_c14) && $use_c14 =~ /$TRUE/i ) { - warning("use_c14 is ONLY scientifically validated with the bgc=BGC configuration\n"); + if ( defined($use_c14) && &value_is_true($use_c14) ) { + $log->warning("use_c14 is ONLY scientifically validated with the bgc=BGC configuration" ); } } if ( defined($use_c14) ) { - if ( $use_c14 =~ /$TRUE/i ) { + if ( &value_is_true($use_c14) ) { my $use_c14_bombspike = $nl->get_value('use_c14_bombspike'); - if ( defined($use_c14_bombspike) && value_is_true($use_c14_bombspike) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'atm_c14_filename', + if ( defined($use_c14_bombspike) && &value_is_true($use_c14_bombspike) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'atm_c14_filename', 'use_c14'=>$use_c14, 'use_cn'=>$nl_flags->{'use_cn'}, 'use_c14_bombspike'=>$nl->get_value('use_c14_bombspike') ); } } else { if ( defined($nl->get_value('use_c14_bombspike')) || defined($nl->get_value('atm_c14_filename')) ) { - fatal_error("use_c14 is FALSE and use_c14_bombspike or atm_c14_filename set\n"); + $log->fatal_error("use_c14 is FALSE and use_c14_bombspike or atm_c14_filename set"); } } } else { if ( defined($nl->get_value('use_c14_bombspike')) || defined($nl->get_value('atm_c14_filename')) ) { - fatal_error("use_c14 NOT set to .true., but use_c14_bompspike/atm_c14_filename defined.\n"); + $log->fatal_error("use_c14 NOT set to .true., but use_c14_bompspike/atm_c14_filename defined."); + } + } + if ( defined($use_c13) ) { + if ( &value_is_true($use_c13) ) { + my $use_c13_timeseries = $nl->get_value('use_c13_timeseries'); + if ( defined($use_c13_timeseries) && &value_is_true($use_c13_timeseries) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'atm_c13_filename', + 'use_c13'=>$use_c13, 'use_cn'=>$nl_flags->{'use_cn'}, 'use_c13_timeseries'=>$nl->get_value('use_c13_timeseries') ); + } + } else { + if ( defined($nl->get_value('use_c13_timeseries')) || + defined($nl->get_value('atm_c13_filename')) ) { + $log->fatal_error("use_c13 is FALSE and use_c13_timeseries or atm_c13_filename set"); + } + } + } else { + if ( defined($nl->get_value('use_c13_timeseries')) || + defined($nl->get_value('atm_c13_filename')) ) { + $log->fatal_error("use_c13 NOT set to .true., but use_c13_bompspike/atm_c13_filename defined."); } } } else { if ( defined($use_c13) || defined($use_c14) || defined($nl->get_value('use_c14_bombspike')) || - defined($nl->get_value('atm_c14_filename')) ) { - fatal_error("bgc=sp and C isotope namelist variables were set, both can't be used at the same time"); + defined($nl->get_value('atm_c14_filename')) || + defined($nl->get_value('use_c13_timeseries')) || + defined($nl->get_value('atm_c13_filename')) ) { + $log->fatal_error("bgc=sp and C isotope namelist variables were set, both can't be used at the same time"); } } } @@ -3075,49 +3139,49 @@ sub setup_logic_c_isotope { #------------------------------------------------------------------------------- sub setup_logic_nitrogen_deposition { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; # # Nitrogen deposition for bgc=CN # if ( $physv->as_long() == $physv->as_long("clm4_0") && $nl_flags->{'bgc_mode'} ne "none" ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndepmapalgo', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndepmapalgo', 'phys'=>$nl_flags->{'phys'}, 'bgc'=>$nl_flags->{'bgc_mode'}, 'hgrid'=>$nl_flags->{'res'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_ndep', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_ndep', 'phys'=>$nl_flags->{'phys'}, 'bgc'=>$nl_flags->{'bgc_mode'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_ndep', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_ndep', 'phys'=>$nl_flags->{'phys'}, 'bgc'=>$nl_flags->{'bgc_mode'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); # Set align year, if first and last years are different if ( $nl->get_value('stream_year_first_ndep') != $nl->get_value('stream_year_last_ndep') ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_ndep', 'sim_year'=>$nl_flags->{'sim_year'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_ndep', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_ndep', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_ndep', 'phys'=>$nl_flags->{'phys'}, 'bgc'=>$nl_flags->{'bgc_mode'}, 'rcp'=>$nl_flags->{'rcp'}, 'hgrid'=>"1.9x2.5" ); } elsif ( $physv->as_long() >= $physv->as_long("clm4_5") && $nl_flags->{'bgc_mode'} =~/cn|bgc/ ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndepmapalgo', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndepmapalgo', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'hgrid'=>$nl_flags->{'res'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_ndep', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_ndep', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_ndep', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_ndep', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); # Set align year, if first and last years are different if ( $nl->get_value('stream_year_first_ndep') != $nl->get_value('stream_year_last_ndep') ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_ndep', 'sim_year'=>$nl_flags->{'sim_year'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_ndep', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_ndep', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_ndep', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'rcp'=>$nl_flags->{'rcp'}, 'hgrid'=>"1.9x2.5" ); } else { @@ -3127,9 +3191,9 @@ sub setup_logic_nitrogen_deposition { defined($nl->get_value('model_year_align_ndep')) || defined($nl->get_value('stream_fldfilename_ndep')) ) { - fatal_error("When bgc is NOT CN or CNDV none of: stream_year_first_ndep," . + $log->fatal_error("When bgc is NOT CN or CNDV none of: stream_year_first_ndep," . "stream_year_last_ndep, model_year_align_ndep, nor stream_fldfilename_ndep" . - " can be set!\n"); + " can be set!"); } } } @@ -3137,23 +3201,23 @@ sub setup_logic_nitrogen_deposition { #------------------------------------------------------------------------------- sub setup_logic_cnmresp { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; # # CN Maintence respiration for bgc=CN # if ( $physv->as_long() >= $physv->as_long("clm4_5") && $nl_flags->{'bgc_mode'} ne "sp" ) { # When FUN is on and it's clm5_0 get a default value - if ( value_is_true( $nl->get_value('use_fun') ) && $physv->as_long() >= $physv->as_long("clm5_0")) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, - $nl, 'br_root', 'phys'=>$nl_flags->{'phys'}, + if ( &value_is_true( $nl->get_value('use_fun') ) && $physv->as_long() >= $physv->as_long("clm5_0")) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + $nl, 'br_root', 'phys'=>$nl_flags->{'phys'}, 'use_fun'=>$nl->get_value('use_fun'), 'use_cn'=>$nl_flags->{'use_cn'} ); } } else { # If bgc is NOT CN/CNDV then make sure not set if ( defined($nl->get_value('br_root'))) { - fatal_error("br_root can NOT be set when phys==clm4_0 or bgc_mode==sp!\n"); + $log->fatal_error("br_root can NOT be set when phys==clm4_0 or bgc_mode==sp!"); } } } @@ -3161,28 +3225,34 @@ sub setup_logic_cnmresp { #------------------------------------------------------------------------------- sub setup_logic_photosyns { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # MUST be after use_hydrstress is set + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; # # Photo synthesis # if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'rootstem_acc', 'phys'=>$nl_flags->{'phys'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'light_inhibit', 'phys'=>$nl_flags->{'phys'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'leafresp_method', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + $nl, 'modifyphoto_and_lmr_forcrop', 'phys'=>$nl_flags->{'phys'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + $nl, 'stomatalcond_method', 'phys'=>$nl_flags->{'phys'}, + 'use_hydrstress'=>$nl_flags->{'use_hydrstress'} ); # When CN on, must NOT be scaled by vcmax25top - if ( value_is_true( $nl_flags->{'use_cn'} ) ) { + if ( &value_is_true( $nl_flags->{'use_cn'} ) ) { if ( $nl->get_value('leafresp_method') == 0 ) { - fatal_error("leafresp_method can NOT be set to scaled to vcmax (0) when CN is on!\n"); + $log->fatal_error("leafresp_method can NOT be set to scaled to vcmax (0) when CN is on!"); } # And when CN off, must NOT be anything besides scaled by vxmac25top } else { if ( $nl->get_value('leafresp_method') != 0 ) { - fatal_error("leafresp_method can NOT be set to anything besides scaled to vcmax (0) when bgc_mode==sp!\n"); + $log->fatal_error("leafresp_method can NOT be set to anything besides scaled to vcmax (0) when bgc_mode==sp!"); } } } @@ -3191,12 +3261,12 @@ sub setup_logic_photosyns { #------------------------------------------------------------------------------- sub setup_logic_canopy { - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; # # Canopy state # if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'leaf_mr_vcm', 'phys'=>$nl_flags->{'phys'} ) } } @@ -3205,25 +3275,25 @@ sub setup_logic_canopy { sub setup_logic_popd_streams { # population density streams require clm4_5/clm5_0 and CN/BGC - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - if ( value_is_true($nl_flags->{'cnfireson'}) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'popdensmapalgo', 'hgrid'=>$nl_flags->{'res'}, + if ( &value_is_true($nl_flags->{'cnfireson'}) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'popdensmapalgo', 'hgrid'=>$nl_flags->{'res'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'}, 'cnfireson'=>$nl_flags->{'cnfireson'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_popdens', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_popdens', 'phys'=>$nl_flags->{'phys'}, 'cnfireson'=>$nl_flags->{'cnfireson'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_popdens', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_popdens', 'phys'=>$nl_flags->{'phys'}, 'cnfireson'=>$nl_flags->{'cnfireson'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); # Set align year, if first and last years are different - if ( $nl->get_value('stream_year_first_popdens') != + if ( $nl->get_value('stream_year_first_popdens') != $nl->get_value('stream_year_last_popdens') ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_popdens', 'sim_year'=>$nl_flags->{'sim_year'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_popdens', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}, 'cnfireson'=>$nl_flags->{'cnfireson'}); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_popdens', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_popdens', 'phys'=>$nl_flags->{'phys'}, 'cnfireson'=>$nl_flags->{'cnfireson'}, 'hgrid'=>"0.5x0.5" ); } else { # If bgc is NOT CN/CNDV or fire_method==nofire then make sure none of the popdens settings are set @@ -3231,9 +3301,9 @@ sub setup_logic_popd_streams { defined($nl->get_value('stream_year_last_popdens')) || defined($nl->get_value('model_year_align_popdens')) || defined($nl->get_value('stream_fldfilename_popdens')) ) { - fatal_error("When bgc is SP (NOT CN or BGC) or fire_method==nofire none of: stream_year_first_popdens,\n" . + $log->fatal_error("When bgc is SP (NOT CN or BGC) or fire_method==nofire none of: stream_year_first_popdens,\n" . "stream_year_last_popdens, model_year_align_popdens, nor\n" . - "stream_fldfilename_popdens can be set!\n"); + "stream_fldfilename_popdens can be set!"); } } } @@ -3243,25 +3313,25 @@ sub setup_logic_popd_streams { sub setup_logic_urbantv_streams { # urban time varying streams require clm4_5/clm5_0 - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urbantvmapalgo', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'urbantvmapalgo', 'hgrid'=>$nl_flags->{'res'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_urbantv', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_urbantv', 'phys'=>$nl_flags->{'phys'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_urbantv', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_urbantv', 'phys'=>$nl_flags->{'phys'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); # Set align year, if first and last years are different - if ( $nl->get_value('stream_year_first_urbantv') != + if ( $nl->get_value('stream_year_first_urbantv') != $nl->get_value('stream_year_last_urbantv') ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_urbantv', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_urbantv', 'phys'=>$nl_flags->{'phys'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_urbantv', 'phys'=>$nl_flags->{'phys'}, 'hgrid'=>"0.9x1.25" ); } } @@ -3270,26 +3340,26 @@ sub setup_logic_urbantv_streams { sub setup_logic_lightning_streams { # lightning streams require clm4_5/clm5_0 and CN/BGC - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - if ( value_is_true($nl_flags->{'cnfireson'}) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lightngmapalgo', 'use_cn'=>$nl_flags->{'use_cn'}, + if ( &value_is_true($nl_flags->{'cnfireson'}) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lightngmapalgo', 'use_cn'=>$nl_flags->{'use_cn'}, 'hgrid'=>$nl_flags->{'res'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_lightng', 'use_cn'=>$nl_flags->{'use_cn'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_lightng', 'use_cn'=>$nl_flags->{'use_cn'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_lightng', 'use_cn'=>$nl_flags->{'use_cn'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_lightng', 'use_cn'=>$nl_flags->{'use_cn'}, 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); # Set align year, if first and last years are different - if ( $nl->get_value('stream_year_first_lightng') != + if ( $nl->get_value('stream_year_first_lightng') != $nl->get_value('stream_year_last_lightng') ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_lightng', 'sim_year'=>$nl_flags->{'sim_year'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_lightng', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_lightng', 'use_cn'=>$nl_flags->{'use_cn'}, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_lightng', 'use_cn'=>$nl_flags->{'use_cn'}, 'hgrid'=>$nl_flags->{'light_res'} ); } else { # If bgc is NOT CN/CNDV then make sure none of the Lightng settings are set @@ -3297,9 +3367,9 @@ sub setup_logic_lightning_streams { defined($nl->get_value('stream_year_last_lightng')) || defined($nl->get_value('model_year_align_lightng')) || defined($nl->get_value('stream_fldfilename_lightng')) ) { - fatal_error("When bgc is SP (NOT CN or BGC) or fire_method==nofire none of: stream_year_first_lightng,\n" . + $log->fatal_error("When bgc is SP (NOT CN or BGC) or fire_method==nofire none of: stream_year_first_lightng,\n" . "stream_year_last_lightng, model_year_align_lightng, nor\n" . - "stream_fldfilename_lightng can be set!\n"); + "stream_fldfilename_lightng can be set!"); } } } @@ -3311,12 +3381,12 @@ sub setup_logic_dry_deposition { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; if ($opts->{'drydep'} ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'drydep_list'); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'drydep_method'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'drydep_list'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'drydep_method'); } else { if ( defined($nl->get_value('drydep_list')) || defined($nl->get_value('drydep_method')) ) { - fatal_error("drydep_list or drydep_method defined, but drydep option NOT set\n"); + $log->fatal_error("drydep_list or drydep_method defined, but drydep option NOT set"); } } } @@ -3328,15 +3398,15 @@ sub setup_logic_fire_emis { if ($opts->{'fire_emis'} ) { if ( $physv->as_long() < $physv->as_long("clm4_5") ) { - fatal_error("fire_emis option can NOT be set for CLM versions before clm4_5"); + $log->fatal_error("fire_emis option can NOT be set for CLM versions before clm4_5"); } - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_emis_factors_file'); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_emis_specifier'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_emis_factors_file'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fire_emis_specifier'); } else { if ( defined($nl->get_value('fire_emis_elevated')) || defined($nl->get_value('fire_emis_factors_file')) || defined($nl->get_value('fire_emis_specifier')) ) { - fatal_error("fire_emission setting defined: fire_emis_elevated, fire_emis_factors_file, or fire_emis_specifier, but fire_emis option NOT set\n"); + $log->fatal_error("fire_emission setting defined: fire_emis_elevated, fire_emis_factors_file, or fire_emis_specifier, but fire_emis option NOT set"); } } } @@ -3349,7 +3419,7 @@ sub setup_logic_megan { my $var = "megan"; if ( $opts->{$var} eq "default" ) { - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan', clm_accelerated_spinup=>$nl_flags->{'clm_accelerated_spinup'} ); $nl_flags->{$var} = $nl->get_value($var); } else { @@ -3357,17 +3427,17 @@ sub setup_logic_megan { } if ($nl_flags->{'megan'} ) { - if ( value_is_true( $nl_flags->{'use_ed'} ) ) { - fatal_error("MEGAN can NOT be on when ED is also on.\n" . - " Use the '-no-megan' option when '-bgc ed' is activated"); + if ( &value_is_true( $nl_flags->{'use_fates'} ) ) { + $log->fatal_error("MEGAN can NOT be on when ED is also on.\n" . + " Use the '-no-megan' option when '-bgc fates' is activated"); } - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan_specifier'); - check_megan_spec( $nl, $definition ); - add_default($opts->{'test'}, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan_factors_file'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan_specifier'); + check_megan_spec( $opts, $nl, $definition ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'megan_factors_file'); } else { if ( defined($nl->get_value('megan_specifier')) || defined($nl->get_value('megan_factors_file')) ) { - fatal_error("megan_specifier or megan_factors_file defined, but megan option NOT set\n"); + $log->fatal_error("megan_specifier or megan_factors_file defined, but megan option NOT set"); } } } @@ -3376,31 +3446,31 @@ sub setup_logic_megan { sub setup_logic_lai_streams { # lai streams require clm4_5/clm5_0 - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - if ( $nl_flags->{'use_crop'} eq ".true." && $nl_flags->{'use_lai_streams'} eq ".true." ) { - fatal_error("turning use_lai_streams on is incompatable with use_crop set to true."); + if ( &value_is_true($nl_flags->{'use_crop'}) && &value_is_true($nl_flags->{'use_lai_streams'}) ) { + $log->fatal_error("turning use_lai_streams on is incompatable with use_crop set to true."); } if ( $nl_flags->{'bgc_mode'} eq "sp" ) { - - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_lai_streams'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lai_mapalgo', + + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_lai_streams'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lai_mapalgo', 'hgrid'=>$nl_flags->{'res'} ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_lai', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_lai', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_lai', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_lai', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); # Set align year, if first and last years are different - if ( $nl->get_value('stream_year_first_lai') != + if ( $nl->get_value('stream_year_first_lai') != $nl->get_value('stream_year_last_lai') ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_lai', 'sim_year'=>$nl_flags->{'sim_year'}, 'sim_year_range'=>$nl_flags->{'sim_year_range'}); } - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_lai', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_lai', 'hgrid'=>"360x720cru" ); } else { # If bgc is CN/CNDV then make sure none of the LAI settings are set @@ -3408,9 +3478,9 @@ sub setup_logic_lai_streams { defined($nl->get_value('stream_year_last_lai')) || defined($nl->get_value('model_year_align_lai')) || defined($nl->get_value('stream_fldfilename_lai')) ) { - fatal_error("When bgc is NOT SP none of the following can be set: stream_year_first_lai,\n" . + $log->fatal_error("When bgc is NOT SP none of the following can be set: stream_year_first_lai,\n" . "stream_year_last_lai, model_year_align_lai, nor\n" . - "stream_fldfilename_lai (eg. don't use this option with BGC,CN,CNDV nor BGDCV).\n"); + "stream_fldfilename_lai (eg. don't use this option with BGC,CN,CNDV nor BGDCV)."); } } } @@ -3420,101 +3490,123 @@ sub setup_logic_lai_streams { sub setup_logic_soilwater_movement { # soilwater_movement require clm4_5/clm5_0 - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soilwater_movement_method' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'upper_boundary_condition' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lower_boundary_condition' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dtmin' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'verySmall' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'xTolerUpper' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'xTolerLower' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'expensive' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'inexpensive' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'flux_calculation' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soilwater_movement_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'upper_boundary_condition' ); + + my $soilmtd = $nl->get_value("soilwater_movement_method"); + my $use_bed = $nl->get_value('use_bedrock' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, + 'lower_boundary_condition', 'vichydro'=>$nl_flags->{'vichydro'}, + 'soilwater_movement_method'=>$soilmtd, 'use_bedrock'=>$use_bed + ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'dtmin' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'verySmall' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'xTolerUpper' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'xTolerLower' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'expensive' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'inexpensive' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'flux_calculation' ); } } #------------------------------------------------------------------------------- sub setup_logic_century_soilbgcdecompcascade { - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - if ( $physv->as_long() >= $physv->as_long("clm4_5") && - (&value_is_true($nl->get_value('use_cn')) || &value_is_true($nl->get_value('use_ed'))) && + if ( $physv->as_long() >= $physv->as_long("clm4_5") && + (&value_is_true($nl->get_value('use_cn')) || &value_is_true($nl->get_value('use_fates'))) && &value_is_true($nl->get_value('use_century_decomp')) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'initial_Cstocks', - 'use_cn' => $nl->get_value('use_cn'), 'use_ed' => $nl->get_value('use_ed'), + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'initial_Cstocks', + 'use_cn' => $nl->get_value('use_cn'), 'use_fates' => $nl->get_value('use_fates'), + 'use_century_decomp' => $nl->get_value('use_century_decomp') ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'initial_Cstocks_depth', + 'use_cn' => $nl->get_value('use_cn'), 'use_fates' => $nl->get_value('use_fates'), 'use_century_decomp' => $nl->get_value('use_century_decomp') ); } } +#------------------------------------------------------------------------------- + +sub setup_logic_cnvegcarbonstate { + # MUST be AFTER: setup_logic_dynamic_plant_nitrogen_alloc as depends on mm_nuptake_opt which is set there + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + + if ( $physv->as_long() >= $physv->as_long("clm4_5") && &value_is_true($nl->get_value('use_cn')) ) { + my $mmnuptake = $nl->get_value('mm_nuptake_opt'); + if ( ! defined($mmnuptake) ) { $mmnuptake = ".false."; } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'initial_vegC', + 'use_cn' => $nl->get_value('use_cn'), 'mm_nuptake_opt' => $mmnuptake ); + } +} #------------------------------------------------------------------------------- sub setup_logic_rooting_profile { - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'rooting_profile_method_water' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'rooting_profile_method_carbon' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'rooting_profile_method_water' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'rooting_profile_method_carbon' ); } } #------------------------------------------------------------------------------- sub setup_logic_friction_vel { - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'zetamaxstable' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'zetamaxstable' ); } } #------------------------------------------------------------------------------- sub setup_logic_soil_resis { - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soil_resis_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soil_resis_method' ); } } #------------------------------------------------------------------------------- sub setup_logic_hillslope_hydrology { # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_geomorphology' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_geomorphology' ); } } #------------------------------------------------------------------------------- sub setup_logic_canopyfluxes { - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_undercanopy_stability' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_undercanopy_stability' ); } } #------------------------------------------------------------------------------- sub setup_logic_canopyhydrology { - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'interception_fraction' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'maximum_leaf_wetted_fraction' ); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_clm5_fpi' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'interception_fraction' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'maximum_leaf_wetted_fraction' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_clm5_fpi' ); } } @@ -3524,27 +3616,31 @@ sub setup_logic_snowpack { # # Snowpack related options # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; if ($physv->as_long() >= $physv->as_long("clm4_5")) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nlevsno'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'h2osno_max'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'int_snow_max'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'n_melt_glcmec'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'wind_dependent_snow_density'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_overburden_compaction_method'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lotmp_snowdensity_method'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'upplim_destruct_metamorph'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'nlevsno'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'h2osno_max'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'int_snow_max'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'n_melt_glcmec'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'wind_dependent_snow_density'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_overburden_compaction_method'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lotmp_snowdensity_method'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'upplim_destruct_metamorph'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fresh_snw_rds_max'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow_glc'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow_glc_ela'); if (remove_leading_and_trailing_quotes($nl->get_value('snow_overburden_compaction_method')) eq 'Vionnet2012') { # overburden_compress_tfactor isn't used if we're using the Vionnet2012 # snow overburden compaction method, so make sure the user hasn't tried # to set it if (defined($nl->get_value('overburden_compress_tfactor'))) { - fatal_error('overburden_compress_tfactor is set, but does not apply when using snow_overburden_compaction_method=Vionnet2012'); + $log->fatal_error('overburden_compress_tfactor is set, but does not apply when using snow_overburden_compaction_method=Vionnet2012'); } } else { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'overburden_compress_tfactor'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'overburden_compress_tfactor'); } } } @@ -3555,22 +3651,22 @@ sub setup_logic_atm_forcing { # # Options related to atmospheric forcings # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + if ($physv->as_long() >= $physv->as_long("clm4_5")) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glcmec_downscale_longwave'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'repartition_rain_snow'); - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lapse_rate'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'glcmec_downscale_longwave'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'repartition_rain_snow'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lapse_rate'); my $var; foreach $var ("lapse_rate_longwave", "longwave_downscaling_limit") { - if ( $nl->get_value("glcmec_downscale_longwave") =~ /$TRUE/i ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); + if ( &value_is_true($nl->get_value("glcmec_downscale_longwave")) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); } else { if (defined($nl->get_value($var))) { - fatal_error("$var can only be set if glcmec_downscale_longwave is true"); + $log->fatal_error("$var can only be set if glcmec_downscale_longwave is true"); } } } @@ -3579,11 +3675,11 @@ sub setup_logic_atm_forcing { "precip_repartition_glc_all_rain_t", "precip_repartition_nonglc_all_snow_t", "precip_repartition_nonglc_all_rain_t") { - if ( $nl->get_value("repartition_rain_snow") =~ /$TRUE/i ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); + if ( &value_is_true($nl->get_value("repartition_rain_snow")) ){ + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var); } else { if (defined($nl->get_value($var))) { - fatal_error("$var can only be set if repartition_rain_snow is true"); + $log->fatal_error("$var can only be set if repartition_rain_snow is true"); } } } @@ -3592,18 +3688,32 @@ sub setup_logic_atm_forcing { #------------------------------------------------------------------------------- -sub setup_logic_ed { +sub setup_logic_lnd2atm { + # + # Options related to fields sent to atmosphere + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + + if ($physv->as_long() >= $physv->as_long("clm4_5")) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'melt_non_icesheet_ice_runoff'); + } +} + +#------------------------------------------------------------------------------- + +sub setup_logic_fates { # # Set some default options related to Ecosystem Demography - # - my ($test_files, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + # + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - if ($physv->as_long() >= $physv->as_long("clm4_5") && value_is_true( $nl_flags->{'use_ed'}) ) { - add_default($test_files, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_ed_spit_fire', 'use_ed'=>$nl_flags->{'use_ed'} ); + if ($physv->as_long() >= $physv->as_long("clm4_5") && &value_is_true( $nl_flags->{'use_fates'}) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_fates_spitfire', 'use_fates'=>$nl_flags->{'use_fates'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fates_paramfile', 'phys'=>$nl_flags->{'phys'}); } } -#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- sub write_output_files { my ($opts, $nl_flags, $defaults, $nl, $physv) = @_; @@ -3630,24 +3740,24 @@ sub write_output_files { #} } else { - @groups = qw(clm_inparm ndepdyn_nml popd_streams urbantv_streams light_streams - lai_streams atm2lnd_inparm clm_canopyhydrology_inparm cnphenology - clm_soilhydrology_inparm dynamic_subgrid + @groups = qw(clm_inparm ndepdyn_nml popd_streams urbantv_streams light_streams + lai_streams atm2lnd_inparm lnd2atm_inparm clm_canopyhydrology_inparm cnphenology + clm_soilhydrology_inparm dynamic_subgrid cnvegcarbonstate finidat_consistency_checks dynpft_consistency_checks clm_initinterp_inparm century_soilbgcdecompcascade soilhydrology_inparm luna friction_velocity mineral_nitrogen_dynamics - soilwater_movement_inparm rooting_profile_inparm - soil_resis_inparm bgc_shared canopyfluxes_inparm + soilwater_movement_inparm rooting_profile_inparm + soil_resis_inparm bgc_shared canopyfluxes_inparm aerosol clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm hillslope_hydrology_inparm cnprecision_inparm clm_glacier_behavior crop irrigation_inparm); - #@groups = qw(clm_inparm clm_canopyhydrology_inparm clm_soilhydrology_inparm + #@groups = qw(clm_inparm clm_canopyhydrology_inparm clm_soilhydrology_inparm # finidat_consistency_checks dynpft_consistency_checks); # Eventually only list namelists that are actually used when CN on #if ( $nl_flags->{'bgc_mode'} eq "cn" ) { # push @groups, qw(ndepdyn_nml popd_streams light_streams); #} - if ( $nl_flags->{'use_lch4'} eq ".true." ) { + if ( &value_is_true($nl_flags->{'use_lch4'}) ) { push @groups, "ch4par_in"; } if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { @@ -3655,8 +3765,10 @@ sub write_output_files { push @groups, "cnmresp_inparm"; push @groups, "photosyns_inparm"; push @groups, "cnfire_inparm"; + push @groups, "cn_general"; push @groups, "nitrif_inparm"; push @groups, "lifire_inparm"; + push @groups, "ch4finundated"; push @groups, "clm_canopy_inparm"; } } @@ -3664,13 +3776,13 @@ sub write_output_files { my $outfile; $outfile = "$opts->{'dir'}/lnd_in"; $nl->write($outfile, 'groups'=>\@groups, 'note'=>"$note" ); - verbose_message("Writing clm namelist to $outfile"); + $log->verbose_message("Writing clm namelist to $outfile"); # Drydep, fire-emission or MEGAN namelist for driver @groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm); $outfile = "$opts->{'dir'}/drv_flds_in"; $nl->write($outfile, 'groups'=>\@groups, 'note'=>"$note" ); - verbose_message("Writing @groups namelists to $outfile"); + $log->verbose_message("Writing @groups namelists to $outfile"); } sub write_output_real_parameter_file { @@ -3679,7 +3791,7 @@ sub write_output_real_parameter_file { # Output real parameters if ( defined($opts->{'output_reals_filename'}) ) { my $file = $opts->{'output_reals_filename'}; - my $fh = IO::File->new($file, '>>') or fatal_error("can't create real parameter filename: $file"); + my $fh = IO::File->new($file, '>>') or $log->fatal_error("can't create real parameter filename: $file"); foreach my $var ( $definition->get_var_names() ) { my $type = $definition->get_var_type($var); my $doc = $definition->get_var_doc($var); @@ -3726,7 +3838,7 @@ sub add_default { # $defaults -- the namelist defaults object # $inputdata_rootdir -- CESM inputdata root directory - my $test_files = shift; + my $opts = shift; my $inputdata_rootdir = shift; my $definition = shift; my $defaults = shift; @@ -3734,6 +3846,7 @@ sub add_default { my $var = shift; my %settings = @_; + my $test_files = $opts->{'test'}; #my $nl = shift; # namelist object #my $var = shift; # name of namelist variable #my %settings = @_; # options @@ -3747,7 +3860,7 @@ sub add_default { my $group = $definition->get_group_name($var); unless ($group) { my $fname = $definition->get_file_name(); - fatal_error("variable \"$var\" not found in namelist definition file $fname.\n"); + $log->fatal_error("variable \"$var\" not found in namelist definition file $fname."); } # check whether the variable has a value in the namelist object -- if so then skip to end @@ -3779,11 +3892,11 @@ sub add_default { unless ( defined($val) ) { unless ($settings{'nofail'}) { if ($var eq 'finidat') { - warning("No default value found for $var.\n" . - " Are defaults provided for this resolution and land mask?\n"); + $log->message("No default value found for $var.\n" . + " Are defaults provided for this resolution and land mask?" ); } else { - fatal_error("No default value found for $var.\n" . - " Are defaults provided for this resolution and land mask?\n"); + $log->fatal_error("No default value found for $var.\n" . + " Are defaults provided for this resolution and land mask?"); } } else { @@ -3804,7 +3917,7 @@ sub add_default { if ($is_input_pathname eq 'abs') { $val = set_abs_filepath($val, $inputdata_rootdir); if ( $test_files and ($val !~ /null/) and (! -f "$val") ) { - fatal_error("file not found: $var = $val"); + $log->fatal_error("file not found: $var = $val"); } } } @@ -3976,7 +4089,7 @@ sub check_use_case_name { } elsif ( $string =~ /^_*($desc)$/ ) { # valid name } else { - fatal_error($diestring); + $log->fatal_error($diestring); } } elsif ( $use_case =~ /^20thC([a-zA-Z0-9_\.]*)_transient$/ ) { my $string = $1; @@ -3985,14 +4098,14 @@ sub check_use_case_name { } elsif ( $string =~ /^_*($desc)$/ ) { # valid name } else { - fatal_error($diestring); + $log->fatal_error($diestring); } } elsif ( $use_case =~ /^([0-9]+)_*($desc)_control$/ ) { # valid name } elsif ( $use_case =~ /^($desc)_pd$/ ) { # valid name } else { - fatal_error($diestring); + $log->fatal_error($diestring); } } @@ -4025,7 +4138,7 @@ sub validate_options { $old = $opts->{$opt}; $opts->{$opt} = valid_option($old, @expect) - or fatal_error("invalid value of $opt ($old) specified in $source\n" . + or $log->fatal_error("invalid value of $opt ($old) specified in $source\n" . "expected one of: @expect"); } else { print "Use cases are:...\n\n"; @@ -4036,13 +4149,13 @@ sub validate_options { &check_use_case_name( $1 ); $use_case = $1; } else { - fatal_error("Bad name for use case file = $file"); + $log->fatal_error("Bad name for use case file = $file"); } my $uc_defaults = Build::NamelistDefaults->new("$file", $cfg); printf "%15s = %s\n", $use_case, $uc_defaults->get_value("use_case_desc"); push @ucases, $use_case; } - exit_message("use cases : @ucases"); + $log->exit_message("use cases : @ucases"); } } } @@ -4090,7 +4203,7 @@ sub list_options { my $doc = $definition->get_var_doc( $var ); $doc =~ s/\n//; chomp( $doc ); - exit_message("valid values for $var ($doc) :\n" . + $log->exit_message("valid values for $var ($doc) :\n" . " Values: @valid_values\n" . " Default = $val\n" . " (NOTE: resolution and mask and other settings may influence what the default is)"); @@ -4113,12 +4226,12 @@ sub list_options { my $doc = $definition->get_var_doc( 'clm_demand' ); $doc =~ s/\n//; chomp( $doc ); - exit_message("valid values for $var ($doc) :\n" . + $log->exit_message("valid values for $var ($doc) :\n" . "Namelist options to require: @demands\n" . "any valid namelist item for clm_inparm can be set. However, not all are\n" . "available in the clm defaults file. The defaults are also dependent on\n" . "resolution and landmask, as well as other settings. Hence, the list above\n" . - "will vary depending on what you set for resolution and landmask.\n"); + "will vary depending on what you set for resolution and landmask."); } } } @@ -4129,7 +4242,7 @@ sub check_megan_spec { # # Check the megan specifier setting # - my ($nl, $definition) = @_; + my ($opts, $nl, $definition) = @_; my $megan_spec = $nl->get_value('megan_specifier'); my @megan_spec_list = split( /\s*,\s*/, $megan_spec ); @@ -4141,19 +4254,19 @@ sub check_megan_spec { my $warn = 0; foreach my $megan_cmpd ( @megan_cmpds ) { if ( ! $definition->is_valid_value( $var, $megan_cmpd, 'noquotes'=>1 ) ) { - warning("megan_compound $megan_cmpd NOT found in list"); + $log->warning("megan_compound $megan_cmpd NOT found in list" ); $warn++; } } if ( $warn > 0 ) { my @valid_values = $definition->get_valid_values( $var, 'noquotes'=>1 ); - warning("list of megan compounds includes:\n" . + $log->warning("list of megan compounds includes:\n" . "@valid_values\n" . - "Does your megan_factors_file include more coumpounds?\n" . - "If NOT your simulation will fail.\n"); + "Does your megan_factors_file include more compounds?\n" . + "If NOT your simulation will fail." ); } } else { - fatal_error("Bad format for megan_specifier = $megan_spec"); + $log->fatal_error("Bad format for megan_specifier = $megan_spec"); } } } @@ -4213,7 +4326,7 @@ sub logical_to_fortran { $result = ".false."; } else { - fatal_error("Unexpected value in logical_to_fortran: $var\n"); + $log->fatal_error("Unexpected value in logical_to_fortran: $var"); } return $result; @@ -4245,6 +4358,13 @@ sub value_is_true { # Return true if the given namelist value is .true. # An undefined value is treated as false (with the assumption that false is the default in the code) my ($val) = @_; + + # Some regular expressions... + ###my $TRUE = qr/\.true\./i; + ###my $FALSE = qr/\.false\./i; + # **N.B.** the use of qr// for precompiling regexps isn't supported until perl 5.005. + my $TRUE = '\.?true\.?|[t]'; + my $FALSE = '\.?false\.?|[f]'; my $is_true = 0; if (defined($val)) { if ($val =~ /$TRUE/i) { @@ -4265,56 +4385,16 @@ sub version { my $logfile = "$cfgdir/../doc/ChangeLog"; - my $fh = IO::File->new($logfile, '<') or fatal_error("can't open ChangeLog file: $logfile"); + my $fh = IO::File->new($logfile, '<') or $log->fatal_error("can't open ChangeLog file: $logfile"); while (my $line = <$fh>) { if ($line =~ /^Tag name:\s*([a-zA-Z0-9_. -]*[clmcesm0-9_.-]+)$/ ) { - exit_message("$1\n"); + $log->exit_message("$1"); } } } -#------------------------------------------------------------------------------- -# Some simple subroutines to print messages out - -sub message { - my ($message) = @_; - print "$message\n"; -} - -sub verbose_message { - my ($message) = @_; - if ($verbosity >= $print_verbose) { - print "$message\n"; - } -} - -#------------------------------------------------------------------------------- -# Some simple subroutines to do a clean exit, print warning, or a fatal error - -sub exit_message { - my ($message) = @_; - print "${ProgName} : $message\n"; - exit; -} - -#------------------------------------------------------------------------------- - -sub warning { - my ($message) = @_; - my $func_name = (caller(1))[3]; - print "Warning : ${ProgName}::${func_name}() : $message\n"; -} - -#------------------------------------------------------------------------------- - -sub fatal_error { - my ($message) = @_; - my $func_name = (caller(1))[3]; - die "ERROR : ${ProgName}::${func_name}() : $message\n"; -} - #------------------------------------------------------------------------------- sub main { @@ -4322,18 +4402,17 @@ sub main { $nl_flags{'cfgdir'} = dirname(abs_path($0)); my %opts = process_commandline(\%nl_flags); + my $cfgdir = $nl_flags{'cfgdir'}; + check_for_perl_utils($cfgdir, \%opts); - version($nl_flags{'cfgdir'}) if $opts{'version'}; - set_print_level(\%opts); - - check_for_perl_utils($nl_flags{'cfgdir'}); - my $cfg = read_configure_definition($nl_flags{'cfgdir'}, \%opts); + $log = namelist_files::LogMessages->new( $ProgName, \%opts ); # global + version($cfgdir) if $opts{'version'}; + my $cfg = read_configure_definition($cfgdir, \%opts); - my $physv = config_files::clm_phys_vers->new( $cfg->get('phys') ); - my $cesmroot = abs_path( "$nl_flags{'cfgdir'}/../../../"); - my $drvblddir = "$cesmroot/cime/driver_cpl/bld"; - my $definition = read_namelist_definition($drvblddir, \%opts, \%nl_flags, $physv); - my $defaults = read_namelist_defaults($drvblddir, \%opts, \%nl_flags, $cfg, $physv); + my $physv = config_files::clm_phys_vers->new( $cfg->get('phys') ); + my $cesmroot = abs_path( "$cfgdir/../../../"); + my $definition = read_namelist_definition($cfgdir, \%opts, \%nl_flags, $physv); + my $defaults = read_namelist_defaults($cfgdir, \%opts, \%nl_flags, $cfg, $physv); # List valid values if asked for list_options(\%opts, $definition, $defaults); @@ -4362,6 +4441,7 @@ sub main { if ($opts{'inputdata'}) { check_input_files($nl, $nl_flags{'inputdata_rootdir'}, $opts{'inputdata'}, $definition); } + $log->final_exit("Successfully made CLM namelist file"); } #------------------------------------------------------------------------------- diff --git a/bld/configure b/bld/configure index 6e18a4ed58..099d738818 100755 --- a/bld/configure +++ b/bld/configure @@ -650,11 +650,11 @@ sub write_filepath_cesmbld "soilbiogeochem", "dyn_subgrid", "init_interp", - "ED", - "ED/main", - "ED/biogeophys", - "ED/biogeochem", - "ED/fire", + "fates", + "fates/main", + "fates/biogeophys", + "fates/biogeochem", + "fates/fire", "utils", "cpl" ); diff --git a/bld/listDefaultNamelist.pl b/bld/listDefaultNamelist.pl index b98bc5262a..063b1e6af0 100755 --- a/bld/listDefaultNamelist.pl +++ b/bld/listDefaultNamelist.pl @@ -51,13 +51,10 @@ # Defaults my $cesmroot = abs_path( "$cfgdir/../../../"); -my $datmblddir = "$cesmroot/cime/components/data_comps/datm/bld"; -my $drvblddir = "$cesmroot/cime/driver_cpl/bld"; # The namelist defaults file contains default values for all required namelist variables. my @nl_defaults_files = ( "$cfgdir/namelist_files/namelist_defaults_overall.xml", - "$drvblddir/namelist_files/namelist_defaults_drv.xml", - #"$datmblddir/namelist_files/namelist_defaults_datm.xml", # in version 2 format can't be read + "$cfgdir/namelist_files/namelist_defaults_drv.xml", ); my $list = "clm.input_data_list"; my %list_of_all_files; @@ -101,7 +98,7 @@ sub GetListofNeededFiles { my $inputopts_ref = shift; my $settings_ref = shift; my $files_ref = shift; - + my $defaults_ref = &queryDefaultXML::ReadDefaultXMLFile( $inputopts_ref, $settings_ref ); my @keys = keys(%$defaults_ref); my $csmdata = $$inputopts_ref{'csmdata'}; @@ -114,7 +111,7 @@ sub GetListofNeededFiles { $value =~ m#$csmdata/(.+?)/([^/]+)$#; my $dir = $1; my $file = $2; - + # If file is already in the list then do NOT do anything if ( defined($list_of_all_files{"$dir/$file"} ) ) { # Test that this file exists @@ -149,7 +146,7 @@ sub GetListofNeededFiles { #----------------------------------------------------------------------------------------------- - my %opts = ( + my %opts = ( res => undef, silent => undef, csmdata => "default", @@ -191,9 +188,7 @@ sub GetListofNeededFiles { } } my %inputopts; - my $datmblddir = "$cfgdir/../../../cime/components/data_comps/datm/bld"; my @nl_definition_files = ( - #"$datmblddir/namelist_files/namelist_definition_datm.xml", # version 2 format can't be used "$cfgdir/namelist_files/namelist_definition_$opts{'phys'}.xml" ); $inputopts{'nldef_files'} = \@nl_definition_files; @@ -255,10 +250,10 @@ sub GetListofNeededFiles { # $settings{'sim_year_range'} = "constant"; my @rcps = $definition->get_valid_values( "rcp", 'noquotes'=>1 ); - $settings{'rcp'} = $rcps[0]; + $settings{'rcp'} = $rcps[0]; YEAR: foreach my $sim_year ( $definition->get_valid_values( "sim_year", 'noquotes'=>1 ) ) { print "sim_year = $sim_year\n" if $printing; - $settings{'sim_year'} = $sim_year; + $settings{'sim_year'} = $sim_year; if ( $sim_year ne 1850 && $sim_year ne 2000 && $sim_year > 1800 ) { next YEAR; } my @bgcsettings = $cfg->get_valid_values( "bgc" ); @@ -293,9 +288,9 @@ sub GetListofNeededFiles { $settings{'maxpft'} = 17; } my @irrigset; - if ( $glc_nec == 0 && $sim_year == 2000 ) { + if ( $glc_nec == 0 && $sim_year == 2000 ) { @irrigset= ( ".true.", ".false." ); - } else { + } else { @irrigset= ( ".false." ); } # diff --git a/bld/namelist_files/LogMessages.pm b/bld/namelist_files/LogMessages.pm new file mode 100755 index 0000000000..77f0569bcc --- /dev/null +++ b/bld/namelist_files/LogMessages.pm @@ -0,0 +1,244 @@ +package namelist_files::LogMessages; +my $pkg_nm = 'namelist_files::LogMessages'; +#----------------------------------------------------------------------------------------------- +# +# SYNOPSIS +# +# require namelist_files::LogMessages; +# +# my %opts; +# my $log = namelist_files::LogMessages->new("ProgName", \%opts); +# $log->message("message to print"); +# $log->verbose_message("message to print only if verbose mode is on"); +# $log->warning("Warning message"); +# $log->exit_message("clean exit"); +# $log->fatal_error("die with fatal error"); +# $log->final_exit("Final message to send (and exit"); +# +# +# DESCRIPTION +# +# Handles log messages for perl. Sets up log messages according to verbose +# or silent setting. It also handles warnings printing them, but on finalization +# aborting unless ignore_warnings was set. +# +# COLLABORATORS: None +# +#----------------------------------------------------------------------------------------------- +# +# Date Author Modification +# 10/06/2017 Erik Kluzek creation +# +#-------------------------------------------------------------------------------------------- + +use strict; +#use warnings; +#use diagnostics; + +#------------------------------------------------------------------------------- + +sub new { + my $class = shift; + my $ProgName = shift; + my %opts = %{shift()}; + + my $nm = "$class\:\:new"; + my $self = {}; + bless($self, $class); + $self->{'nwarns'} = 0; + $self->{'verbosity'} = 1; + $self->{'NO_EXIT'} = $opts{'NO_EXIT'}; + $self->{'ProgName'} = $ProgName; + $self->{'ignore_warnings'} = $opts{'ignore_warnings'}; + $self->__set_print_level( \%opts ); + return( $self ); +} + + +#------------------------------------------------------------------------------- + +sub __set_print_level { + my $self = shift; + # Define print levels: + # 0 - only issue fatal error messages + # 1 - only informs what files are created (default) + # 2 - verbose + my %opts = %{shift()}; + + if ( $opts{'silent'} && $opts{'verbose'} ) { + $self->fatal_error( "Can not set both the -silent and the -verbose options -- set one or the other" ); + } + my $verbosity = 1; + if ($opts{'silent'}) { $verbosity = 0; } + if ($opts{'verbose'}) { $verbosity = 2; } + $self->{'verbosity'} = $verbosity; + $self->{'print_verbose'} = 2; +} + +#------------------------------------------------------------------------------- + +sub message { + my $self = shift; + my ($message) = @_; + if ($self->{'verbosity'} > 0) { + print "$message\n"; + } +} + +#------------------------------------------------------------------------------- + +sub verbose_message { + my $self = shift; + + my ($message) = @_; + if ($self->{'verbosity'} >= $self->{'print_verbose'}) { + print "$message\n"; + } +} +#------------------------------------------------------------------------------- + +sub nwarns { + my $self = shift; + + return( $self->{'nwarns'} ); +} + +#------------------------------------------------------------------------------- + +sub final_exit { + my $self = shift; + my ($message) = @_; + if ( $self->{'nwarns'} > 0 ) { + $self->message( "\n\nYou ran with the -ignore_warnings options and allowed $self->{'nwarns'} to go past\n" ); + } + $self->verbose_message( $message ); + if ( $self->{'NO_EXIT'} ) { + die + } else { + exit; + } +} + +#------------------------------------------------------------------------------- +# Some simple subroutines to do a clean exit, print warning, or a fatal error + +sub exit_message { + my $self = shift; + my ($message) = @_; + print "$self->{ProgName} : $message\n"; + if ( $self->{'NO_EXIT'} ) { + die + } else { + exit; + } +} + +#------------------------------------------------------------------------------- + +sub warning { + my $self = shift; + my $message = shift; + + $self->{'nwarns'} = $self->{'nwarns'} + 1; + my $func_name = (caller(1))[3]; + if ( $self->{'ignore_warnings'} ) { + print "Warning : $self->{ProgName}::${func_name}() : $message\n\n"; + } else { + die "Warning : $self->{ProgName}::${func_name}() : $message\n" . + " -- Add -ignore_warnings option to CLM_BLDNML_OPTS to ignore this warning\n\n"; + } +} + +#------------------------------------------------------------------------------- + +sub fatal_error { + my $self = shift; + my ($message) = @_; + my $func_name = (caller(1))[3]; + die "ERROR : $self->{ProgName}::${func_name}() : $message\n"; +} + +#------------------------------------------------------------------------------- + +#----------------------------------------------------------------------------------------------- +# Unit testing of above +#----------------------------------------------------------------------------------------------- +if ( ! defined(caller) && $#ARGV == -1 ) { + package LogMessage_unit_tester; + + require Test::More; + Test::More->import( ); + + plan( tests=>11 ); + + sub testit { + print "unit tester\n"; + my %opts; + my $message; + + # Standard verbose level, test all methods + $opts{'NO_EXIT'} = 1; + my $log = namelist_files::LogMessages->new("ProgName", \%opts); + isa_ok($log, "namelist_files::LogMessages", "Created LogMessages object"); + $log->message("message to print"); + $log->verbose_message("YOU SHOULD NOT SEE THIS MESSAGE BECAUSE IT IS VERBOSE AND VERBOSE NOT ON"); + $message = "Warning message"; + is ( $log->nwarns(), 0, "Make sure have zero warnings" ); + eval{ $log->warning($message); }; + like( $@, qr/$message/, "check that a warning dies without ignore_warnings option" ); + is ( $log->nwarns(), 1, "Make sure have one warning" ); + $message = "die with fatal error"; + eval{ $log->fatal_error($message); }; + like( $@, qr/$message/, "check that a fatal_error dies" ); + $message = "exit with exit message"; + eval{ $log->exit_message($message); }; + like( $@, qr/Died/, "check that a exit_message exits" ); + $message = "Final message to send"; + eval{ $log->final_exit($message); }; + like( $@, qr/Died/, "check that a final exits" ); + + # Test ignore_warnings option and verbose mode + $opts{'ignore_warnings'} = 1; + $opts{'verbose'} = 1; + $opts{'NO_EXIT'} = 1; + $log = namelist_files::LogMessages->new("ProgName", \%opts); + isa_ok($log, "namelist_files::LogMessages", "Created LogMessages object"); + $log->verbose_message("message to print only if verbose mode is on"); + $log->warning("Warning message"); + $log->warning("Warning message2"); + $log->warning("Warning message3"); + $log->warning("Warning message4"); + $log->warning("Warning message5"); + is ( $log->nwarns(), 5, "Make sure have five warnings" ); + eval{ $log->final_exit($message); }; + print "content: $@\n"; + like( $@, qr/Died/, "check that a final_exit with warning exits" ); + # silent mode + $opts{'ignore_warnings'} = 0; + $opts{'verbose'} = 0; + $opts{'silent'} = 1; + $opts{'NO_EXIT'} = 1; + $log = namelist_files::LogMessages->new("ProgName", \%opts); + $log->message("YOU SHOULD NOT SEE THIS MESSAGE BECAUSE SILENT MODE IS ON"); + $log->verbose_message("YOU SHOULD NOT SEE THIS VERBOSE MESSAGE BECAUSE SILENT MODE IS ON"); + # Should die with error if both silent and verbose mode is on + $opts{'ignore_warnings'} = 0; + $opts{'verbose'} = 1; + $opts{'silent'} = 1; + $opts{'NO_EXIT'} = 1; + eval{ $log = namelist_files::LogMessages->new("ProgName", \%opts); }; + print "content: $@\n"; + like( $@, qr/ERROR : /, "check that died if both verbose and silent mode is on" ); + print "\nSuccessfully ran all tests\n"; + } +} + +#----------------------------------------------------------------------------------------------- +# Determine if you should run the unit test or if this is being called from a require statement +#----------------------------------------------------------------------------------------------- + +if ( defined(caller) ) { + 1 # to make use or require happy +} elsif ( $#ARGV == -1 ) { + &LogMessage_unit_tester::testit(); +} diff --git a/bld/namelist_files/checkmapfiles.ncl b/bld/namelist_files/checkmapfiles.ncl index 7ceff5049c..6302615d1c 100644 --- a/bld/namelist_files/checkmapfiles.ncl +++ b/bld/namelist_files/checkmapfiles.ncl @@ -9,7 +9,7 @@ ; print( "Check that datm mapping files are consistent" ); - resolutions = (/ "128x256", "64x128", "48x96", "32x64", "8x16", "94x192", "0.23x0.31", "0.47x0.63", "0.9x1.25", "1.9x2.5", "2.5x3.33", "4x5", "10x15", "5x5_amazon", "1x1_tropicAtl", "1x1_camdenNJ", "1x1_vancouverCAN", "1x1_mexicocityMEX", "1x1_asphaltjungleNJ", "1x1_brazil", "1x1_urbanc_alpha", "1x1_numaIA", "1x1_smallvilleIA", "ne4np4", "ne16np4", "ne30np4", "ne60np4", "ne120np4", "ne240np4" /); + resolutions = (/ "128x256", "64x128", "48x96", "32x64", "8x16", "94x192", "0.23x0.31", "0.47x0.63", "0.9x1.25", "1.9x2.5", "2.5x3.33", "4x5", "10x15", "5x5_amazon", "1x1_camdenNJ", "1x1_vancouverCAN", "1x1_mexicocityMEX", "1x1_asphaltjungleNJ", "1x1_brazil", "1x1_urbanc_alpha", "1x1_numaIA", "1x1_smallvilleIA", "ne4np4", "ne16np4", "ne30np4", "ne60np4", "ne120np4", "ne240np4" /); space = " "; badres = 0 diff --git a/bld/namelist_files/namelist_defaults_clm4_0.xml b/bld/namelist_files/namelist_defaults_clm4_0.xml index 0131242d84..8365485f88 100644 --- a/bld/namelist_files/namelist_defaults_clm4_0.xml +++ b/bld/namelist_files/namelist_defaults_clm4_0.xml @@ -202,8 +202,6 @@ ic_tod="0" sim_year="2000" glc_nec="0" irrig=".false." crop="off" >lnd/clm2/init lnd/clm2/surfdata/surfdata_10x15_USGS_070307.nc -lnd/clm2/surfdata/surfdata_1x1_tropicAtl_testyr1000_c100527.nc - @@ -359,10 +355,6 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_simyr1850_c130311.nc lnd/clm2/surfdata_map/surfdata_ne240np4_simyr1850_c130313.nc - - -lnd/clm2/surfdata/surfdata_1x1_tropicAtl_simyr1850_c090923.nc - @@ -381,8 +373,6 @@ lnd/clm2/surfdata/surfdata_1x1_tropicAtl_simyr1850_c090923.nc lnd/clm2/surfdata/surfdata.pftdyn_1.9x2.5_simyr1850-2005_c091108.nc lnd/clm2/surfdata/surfdata.pftdyn_2.5x3.33_simyr1850-2005_c091109.nc lnd/clm2/surfdata/surfdata.pftdyn_10x15_simyr1850-2005_c100205.nc -lnd/clm2/surfdata/surfdata.pftdyn_1x1_tropicAtl_simyr1850-2005_c091026.nc -lnd/clm2/surfdata/surfdata.pftdyn_1x1_tropicAtl_testyr1000-1004_c100527.nc lnd/clm2/surfdata_map/surfdata.pftdyn_48x96_hist_simyr1850-2005_c120127.nc lnd/clm2/surfdata_map/surfdata.pftdyn_ne30np4_hist_simyr1850-2005_c120907.nc @@ -519,7 +509,6 @@ lnd/clm2/surfdata/surfdata_1x1_tropicAtl_simyr1850_c090923.nc nn nn nn -nn nn nn nn @@ -527,7 +516,6 @@ lnd/clm2/surfdata/surfdata_1x1_tropicAtl_simyr1850_c090923.nc nn nn nn -nn nn @@ -544,7 +532,6 @@ lnd/clm2/surfdata/surfdata_1x1_tropicAtl_simyr1850_c090923.nc nn nn nn -nn nn nn nn @@ -552,7 +539,6 @@ lnd/clm2/surfdata/surfdata_1x1_tropicAtl_simyr1850_c090923.nc nn nn nn -nn nn @@ -686,23 +672,6 @@ lnd/clm2/surfdata/surfdata_1x1_tropicAtl_simyr1850_c090923.nc - - -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_AVHRR_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_MODIS_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_USGS_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_10x10min_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_MODIS_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_USGS_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_IGBP-GSDP_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_ISRIC-WISE_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_GLOBE-Gardner_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_GLOBE-Gardner-mergeGIS_to_1x1_tropicAtl_nomask_aave_da_c120927.nc - - - lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_0.5x0.5_AVHRR_to_1x1_urbanc_alpha_nomask_aave_da_c120717.nc diff --git a/bld/namelist_files/namelist_defaults_clm4_5.xml b/bld/namelist_files/namelist_defaults_clm4_5.xml index c221832b1e..eeca7e6792 100644 --- a/bld/namelist_files/namelist_defaults_clm4_5.xml +++ b/bld/namelist_files/namelist_defaults_clm4_5.xml @@ -14,6 +14,11 @@ are: hgrid, defaults, mask, ic_ymd, ic_tod, sim_year and all configuration attributes from the config_cache.xml file (with keys converted to upper-case). --> + +0.9x1.25 + +2000 + 1800 @@ -38,8 +43,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 2 1 -2 -1 +2 +1 0 @@ -48,7 +53,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). >'TOTECOSYSC','TOTECOSYSN','TOTSOMC','TOTSOMN','TOTVEGC','TOTVEGN','TLAI','GPP','NPP','TWS','TSAI','HTOP','HBOT' 'TOTECOSYSC','TOTECOSYSN','TOTSOMC','TOTSOMN','TOTVEGC','TOTVEGN','TLAI','GPP','CPOOL','NPP','TWS' -'TOTSOMC','TOTSOMN','TLAI','GPP','NPP','TWS' 'TLAI','TWS' @@ -71,11 +76,22 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 1 0 - -lnd/clm2/isotopes/atm_delta_C14_data_1850-2007_monthly_23082011.nc + +.true. +.false. + + +Medlyn2011 +Ball-Berry1987 +Ball-Berry1987 + + +lnd/clm2/isotopes/atm_delta_C13_CMIP6_1850-2015_yearly_v2.0_c171012.nc +lnd/clm2/isotopes/atm_delta_C14_CMIP6_3x1_global_1850-2015_yearly_v2.0_c171012.nc -.false. +.false. +.true. 0 @@ -83,7 +99,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). NONE -NONE +NONE 0.50,0.30 @@ -109,9 +125,12 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 20SL_8.5m 10SL_3.5m +.false. +.false. .true. .false. + 1 0 @@ -129,7 +148,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 1.d-2 -0.0090932 +0.001d00 1.d-2 1.d-2 @@ -165,6 +184,10 @@ attributes from the config_cache.xml file (with keys converted to upper-case). -2. 0. + +.false. +.true. + li2016crufrc li2014qianfrc @@ -179,17 +202,29 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 0.001d00 0.3d00 0.39d00 - -30.0d00 +75.d00 +1050.d00 +0.5d00, 0.25d00 + +30.0d00 +20.0d00 80.0d00 -0.6d00 -0.85d00 -0.0156d00 -0.4d-4 -0.0079611 -3.6d-4 -0.36d00 +0.85d00 +0.98d00 +0.033d00 +0.09d-4 +0.010d00 +0.008d00 +0.17d-3 +1.6d-4 0.33d00 +105.d00 +1050.d00 +0.5d00, 0.28d00 .false. @@ -206,11 +241,16 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 0 -1 -4 1 + +1 1 -2 + +4 +2 +2 +3 + 60. 1.e-8 1.e-1 @@ -225,11 +265,12 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 14400 -3400. 0.6 -0.5 +1.0 +0.5 0.1 -.true. +.false. .false. @@ -246,7 +287,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 1.e30 -1.0 +10.0d00 10.0 .true. @@ -261,19 +302,38 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 100.d00 175.d00 +54.526d00 +204.526d00 + 0.08d00 +.false. +.false. + +1.e9 + -'single_at_atm_topo','virtual','multiple' +'single_at_atm_topo','virtual','virtual','multiple' -'remains_in_place','replaced_by_ice','replaced_by_ice' +'remains_in_place','replaced_by_ice','replaced_by_ice','replaced_by_ice' + + +'melted','melted','remains_ice','remains_ice' -lnd/clm2/paramdata/clm5_params.c161105.nc -lnd/clm2/paramdata/clm_params.c161101.nc -lnd/clm2/paramdata/clm_params_ed.c161103.nc -lnd/clm2/paramdata/clm_params_ed.c161103.nc +lnd/clm2/paramdata/clm5_params.c171117.nc +lnd/clm2/paramdata/clm_params.c170913.nc + +lnd/clm2/paramdata/fates_params.c170331.nc + @@ -302,6 +363,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .true. +.false. .false. @@ -360,7 +422,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .false. .false. -.false. +.false. .false. @@ -369,6 +431,10 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .true. 1.d-9 +-6.d+1 +-6.d+0 +-6.d+2 +-6.d+1 @@ -377,216 +443,183 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. -.false. -.true. - +.false. +.true. + - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45SP.0521-01-01.0.9x1.25_g1v6_simyr1850_c160127.nc - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.0.9x1.25_g1v6_simyr1850_c160127.nc - + +75 - - -lnd/clm2/initdata_map/clmi.ICRUCLM45SP.2000-01-01.0.9x1.25_g1v6_simyr2000_c160127.nc - + +1850,2000 - - -lnd/clm2/initdata_map/clmi.I2000CLM45CRUBGC.2000-01-01.0.9x1.25_gx1v6_simyr2000_c160413.nc - + +.true. +.true. +.false. +hgrid=1.9x2.5 maxpft=79 mask=gx1v6 use_cn=.true. use_nitrif_denitrif=.true. use_vertsoilc=.true. use_crop=.true. irrigate=.false. glc_nec=10 + - - - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.1.9x2.5_g1v6_simyr1850_c160127.nc - - - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.1.9x2.5_g1v6_simyr1850_c160127.nc - - - - - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.360x720cru_hcru_simyr1850_c160127.nc - - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.360x720cru_hcru_simyr1850_c160127.nc - - - +hgrid=1.9x2.5 maxpft=79 mask=gx1v6 use_cn=.true. use_nitrif_denitrif=.true. use_vertsoilc=.true. use_crop=.true. irrigate=.true. glc_nec=10 + - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.ne30np4_g1v6_simyr1850_c160127.nc - - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.ne30np4_g1v6_simyr1850_c160127.nc - - - - - - - - -lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGCDV.0241-01-01.0.9x1.25_g1v6_simyr1850_c160127.nc - - - - - - - -lnd/clm2/initdata_map/clmi.ICRUCLM45BGCCROP.78pfts.levis_reinterp.1.9x2.5_g1v6_simyr2000_c160127.nc - - - + - -lnd/clm2/initdata_map/clmi.ICRUCLM45BGCCROP.78pfts.levis.10x15_USGS_simyr2000_c160127.nc + +lnd/clm2/initdata_map/clmi.IGM1850GSWCLM50BGCCROP.0481-01-01.1.9x2.5_gx1v6_gl5_simyr1850_c170419.nc - + - -lnd/clm2/initdata_map/clmi.ICRUCLM45BGCCROP.78pfts.Irrig.levis.10x15_USGS_simyr2000_c160127.nc + +lnd/clm2/initdata_map/clmi.IGM2000GSWP3CLM50BGCCROPIRR.2011-01-01.1.9x2.5_gx1v6_gl5_simyr2000_c170419.nc - -lnd/clm2/surfdata_map/surfdata_360x720cru_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_0.125x0.125_simyr2000_c150114.nc - -lnd/clm2/surfdata_map/surfdata_48x96_16pfts_simyr2000_c160127.nc - - -lnd/clm2/surfdata_map/surfdata_0.9x1.25_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_1.9x2.5_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_4x5_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_10x15_16pfts_simyr2000_c160127.nc - - -lnd/clm2/surfdata_map/surfdata_ne120np4_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_ne30np4_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_ne16np4_16pfts_simyr2000_c160127.nc - + +lnd/clm2/surfdata_map/surfdata_360x720cru_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_48x96_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + + +lnd/clm2/surfdata_map/surfdata_0.47x0.63_16pfts_Irrig_CMIP6_simyr2000_c170919.nc + +lnd/clm2/surfdata_map/surfdata_0.9x1.25_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_1.9x2.5_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_4x5_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_10x15_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + + +lnd/clm2/surfdata_map/surfdata_ne120np4_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_ne30np4_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_ne16np4_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + + +lnd/clm2/surfdata_map/surfdata_5x5_amazon_16pfts_Irrig_CMIP6_simyr2000_c171214.nc + +lnd/clm2/surfdata_map/surfdata_1x1_brazil_16pfts_Irrig_CMIP6_simyr2000_c171214.nc + + +lnd/clm2/surfdata_map/surfdata_64x128_16pfts_Irrig_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_0.47x0.63_78pfts_CMIP6_simyr2000_c170919.nc + +lnd/clm2/surfdata_map/surfdata_0.9x1.25_78pfts_CMIP6_simyr2000_c170824.nc -lnd/clm2/surfdata_map/surfdata_1.9x2.5_78pfts_simyr2000_c160127.nc +lnd/clm2/surfdata_map/surfdata_1.9x2.5_78pfts_CMIP6_simyr2000_c170824.nc lnd/clm2/surfdata_map/surfdata_0.125x0.125_mp24_simyr2000_c150114.nc -lnd/clm2/surfdata_map/surfdata_10x15_78pfts_simyr2000_c160127.nc +lnd/clm2/surfdata_map/surfdata_10x15_78pfts_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_4x5_78pfts_CMIP6_simyr2000_c170824.nc -lnd/clm2/surfdata_map/surfdata_1x1_numaIA_78pfts_simyr2000_c160127.nc +lnd/clm2/surfdata_map/surfdata_1x1_numaIA_78pfts_CMIP6_simyr2000_c171214.nc -lnd/clm2/surfdata_map/surfdata_1x1_smallvilleIA_78pfts_simyr2000_c160127.nc +lnd/clm2/surfdata_map/surfdata_1x1_smallvilleIA_78pfts_CMIP6_simyr2000_c171214.nc - -lnd/clm2/surfdata_map/surfdata_5x5_amazon_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_1x1_brazil_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_1x1_tropicAtl_16pfts_simyr2000_c160127.nc + +lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_ne30np4_78pfts_CMIP6_simyr2000_c170824.nc + +lnd/clm2/surfdata_map/surfdata_ne16np4_78pfts_CMIP6_simyr2000_c170824.nc - -lnd/clm2/surfdata_map/surfdata_1x1_camdenNJ_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_1x1_vancouverCAN_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_1x1_mexicocityMEX_16pfts_simyr2000_c160127.nc - -lnd/clm2/surfdata_map/surfdata_1x1_urbanc_alpha_16pfts_simyr2000_c160127.nc - - - -lnd/clm2/surfdata_map/surfdata_360x720cru_16pfts_simyr1850_c160127.nc - -lnd/clm2/surfdata_map/surfdata_48x96_16pfts_simyr1850_c160127.nc - - -lnd/clm2/surfdata_map/surfdata_0.9x1.25_16pfts_simyr1850_c160127.nc + +lnd/clm2/surfdata_map/surfdata_1x1_camdenNJ_16pfts_Irrig_CMIP6_simyr2000_c171214.nc + +lnd/clm2/surfdata_map/surfdata_1x1_vancouverCAN_16pfts_Irrig_CMIP6_simyr2000_c171214.nc + +lnd/clm2/surfdata_map/surfdata_1x1_mexicocityMEX_16pfts_Irrig_CMIP6_simyr2000_c171214.nc + +lnd/clm2/surfdata_map/surfdata_1x1_urbanc_alpha_16pfts_Irrig_CMIP6_simyr2000_c171214.nc + + + +lnd/clm2/surfdata_map/surfdata_360x720cru_16pfts_Irrig_CMIP6_simyr1850_c170824.nc + +lnd/clm2/surfdata_map/surfdata_48x96_16pfts_Irrig_CMIP6_simyr1850_c170824.nc + + +lnd/clm2/surfdata_map/surfdata_0.47x0.63_16pfts_Irrig_CMIP6_simyr1850_c170919.nc + +lnd/clm2/surfdata_map/surfdata_0.9x1.25_16pfts_Irrig_CMIP6_simyr1850_c170824.nc -lnd/clm2/surfdata_map/surfdata_1.9x2.5_16pfts_simyr1850_c160127.nc - -lnd/clm2/surfdata_map/surfdata_10x15_16pfts_simyr1850_c160127.nc +lnd/clm2/surfdata_map/surfdata_1.9x2.5_16pfts_Irrig_CMIP6_simyr1850_c170824.nc + +lnd/clm2/surfdata_map/surfdata_10x15_16pfts_Irrig_CMIP6_simyr1850_c170824.nc + +lnd/clm2/surfdata_map/surfdata_4x5_16pfts_Irrig_CMIP6_simyr1850_c170824.nc - -lnd/clm2/surfdata_map/surfdata_1x1_tropicAtl_16pfts_simyr1850_c160127.nc - -lnd/clm2/surfdata_map/surfdata_1x1_brazil_16pfts_simyr1850_c160127.nc + +lnd/clm2/surfdata_map/surfdata_1x1_brazil_16pfts_Irrig_CMIP6_simyr1850_c171214.nc - -lnd/clm2/surfdata_map/surfdata_ne120np4_16pfts_simyr1850_c160127.nc - -lnd/clm2/surfdata_map/surfdata_ne30np4_16pfts_simyr1850_c160127.nc + +lnd/clm2/surfdata_map/surfdata_ne120np4_16pfts_Irrig_CMIP6_simyr1850_c170824.nc + +lnd/clm2/surfdata_map/surfdata_ne30np4_16pfts_Irrig_CMIP6_simyr1850_c170824.nc + +lnd/clm2/surfdata_map/surfdata_360x720cru_78pfts_CMIP6_simyr1850_c170824.nc + +lnd/clm2/surfdata_map/surfdata_48x96_78pfts_CMIP6_simyr1850_c170824.nc + + +lnd/clm2/surfdata_map/surfdata_0.47x0.63_78pfts_CMIP6_simyr1850_c170919.nc -lnd/clm2/surfdata_map/surfdata_0.9x1.25_78pfts_simyr1850_c161128.nc +lnd/clm2/surfdata_map/surfdata_0.9x1.25_78pfts_CMIP6_simyr1850_c170824.nc -lnd/clm2/surfdata_map/surfdata_1.9x2.5_78pfts_simyr1850_c161128.nc +lnd/clm2/surfdata_map/surfdata_1.9x2.5_78pfts_CMIP6_simyr1850_c170824.nc -lnd/clm2/surfdata_map/surfdata_10x15_78pfts_simyr1850_c160127.nc +lnd/clm2/surfdata_map/surfdata_10x15_78pfts_CMIP6_simyr1850_c170824.nc -lnd/clm2/surfdata_map/surfdata_4x5_78pfts_simyr1850_c160216.nc +lnd/clm2/surfdata_map/surfdata_4x5_78pfts_CMIP6_simyr1850_c170824.nc -lnd/clm2/surfdata_map/surfdata_1x1_smallvilleIA_78pfts_simyr1850_c160127.nc +lnd/clm2/surfdata_map/surfdata_1x1_smallvilleIA_78pfts_CMIP6_simyr1850_c171214.nc + +lnd/clm2/surfdata_map/surfdata_1x1_numaIA_78pfts_CMIP6_simyr1850_c170917.nc + + +lnd/clm2/surfdata_map/surfdata_1x1_brazil_78pfts_CMIP6_simyr1850_c171214.nc -lnd/clm2/surfdata_map/surfdata_ne30np4_78pfts_simyr1850_c160208.nc +lnd/clm2/surfdata_map/surfdata_ne30np4_78pfts_CMIP6_simyr1850_c170824.nc -lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc +lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_CMIP6_simyr1850_c170824.nc @@ -594,35 +627,53 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc dataset (arbitrarily, RCP8.5) for the historical period, because all of the RCP datasets contain the 1850-2000 period as well as the future period. --> +lnd/clm2/surfdata_map/landuse.timeseries_0.47x0.63_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c171025.nc +lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + +lnd/clm2/surfdata_map/landuse.timeseries_1x1_brazil_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + +lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + + + lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_10x15_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_48x96_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc -lnd/clm2/surfdata_map/landuse.timeseries_1x1_tropicAtl_hist_16pfts_simyr1850-2005_c160127.nc lnd/clm2/surfdata_map/landuse.timeseries_1x1_brazil_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_1x1_brazil_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_1x1_numaIA_hist_78pfts_CMIP6_simyr1850-2015_c170917.nc lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_rcp8.5_16pfts_simyr1850-2100_c160127.nc - - - -lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_78pfts_simyr1850-2015_c161128.nc -lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_78pfts_simyr1850-2015_c161216.nc -lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_78pfts_simyr1850-2005_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc @@ -631,82 +682,159 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc - + +lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + +lnd/clm2/surfdata_map/landuse.timeseries_1x1_brazil_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + +lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + +lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + +lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc + + lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_10x15_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_48x96_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_1x1_brazil_rcp8.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_1x1_brazil_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_rcp6.0_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_rcp6.0_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_rcp6.0_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_10x15_rcp6.0_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_48x96_rcp6.0_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_rcp6.0_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_rcp4.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_rcp4.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_rcp4.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_10x15_rcp4.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_48x96_rcp4.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_rcp4.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne120np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_rcp4.5_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_rcp2.6_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_360x720cru_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_rcp2.6_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_rcp2.6_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_10x15_rcp2.6_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc +lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_48x96_rcp2.6_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_48x96_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_rcp2.6_16pfts_simyr1850-2100_c160127.nc + use_crop=".true." >lnd/clm2/surfdata_map/landuse.timeseries_ne30np4_hist_78pfts_CMIP6_simyr1850-2015_c170824.nc .true. .false. -1.1678d-06 - +0.83d-06 0.015d00 0.015d00 -20.0d00, 20.0d00, 20.0d00 -200.0d00, 200.0d00, 200.0d00 -20.0d00, 20.0d00, 20.0d00 -200.0d00, 200.0d00, 200.0d00 +20.0d00, 20.0d00, 20.0d00 +200.0d00, 200.0d00, 200.0d00 +20.0d00, 20.0d00, 20.0d00 +200.0d00, 200.0d00, 200.0d00 + +1.50d00 +0.3 +1.50d00 +0.3 + +100.d00 +20.d00 +1.d00 +1.d00 @@ -752,7 +880,6 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc nn nn nn -nn nn @@ -771,7 +898,6 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc nn nn nn -nn nn nn nn @@ -779,7 +905,6 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc nn nn nn -nn nn @@ -803,7 +928,6 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc nn nn nn -nn nn @@ -831,7 +955,7 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc 1850 2010 -lnd/clm2/firedata/clmforc.Li_2012_hdm_0.5x0.5_AVHRR_simyr1850-2010_c130401.nc +lnd/clm2/firedata/clmforc.Li_2017_HYDEv3.2_CMIP6_hdm_0.5x0.5_AVHRR_simyr1850-2016_c170829.nc bilinear @@ -841,7 +965,6 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc nn nn nn -nn nn @@ -884,12 +1007,11 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc nn nn nn -nn nn -.true. -.false. +.true. +.false. @@ -910,6 +1032,8 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc >lnd/clm2/mappingdata/maps/0.1x0.1/map_0.5x0.5_AVHRR_to_0.1x0.1_nomask_aave_da_c120406.nc lnd/clm2/mappingdata/maps/0.1x0.1/map_0.5x0.5_MODIS_to_0.1x0.1_nomask_aave_da_c120406.nc +lnd/clm2/mappingdata/maps/0.1x0.1/map_0.25x0.25_MODIS_to_0.1x0.1_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/0.1x0.1/map_0.5x0.5_nomask_to_0.1x0.1_nomask_aave_da_c120406.nc >lnd/clm2/mappingdata/maps/0.1x0.1/map_5x5min_IGBP-GSDP_to_0.1x0.1_nomask_aave_da_c120406.nc lnd/clm2/mappingdata/maps/0.1x0.1/map_5x5min_ISRIC-WISE_to_0.1x0.1_nomask_aave_da_c120406.nc +lnd/clm2/mappingdata/maps/0.1x0.1/map_5x5min_ORNL-Soil_to_0.1x0.1_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/0.1x0.1/map_5x5min_nomask_to_0.1x0.1_nomask_aave_da_c120406.nc >lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_0.5x0.5_AVHRR_to_1x1_asphaltjungleNJ_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_0.5x0.5_MODIS_to_1x1_asphaltjungleNJ_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_0.25x0.25_MODIS_to_1x1_asphaltjungleNJ_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_0.5x0.5_nomask_to_1x1_asphaltjungleNJ_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_5x5min_IGBP-GSDP_to_1x1_asphaltjungleNJ_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_5x5min_ISRIC-WISE_to_1x1_asphaltjungleNJ_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_5x5min_ORNL-Soil_to_1x1_asphaltjungleNJ_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_asphaltjungleNJ/map_5x5min_nomask_to_1x1_asphaltjungleNJ_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_brazil/map_0.5x0.5_AVHRR_to_1x1_brazil_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_brazil/map_0.5x0.5_MODIS_to_1x1_brazil_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_brazil/map_0.25x0.25_MODIS_to_1x1_brazil_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_brazil/map_0.5x0.5_nomask_to_1x1_brazil_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_brazil/map_5x5min_IGBP-GSDP_to_1x1_brazil_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_brazil/map_5x5min_ISRIC-WISE_to_1x1_brazil_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_brazil/map_5x5min_ORNL-Soil_to_1x1_brazil_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_brazil/map_5x5min_nomask_to_1x1_brazil_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_0.5x0.5_AVHRR_to_1x1_camdenNJ_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_0.5x0.5_MODIS_to_1x1_camdenNJ_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_0.25x0.25_MODIS_to_1x1_camdenNJ_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_0.5x0.5_nomask_to_1x1_camdenNJ_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_5x5min_IGBP-GSDP_to_1x1_camdenNJ_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_5x5min_ISRIC-WISE_to_1x1_camdenNJ_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_5x5min_ORNL-Soil_to_1x1_camdenNJ_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_camdenNJ/map_5x5min_nomask_to_1x1_camdenNJ_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_0.5x0.5_AVHRR_to_1x1_mexicocityMEX_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_0.5x0.5_MODIS_to_1x1_mexicocityMEX_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_0.25x0.25_MODIS_to_1x1_mexicocityMEX_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_0.5x0.5_nomask_to_1x1_mexicocityMEX_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_5x5min_IGBP-GSDP_to_1x1_mexicocityMEX_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_5x5min_ISRIC-WISE_to_1x1_mexicocityMEX_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_5x5min_ORNL-Soil_to_1x1_mexicocityMEX_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_mexicocityMEX/map_5x5min_nomask_to_1x1_mexicocityMEX_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_numaIA/map_0.5x0.5_AVHRR_to_1x1_numaIA_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_numaIA/map_0.5x0.5_MODIS_to_1x1_numaIA_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_numaIA/map_0.25x0.25_MODIS_to_1x1_numaIA_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_numaIA/map_0.5x0.5_nomask_to_1x1_numaIA_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_numaIA/map_5x5min_IGBP-GSDP_to_1x1_numaIA_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_numaIA/map_5x5min_ISRIC-WISE_to_1x1_numaIA_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_numaIA/map_5x5min_ORNL-Soil_to_1x1_numaIA_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_numaIA/map_5x5min_nomask_to_1x1_numaIA_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_0.5x0.5_AVHRR_to_1x1_smallvilleIA_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_0.5x0.5_MODIS_to_1x1_smallvilleIA_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_0.25x0.25_MODIS_to_1x1_smallvilleIA_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_0.5x0.5_nomask_to_1x1_smallvilleIA_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_5x5min_IGBP-GSDP_to_1x1_smallvilleIA_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_5x5min_ISRIC-WISE_to_1x1_smallvilleIA_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_5x5min_ORNL-Soil_to_1x1_smallvilleIA_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_smallvilleIA/map_5x5min_nomask_to_1x1_smallvilleIA_nomask_aave_da_c120717.nc - - -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_AVHRR_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_MODIS_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_10x10min_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_MODIS_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_MODIS-wCsp_to_1x1_tropicAtl_nomask_aave_da_c160425.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_USGS_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_LandScan2004_to_1x1_tropicAtl_nomask_aave_da_c121114.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_IGBP-GSDP_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_ISRIC-WISE_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_GLOBE-Gardner_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_GLOBE-Gardner-mergeGIS_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.9x1.25_GRDC_to_1x1_tropicAtl_nomask_aave_da_c130309.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_360x720_cruncep_to_1x1_tropicAtl_nomask_aave_da_c130326.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_1km-merge-10min_HYDRO1K-merge-nomask_to_1x1_tropicAtl_nomask_aave_da_c130403.nc - - - lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_0.5x0.5_AVHRR_to_1x1_urbanc_alpha_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_0.5x0.5_MODIS_to_1x1_urbanc_alpha_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_0.25x0.25_MODIS_to_1x1_urbanc_alpha_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_0.5x0.5_nomask_to_1x1_urbanc_alpha_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_5x5min_IGBP-GSDP_to_1x1_urbanc_alpha_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_5x5min_ISRIC-WISE_to_1x1_urbanc_alpha_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_5x5min_ORNL-Soil_to_1x1_urbanc_alpha_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_urbanc_alpha/map_5x5min_nomask_to_1x1_urbanc_alpha_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_0.5x0.5_AVHRR_to_1x1_vancouverCAN_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_0.5x0.5_MODIS_to_1x1_vancouverCAN_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_0.25x0.25_MODIS_to_1x1_vancouverCAN_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_0.5x0.5_nomask_to_1x1_vancouverCAN_nomask_aave_da_c120717.nc >lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_5x5min_IGBP-GSDP_to_1x1_vancouverCAN_nomask_aave_da_c120717.nc lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_5x5min_ISRIC-WISE_to_1x1_vancouverCAN_nomask_aave_da_c120717.nc +lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_5x5min_ORNL-Soil_to_1x1_vancouverCAN_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1x1_vancouverCAN/map_5x5min_nomask_to_1x1_vancouverCAN_nomask_aave_da_c120717.nc + + +lnd/clm2/mappingdata/maps/0.47x0.63/map_0.25x0.25_MODIS_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_0.5x0.5_AVHRR_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_0.5x0.5_MODIS_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_0.9x1.25_GRDC_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_10x10min_IGBPmergeICESatGIS_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_10x10min_nomask_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_1km-merge-10min_HYDRO1K-merge-nomask_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_360x720cru_cruncep_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_3x3min_GLOBE-Gardner-mergeGIS_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_3x3min_GLOBE-Gardner_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_3x3min_LandScan2004_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_3x3min_MODIS-wCsp_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_3x3min_USGS_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_5x5min_IGBP-GSDP_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_5x5min_ISRIC-WISE_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_5x5min_nomask_to_0.47x0.63_nomask_aave_da_c170914.nc +lnd/clm2/mappingdata/maps/0.47x0.63/map_5x5min_ORNL-Soil_to_0.47x0.63_nomask_aave_da_c170914.nc + + + + lnd/clm2/mappingdata/maps/0.9x1.25/map_0.5x0.5_landuse_to_0.9x1.25_aave_da_110307.nc +lnd/clm2/mappingdata/maps/0.9x1.25/map_0.25x0.25_MODIS_to_0.9x1.25_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/0.9x1.25/map_0.5x0.5_lanwat_to_0.9x1.25_aave_da_110307.nc >lnd/clm2/mappingdata/maps/0.9x1.25/map_5minx5min_irrig_to_0.9x1.25_aave_da_110529.nc lnd/clm2/mappingdata/maps/0.9x1.25/map_5x5min_ISRIC-WISE_to_0.9x1.25_nomask_aave_da_c120525.nc +lnd/clm2/mappingdata/maps/0.9x1.25/map_5x5min_ORNL-Soil_to_0.9x1.25_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/0.9x1.25/map_3x3min_MODIS_to_0.9x1.25_nomask_aave_da_c120523.nc lnd/clm2/mappingdata/maps/1.9x2.5/map_0.5x0.5_landuse_to_1.9x2.5_aave_da_110307.nc +lnd/clm2/mappingdata/maps/1.9x2.5/map_0.25x0.25_MODIS_to_1.9x2.5_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/1.9x2.5/map_0.5x0.5_lanwat_to_1.9x2.5_aave_da_110307.nc >lnd/clm2/mappingdata/maps/1.9x2.5/map_5x5min_nomask_to_1.9x2.5_nomask_aave_da_c120606.nc lnd/clm2/mappingdata/maps/1.9x2.5/map_5x5min_ISRIC-WISE_to_1.9x2.5_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/1.9x2.5/map_5x5min_ORNL-Soil_to_1.9x2.5_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/1.9x2.5/map_3x3min_MODIS_to_1.9x2.5_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_landuse_to_10x15_aave_da_110307.nc +lnd/clm2/mappingdata/maps/10x15/map_0.25x0.25_MODIS_to_10x15_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_lanwat_to_10x15_aave_da_110307.nc >lnd/clm2/mappingdata/maps/10x15/map_5x5min_nomask_to_10x15_nomask_aave_da_c120327.nc lnd/clm2/mappingdata/maps/10x15/map_5x5min_ISRIC-WISE_to_10x15_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/10x15/map_5x5min_ORNL-Soil_to_10x15_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/10x15/map_3x3min_MODIS_to_10x15_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/360x720/map_0.5x0.5_MODIS_to_360x720_nomask_aave_da_c120830.nc +lnd/clm2/mappingdata/maps/360x720/map_0.25x0.25_MODIS_to_360x720cru_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/360x720/map_0.5x0.5_AVHRR_to_360x720_nomask_aave_da_c120830.nc >lnd/clm2/mappingdata/maps/360x720/map_5x5min_nomask_to_360x720_nomask_aave_da_c120830.nc lnd/clm2/mappingdata/maps/360x720/map_5x5min_ISRIC-WISE_to_360x720_nomask_aave_da_c120830.nc +lnd/clm2/mappingdata/maps/360x720/map_5x5min_ORNL-Soil_to_360x720cru_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/360x720/map_3x3min_MODIS_to_360x720_nomask_aave_da_c120830.nc lnd/clm2/mappingdata/maps/512x1024/map_0.5x0.5_MODIS_to_512x1024_nomask_aave_da_c110920.nc +lnd/clm2/mappingdata/maps/512x1024/map_0.25x0.25_MODIS_to_512x1024_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/512x1024/map_0.5x0.5_AVHRR_to_512x1024_nomask_aave_da_c110920.nc >lnd/clm2/mappingdata/maps/512x1024/map_5x5min_nomask_to_512x1024_nomask_aave_da_c110920.nc lnd/clm2/mappingdata/maps/512x1024/map_5x5min_ISRIC-WISE_to_512x1024_nomask_aave_da_c120906.nc +lnd/clm2/mappingdata/maps/512x1024/map_5x5min_ORNL-Soil_to_512x1024_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/512x1024/map_3x3min_MODIS_to_512x1024_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/128x256/map_0.5x0.5_MODIS_to_128x256_nomask_aave_da_c110920.nc +lnd/clm2/mappingdata/maps/128x256/map_0.25x0.25_MODIS_to_128x256_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/128x256/map_0.5x0.5_AVHRR_to_128x256_nomask_aave_da_c110920.nc >lnd/clm2/mappingdata/maps/128x256/map_5x5min_nomask_to_128x256_nomask_aave_da_c110920.nc lnd/clm2/mappingdata/maps/128x256/map_5x5min_ISRIC-WISE_to_128x256_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/128x256/map_5x5min_ORNL-Soil_to_128x256_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/128x256/map_3x3min_MODIS_to_128x256_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/64x128/map_0.5x0.5_MODIS_to_64x128_nomask_aave_da_c110920.nc +lnd/clm2/mappingdata/maps/64x128/map_0.25x0.25_MODIS_to_64x128_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/64x128/map_0.5x0.5_AVHRR_to_64x128_nomask_aave_da_c110920.nc >lnd/clm2/mappingdata/maps/64x128/map_5x5min_nomask_to_64x128_nomask_aave_da_c110920.nc lnd/clm2/mappingdata/maps/64x128/map_5x5min_ISRIC-WISE_to_64x128_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/64x128/map_5x5min_ORNL-Soil_to_64x128_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/64x128/map_3x3min_MODIS_to_64x128_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/48x96/map_0.5x0.5_MODIS_to_48x96_nomask_aave_da_c110822.nc +lnd/clm2/mappingdata/maps/48x96/map_0.25x0.25_MODIS_to_48x96_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/48x96/map_0.5x0.5_AVHRR_to_48x96_nomask_aave_da_c110822.nc >lnd/clm2/mappingdata/maps/48x96/map_5x5min_nomask_to_48x96_nomask_aave_da_c110822.nc lnd/clm2/mappingdata/maps/48x96/map_5x5min_ISRIC-WISE_to_48x96_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/48x96/map_5x5min_ORNL-Soil_to_48x96_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/48x96/map_3x3min_MODIS_to_48x96_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/32x64/map_0.5x0.5_MODIS_to_32x64_nomask_aave_da_c110920.nc +lnd/clm2/mappingdata/maps/32x64/map_0.25x0.25_MODIS_to_32x64_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/32x64/map_0.5x0.5_AVHRR_to_32x64_nomask_aave_da_c110920.nc >lnd/clm2/mappingdata/maps/32x64/map_5x5min_nomask_to_32x64_nomask_aave_da_c110920.nc lnd/clm2/mappingdata/maps/32x64/map_5x5min_ISRIC-WISE_to_32x64_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/32x64/map_5x5min_ORNL-Soil_to_32x64_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/32x64/map_3x3min_MODIS_to_32x64_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/8x16/map_0.5x0.5_MODIS_to_8x16_nomask_aave_da_c110920.nc +lnd/clm2/mappingdata/maps/8x16/map_0.25x0.25_MODIS_to_8x16_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/8x16/map_0.5x0.5_AVHRR_to_8x16_nomask_aave_da_c110920.nc >lnd/clm2/mappingdata/maps/8x16/map_5x5min_nomask_to_8x16_nomask_aave_da_c110920.nc lnd/clm2/mappingdata/maps/8x16/map_5x5min_ISRIC-WISE_to_8x16_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/8x16/map_5x5min_ORNL-Soil_to_8x16_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/8x16/map_3x3min_MODIS_to_8x16_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/4x5/map_0.5x0.5_MODIS_to_4x5_nomask_aave_da_c110822.nc +lnd/clm2/mappingdata/maps/4x5/map_0.25x0.25_MODIS_to_4x5_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/4x5/map_0.5x0.5_AVHRR_to_4x5_nomask_aave_da_c110822.nc >lnd/clm2/mappingdata/maps/4x5/map_5x5min_nomask_to_4x5_nomask_aave_da_c110822.nc lnd/clm2/mappingdata/maps/4x5/map_5x5min_ISRIC-WISE_to_4x5_nomask_aave_da_c120906.nc +lnd/clm2/mappingdata/maps/4x5/map_5x5min_ORNL-Soil_to_4x5_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/4x5/map_3x3min_MODIS_to_4x5_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/0.23x0.31/map_0.5x0.5_MODIS_to_0.23x0.31_nomask_aave_da_c110920.nc +lnd/clm2/mappingdata/maps/0.23x0.31/map_0.25x0.25_MODIS_to_0.23x0.31_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/0.23x0.31/map_0.5x0.5_AVHRR_to_0.23x0.31_nomask_aave_da_c110920.nc >lnd/clm2/mappingdata/maps/0.23x0.31/map_5x5min_nomask_to_0.23x0.31_nomask_aave_da_c110920.nc lnd/clm2/mappingdata/maps/0.23x0.31/map_5x5min_ISRIC-WISE_to_0.23x0.31_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/0.23x0.31/map_5x5min_ORNL-Soil_to_0.23x0.31_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/0.23x0.31/map_3x3min_MODIS_to_0.23x0.31_nomask_aave_da_c110930.nc lnd/clm2/mappingdata/maps/2.5x3.33/map_0.5x0.5_MODIS_to_2.5x3.33_nomask_aave_da_c110823.nc +lnd/clm2/mappingdata/maps/2.5x3.33/map_0.25x0.25_MODIS_to_2.5x3.33_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/2.5x3.33/map_0.5x0.5_AVHRR_to_2.5x3.33_nomask_aave_da_c110823.nc >lnd/clm2/mappingdata/maps/2.5x3.33/map_5x5min_nomask_to_2.5x3.33_nomask_aave_da_c110823.nc lnd/clm2/mappingdata/maps/2.5x3.33/map_5x5min_ISRIC-WISE_to_2.5x3.33_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/2.5x3.33/map_5x5min_ORNL-Soil_to_2.5x3.33_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/2.5x3.33/map_3x3min_MODIS_to_2.5x3.33_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/0.5x0.5/map_0.5x0.5_AVHRR_to_0.5x0.5_nomask_aave_da_c111021.nc +lnd/clm2/mappingdata/maps/0.5x0.5/map_0.25x0.25_MODIS_to_0.5x0.5_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/0.5x0.5/map_0.5x0.5_MODIS_to_0.5x0.5_nomask_aave_da_c111021.nc >lnd/clm2/mappingdata/maps/0.5x0.5/map_3x3min_MODIS-wCsp_to_0.5x0.5_nomask_aave_da_c160425.nc lnd/clm2/mappingdata/maps/0.5x0.5/map_5x5min_ISRIC-WISE_to_0.5x0.5_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/0.5x0.5/map_5x5min_ORNL-Soil_to_0.5x0.5_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/0.5x0.5/map_3x3min_LandScan2004_to_0.5x0.5_nomask_aave_da_c120518.nc lnd/clm2/mappingdata/maps/ne4np4/map_0.5x0.5_MODIS_to_ne4np4_nomask_aave_da_c110923.nc +lnd/clm2/mappingdata/maps/ne4np4/map_0.25x0.25_MODIS_to_ne4np4_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/ne4np4/map_0.5x0.5_AVHRR_to_ne4np4_nomask_aave_da_c110923.nc >lnd/clm2/mappingdata/maps/ne4np4/map_5x5min_nomask_to_ne4np4_nomask_aave_da_c110923.nc lnd/clm2/mappingdata/maps/ne4np4/map_5x5min_ISRIC-WISE_to_ne4np4_nomask_aave_da_c120906.nc +lnd/clm2/mappingdata/maps/ne4np4/map_5x5min_ORNL-Soil_to_ne4np4_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/ne4np4/map_3x3min_MODIS_to_ne4np4_nomask_aave_da_c120906.nc lnd/clm2/mappingdata/maps/ne16np4/map_0.5x0.5_MODIS_to_ne16np4_nomask_aave_da_c110922.nc +lnd/clm2/mappingdata/maps/ne16np4/map_0.25x0.25_MODIS_to_ne16np4_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/ne16np4/map_0.5x0.5_AVHRR_to_ne16np4_nomask_aave_da_c110922.nc >lnd/clm2/mappingdata/maps/ne16np4/map_5x5min_nomask_to_ne16np4_nomask_aave_da_c110922.nc lnd/clm2/mappingdata/maps/ne16np4/map_5x5min_ISRIC-WISE_to_ne16np4_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/ne16np4/map_5x5min_ORNL-Soil_to_ne16np4_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/ne16np4/map_3x3min_MODIS_to_ne16np4_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/ne30np4/map_0.5x0.5_landuse_to_ne30np4_aave_da_110320.nc +lnd/clm2/mappingdata/maps/ne30np4/map_0.25x0.25_MODIS_to_ne30np4_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/ne30np4/map_0.5x0.5_lanwat_to_ne30np4_aave_da_110320.nc >lnd/clm2/mappingdata/maps/ne30np4/map_5minx5min_irrig_to_ne30np4_aave_da_110720.nc lnd/clm2/mappingdata/maps/ne30np4/map_5x5min_ISRIC-WISE_to_ne30np4_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/ne30np4/map_5x5min_ORNL-Soil_to_ne30np4_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/ne30np4/map_3x3min_MODIS_to_ne30np4_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/ne60np4/map_0.5x0.5_MODIS_to_ne60np4_nomask_aave_da_c110922.nc +lnd/clm2/mappingdata/maps/ne60np4/map_0.25x0.25_MODIS_to_ne60np4_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/ne60np4/map_0.5x0.5_AVHRR_to_ne60np4_nomask_aave_da_c110922.nc >lnd/clm2/mappingdata/maps/ne60np4/map_5x5min_nomask_to_ne60np4_nomask_aave_da_c110922.nc lnd/clm2/mappingdata/maps/ne60np4/map_5x5min_ISRIC-WISE_to_ne60np4_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/ne60np4/map_5x5min_ORNL-Soil_to_ne60np4_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/ne60np4/map_3x3min_MODIS_to_ne60np4_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/ne120np4/map_0.5x0.5_landuse_to_ne120np4_aave_da_110320.nc +lnd/clm2/mappingdata/maps/ne120np4/map_0.25x0.25_MODIS_to_ne120np4_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/ne120np4/map_0.5x0.5_lanwat_to_ne120np4_aave_da_110320.nc >lnd/clm2/mappingdata/maps/ne120np4/map_5minx5min_soitex_to_ne120np4_aave_da_110320.nc lnd/clm2/mappingdata/maps/ne120np4/map_5x5min_ISRIC-WISE_to_ne120np4_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/ne120np4/map_5x5min_ORNL-Soil_to_ne120np4_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/ne120np4/map_5minx5min_irrig_to_ne120np4_aave_da_110817.nc lnd/clm2/mappingdata/maps/5x5_amazon/map_0.5x0.5_MODIS_to_5x5_amazon_nomask_aave_da_c110920.nc +lnd/clm2/mappingdata/maps/5x5_amazon/map_0.25x0.25_MODIS_to_5x5_amazon_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/5x5_amazon/map_0.5x0.5_AVHRR_to_5x5_amazon_nomask_aave_da_c110920.nc >lnd/clm2/mappingdata/maps/5x5_amazon/map_5x5min_nomask_to_5x5_amazon_nomask_aave_da_c110920.nc lnd/clm2/mappingdata/maps/5x5_amazon/map_5x5min_ISRIC-WISE_to_5x5_amazon_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/5x5_amazon/map_5x5min_ORNL-Soil_to_5x5_amazon_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/5x5_amazon/map_3x3min_MODIS_to_5x5_amazon_nomask_aave_da_c111111.nc lnd/clm2/mappingdata/maps/ne240np4/map_0.5x0.5_MODIS_to_ne240np4_nomask_aave_da_c110922.nc +lnd/clm2/mappingdata/maps/ne240np4/map_0.25x0.25_MODIS_to_ne240np4_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/ne240np4/map_0.5x0.5_AVHRR_to_ne240np4_nomask_aave_da_c110922.nc >lnd/clm2/mappingdata/maps/ne240np4/map_5x5min_nomask_to_ne240np4_nomask_aave_da_c110922.nc lnd/clm2/mappingdata/maps/ne240np4/map_5x5min_ISRIC-WISE_to_ne240np4_nomask_aave_da_c111115.nc +lnd/clm2/mappingdata/maps/ne240np4/map_5x5min_ORNL-Soil_to_ne240np4_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/ne240np4/map_3x3min_MODIS_to_ne240np4_nomask_aave_da_c111111.nc >lnd/clm2/mappingdata/maps/0.125x0.125/map_0.5x0.5_AVHRR_to_0.125x0.125_nomask_aave_da_c140702.nc lnd/clm2/mappingdata/maps/0.125x0.125/map_0.5x0.5_MODIS_to_0.125x0.125_nomask_aave_da_c140702.nc +lnd/clm2/mappingdata/maps/0.125x0.125/map_0.25x0.25_MODIS_to_0.125x0.125_nomask_aave_da_c170321.nc lnd/clm2/mappingdata/maps/0.125x0.125/map_0.9x1.25_GRDC_to_0.125x0.125_nomask_aave_da_c140702.nc >lnd/clm2/mappingdata/maps/0.125x0.125/map_5x5min_IGBP-GSDP_to_0.125x0.125_nomask_aave_da_c140702.nc lnd/clm2/mappingdata/maps/0.125x0.125/map_5x5min_ISRIC-WISE_to_0.125x0.125_nomask_aave_da_c140702.nc +lnd/clm2/mappingdata/maps/0.125x0.125/map_5x5min_ORNL-Soil_to_0.125x0.125_nomask_aave_da_c170706.nc lnd/clm2/mappingdata/maps/0.125x0.125/map_5x5min_nomask_to_0.125x0.125_nomask_aave_da_c140702.nc @@ -2025,11 +2274,15 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc -.false. -.true. +TWS_inversion +ZWT_inversion +.true. +.true. + +1.9x2.5 -.false. -.true. +lnd/clm2/paramdata/finundated_inversiondata_0.9x1.25_c170706.nc @@ -2050,11 +2303,11 @@ lnd/clm2/surfdata_map/surfdata_ne120np4_78pfts_simyr1850_c160216.nc .true. .true. -.true. -.true. -.false. -.false. +.true. +.true. +.false. +.false. -.true. +.false. diff --git a/bld/namelist_files/namelist_defaults_clm4_5_tools.xml b/bld/namelist_files/namelist_defaults_clm4_5_tools.xml index 90cec98eaf..d6cece9e92 100644 --- a/bld/namelist_files/namelist_defaults_clm4_5_tools.xml +++ b/bld/namelist_files/namelist_defaults_clm4_5_tools.xml @@ -22,6 +22,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). lnd/clm2/mappingdata/grids/SCRIPgrid_0.23x0.31_nomask_c110308.nc +lnd/clm2/mappingdata/grids/SCRIPgrid_0.47x0.63_nomask_c170914.nc lnd/clm2/mappingdata/grids/0.9x1.25_c110307.nc lnd/clm2/mappingdata/grids/1.9x2.5_c110308.nc lnd/clm2/mappingdata/grids/SCRIPgrid_2.5x3.33_nomask_c110308.nc @@ -58,12 +59,16 @@ attributes from the config_cache.xml file (with keys converted to upper-case). >lnd/clm2/mappingdata/grids/SCRIPgrid_0.5x0.5_AVHRR_c110228.nc lnd/clm2/mappingdata/grids/SCRIPgrid_0.5x0.5_MODIS_c110228.nc +lnd/clm2/mappingdata/grids/SCRIPgrid_0.25x0.25_MODIS_c170321.nc lnd/clm2/mappingdata/grids/SCRIPgrid_5x5min_nomask_c110530.nc lnd/clm2/mappingdata/grids/SCRIPgrid_5x5min_IGBP-GSDP_c110228.nc lnd/clm2/mappingdata/grids/SCRIPgrid_5x5min_ISRIC-WISE_c111114.nc +lnd/clm2/mappingdata/grids/SCRIPgrid_5x5min_ORNL-Soil_c170630.nc lnd/clm2/mappingdata/grids/SCRIPgrid_10x10min_nomask_c110228.nc lnd/clm2/mappingdata/grids/SCRIPgrid_1x1pt_mexicocityMEX_nomask_c110308.nc lnd/clm2/mappingdata/grids/SCRIPgrid_1x1pt_numaIA_nomask_c110308.nc lnd/clm2/mappingdata/grids/SCRIPgrid_1x1pt_smallvilleIA_nomask_c110308.nc -lnd/clm2/mappingdata/grids/SCRIPgrid_1x1pt_tropicAtl_nomask_c110308.nc lnd/clm2/mappingdata/grids/SCRIPgrid_1x1pt_urbanc_alpha_nomask_c110308.nc lnd/clm2/mappingdata/grids/SCRIPgrid_1x1pt_vancouverCAN_nomask_c110308.nc lnd/clm2/mappingdata/grids/SCRIPgrid_5x5pt_amazon_nomask_c110308.nc @@ -128,7 +132,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). MODIS MODIS MODIS -GRDC +MODIS LandScan2004 MODIS ISRIC-WISE @@ -141,7 +145,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). IGBP-GSDP AVHRR AVHRR -ISRIC-WISE +ORNL-Soil AVHRR HYDRO1K-merge-nomask GRDC @@ -151,12 +155,12 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 3x3min 0.5x0.5 0.5x0.5 -0.5x0.5 -0.5x0.5 +0.25x0.25 +0.25x0.25 3x3min -0.9x1.25 +0.25x0.25 3x3min -0.5x0.5 +0.25x0.25 5x5min 3x3min 10x10min @@ -178,7 +182,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). mksrf_fvocef mksrf_flai mksrf_fvegtyp -mksrf_fhrvtyp +mksrf_fvegtyp mksrf_furban mksrf_fsoicol mksrf_forganic @@ -200,8 +204,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). -lnd/clm2/rawdata/pftlandusedyn.0.5x0.5.simyr1850-2005.c090630/mksrf_lai_global_c090506.nc +lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_lai_78pfts_simyr2005.c170413.nc @@ -211,8 +215,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). lnd/clm2/rawdata/mksrf_soitex.10level.c010119.nc -lnd/clm2/rawdata/pftlandusedyn.0.5x0.5.simyr1850-2005.c090630/mksrf_soilcol_global_c090324.nc +lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_soilcolor_CMIP6_simyr2005.c170623.nc lnd/clm2/rawdata/mksrf_organic_10level_5x5min_ISRIC-WISE-NCSCD_nlev7_c120830.nc @@ -255,7 +259,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). lnd/clm2/rawdata/mksrf_GlacierRegion_10x10min_nomask_c160122.nc +>lnd/clm2/rawdata/mksrf_GlacierRegion_10x10min_nomask_c170616.nc lnd/clm2/rawdata/mksrf_peatf_0.5x0.5_AVHRR_simyr2000.c130228.nc -lnd/clm2/rawdata/mksf_soilthk_5x5min_ORNL_SOILS_simyr1900-2015_c150701.nc +lnd/clm2/rawdata/mksf_soilthk_5x5min_ORNL-Soil_simyr1900-2015_c170630.nc lnd/clm2/rawdata/mksrf_abm_0.5x0.5_AVHRR_simyr2000.c130201.nc @@ -286,675 +290,339 @@ attributes from the config_cache.xml file (with keys converted to upper-case). -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1850.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1850.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1851.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1851.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1852.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1852.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1853.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1853.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1854.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1854.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1855.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1855.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1856.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1856.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1857.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1857.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1858.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1858.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1859.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1859.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1860.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1860.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1861.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1861.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1862.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1862.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1863.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1863.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1864.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1864.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1865.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1865.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1866.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1866.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1867.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1867.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1868.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1868.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1869.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1869.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1870.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1870.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1871.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1871.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1872.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1872.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1873.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1873.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1874.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1874.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1875.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1875.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1876.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1876.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1877.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1877.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1878.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1878.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1879.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1879.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1880.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1880.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1881.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1881.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1882.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1882.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1883.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1883.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1884.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1884.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1885.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1885.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1886.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1886.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1887.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1887.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1888.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1888.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1889.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1889.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1890.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1890.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1891.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1891.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1892.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1892.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1893.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1893.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1894.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1894.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1895.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1895.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1896.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1896.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1897.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1897.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1898.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1898.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1899.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1899.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1900.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1900.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1901.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1901.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1902.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1902.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1903.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1903.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1904.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1904.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1905.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1905.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1906.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1906.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1907.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1907.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1908.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1908.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1909.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1909.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1910.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1910.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1911.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1911.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1912.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1912.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1913.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1913.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1914.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1914.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1915.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1915.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1916.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1916.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1917.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1917.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1918.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1918.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1919.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1919.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1920.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1920.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1921.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1921.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1922.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1922.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1923.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1923.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1924.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1924.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1925.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1925.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1926.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1926.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1927.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1927.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1928.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1928.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1929.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1929.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1930.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1930.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1931.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1931.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1932.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1932.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1933.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1933.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1934.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1934.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1935.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1935.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1936.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1936.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1937.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1937.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1938.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1938.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1939.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1939.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1940.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1940.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1941.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1941.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1942.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1942.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1943.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1943.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1944.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1944.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1945.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1945.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1946.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1946.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1947.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1947.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1948.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1948.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1949.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1949.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1950.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1950.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1951.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1951.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1952.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1952.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1953.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1953.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1954.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1954.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1955.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1955.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1956.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1956.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1957.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1957.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1958.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1958.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1959.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1959.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1960.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1960.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1961.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1961.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1962.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1962.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1963.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1963.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1964.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1964.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1965.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1965.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1966.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1966.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1967.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1967.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1968.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1968.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1969.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1969.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1970.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1970.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1971.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1971.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1972.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1972.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1973.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1973.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1974.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1974.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1975.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1975.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1976.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1976.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1977.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1977.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1978.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1978.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1979.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1979.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1980.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1980.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1981.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1981.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1982.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1982.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1983.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1983.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1984.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1984.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1985.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1985.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1986.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1986.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1987.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1987.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1988.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1988.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1989.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1989.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1990.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1990.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1991.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1991.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1992.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1992.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1993.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1993.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1994.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1994.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1995.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1995.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1996.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1996.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1997.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1997.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1998.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1998.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1999.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_1999.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2000.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2000.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2001.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2001.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2002.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2002.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2003.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2003.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2004.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2004.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2005.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2005.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2006.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2006.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2007.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2007.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2008.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2008.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2009.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2009.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2010.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2010.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2011.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2011.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2012.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2012.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2013.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2013.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2014.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2014.c170629.nc -lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2015.c161208.nc +lnd/clm2/rawdata/pftcftdynharv.0.25x0.25.LUH2.histsimyr1850-2015.c170629/mksrf_landuse_histclm50_LUH2_2015.c170629.nc - - - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1850_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1851_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1852_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1853_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1854_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1855_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1856_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1857_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1858_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1859_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1860_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1861_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1862_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1863_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1864_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1865_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1866_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1867_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1868_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1869_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1870_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1871_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1872_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1873_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1874_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1875_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1876_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1877_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1878_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1879_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1880_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1881_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1882_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1883_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1884_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1885_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1886_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1887_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1888_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1889_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1890_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1891_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1892_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1893_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1894_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1895_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1896_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1897_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1898_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1899_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1900_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1901_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1902_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1903_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1904_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1905_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1906_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1907_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1908_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1909_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1910_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1911_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1912_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1913_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1914_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1915_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1916_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1917_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1918_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1919_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1920_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1921_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1922_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1923_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1924_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1925_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1926_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1927_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1928_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1929_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1930_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1931_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1932_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1933_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1934_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1935_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1936_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1937_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1938_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1939_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1940_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1941_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1942_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1943_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1944_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1945_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1946_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1947_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1948_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1949_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1950_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1951_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1952_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1953_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1954_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1955_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1956_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1957_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1958_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1959_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1960_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1961_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1962_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1963_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1964_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1965_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1966_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1967_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1968_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1969_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1970_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1971_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1972_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1973_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1974_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1975_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1976_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1977_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1978_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1979_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1980_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1981_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1982_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1983_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1984_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1985_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1986_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1987_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1988_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1989_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1990_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1991_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1992_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1993_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1994_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1995_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1996_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1997_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1998_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1999_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2000_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2001_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2002_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2003_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2004_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2005_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2006_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2007_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2008_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2009_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2010_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2011_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2012_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2013_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2014_c170103.nc - -lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2015_c170103.nc - - atm/cam/ggas/ghg_hist_1765-2005_c091218.nc atm/cam/ggas/ghg_rcp26_1765-2500_c100405.nc diff --git a/bld/namelist_files/namelist_defaults_drv.xml b/bld/namelist_files/namelist_defaults_drv.xml new file mode 100644 index 0000000000..2ad5c26013 --- /dev/null +++ b/bld/namelist_files/namelist_defaults_drv.xml @@ -0,0 +1,9 @@ + + + + + + +Buildconf/camconf/drv_flds_in,Buildconf/clmconf/drv_flds_in + + diff --git a/bld/namelist_files/namelist_defaults_overall.xml b/bld/namelist_files/namelist_defaults_overall.xml index 73efac3e50..a21a0c006e 100644 --- a/bld/namelist_files/namelist_defaults_overall.xml +++ b/bld/namelist_files/namelist_defaults_overall.xml @@ -13,9 +13,12 @@ determine default values for namelists. --> -arb_ic -cold -cold +startup +startup +arb_ic +arb_ic +arb_ic +cold /fs/cgd/csm/inputdata @@ -23,7 +26,6 @@ determine default values for namelists. 1.9x2.5 1x1_brazil -1x1_tropicAtl 5x5_amazon 1x1_camdenNJ 1x1_vancouverCAN @@ -76,7 +78,6 @@ determine default values for namelists. gx1v6 navy -test navy navy navy diff --git a/bld/namelist_files/namelist_definition_clm4_0.xml b/bld/namelist_files/namelist_definition_clm4_0.xml index 0cf9ae564d..197fc3a9b4 100644 --- a/bld/namelist_files/namelist_definition_clm4_0.xml +++ b/bld/namelist_files/namelist_definition_clm4_0.xml @@ -668,7 +668,7 @@ CLM run type. +"512x1024,360x720cru,128x256,64x128,48x96,32x64,8x16,94x192,0.23x0.31,0.47x0.63,0.9x1.25,1.9x2.5,2.5x3.33,4x5,10x15,5x5_amazon,1x1_camdenNJ,1x1_vancouverCAN,1x1_mexicocityMEX,1x1_asphaltjungleNJ,1x1_brazil,1x1_urbanc_alpha,1x1_numaIA,1x1_smallvilleIA,0.1x0.1,0.5x0.5,3x3min,5x5min,10x10min,0.33x0.33,ne4np4,ne16np4,ne30np4,ne60np4,ne120np4,ne240np4"> Horizontal resolutions Note: 0.1x0.1, 0.5x0.5, 5x5min, 10x10min, 3x3min and 0.33x0.33 are only used for CLM tools diff --git a/bld/namelist_files/namelist_definition_clm4_5.xml b/bld/namelist_files/namelist_definition_clm4_5.xml index 751b128675..ffadfe02a0 100644 --- a/bld/namelist_files/namelist_definition_clm4_5.xml +++ b/bld/namelist_files/namelist_definition_clm4_5.xml @@ -220,6 +220,16 @@ Critical RH for ignition (0-100) Saturation RH for ignition (0-100) + +Lower threshold for fuel mass needed for ignition + + + +Upper threshold for fuel mass needed for ignition + + Saturation BTRAN for ignition (0-1) @@ -240,6 +250,11 @@ Global constant for deforestation fires (/day) Fire occurance for high GDP areas that are tree dominated (fraction) + +Combustion completeness factor (for litter and CWD[Course Woody Debris]) (unitless) + + Critical threshold for truncation of Nitrogen (truncate Nitrogen states to zero below this value) @@ -265,6 +280,11 @@ Critical threshold of negative Carbon to die (abort when Carbon states are below Initial stocks of Carbon to use in soil organic matter pools for CENTURY decomposition + +Soil depth to place initial stocks of Carbon in soil organic matter pools for CENTURY decomposition + + Slope of free living Nitrogen fixation with annual ET @@ -277,7 +297,7 @@ Intercept of free living Nitrogen fixation with zero annual ET -If TRUE use the undercanopy stability term used with CLM4.5 (Sakaguchi&Zeng, 2008) +If TRUE use the undercanopy stability term used with CLM4.5 (Sakaguchi&Zeng, 2008) Index of lower boundary condition for Richards equation. -lower_boundary_condition = 1 : flux lower boundary condition -lower_boundary_condition = 2 : zero-flux lower boundary condition -lower_boundary_condition = 3 : water table head-based lower boundary condition w/ aquifer layer. -lower_boundary_condition = 4 : 11-layer solution w/ aquifer layer +lower_boundary_condition = 1 : flux lower boundary condition (use with soilwater_movement_method=adaptive time stepping) +lower_boundary_condition = 2 : zero-flux lower boundary condition (use with soilwater_movement_method=adaptive time stepping) +lower_boundary_condition = 3 : water table head-based lower boundary condition w/ aquifer layer. (use with soilwater_movement_method=adaptive time stepping) +lower_boundary_condition = 4 : 11-layer solution w/ aquifer layer (only used with soilwater_movement_method=Zeng&Decker 2009) TODO(bja, 2015-09) these should be strings so they have meaningful names instead of ints. @@ -420,15 +440,14 @@ If TRUE, irrigation will be active. + group="clm_inparm" valid_values="1,3,5,10,36" > Number of multiple elevation classes over glacier points. -Normally this is ONLY used when running CESM with the active glacier model. If TRUE, dynamically change areas and topographic heights over glacier points. -Only works when glc_nec is greater than zero, and when coupled to CISM. +Only works when running with a non-stub glacier model. + + +Treatment of ice runoff for each glacier region (GLACIER_REGION in surface dataset). +First item corresponds to GLACIER_REGION with ID 0 in the surface dataset, +second to GLACIER_REGION with ID 1, etc. +Allowed values are: +'remains_ice': ice runoff is sent to the river model as ice; this is a crude parameterization + of iceberg calving, and so is appropriate in regions where there is substantial iceberg calving + in reality +'melted': ice runoff generated by the CLM physics (primarily due to snow capping) is melted + (generating a negative sensible heat flux) and runs off as liquid; this is appropriate in + regions that have little iceberg calving in reality. This can be important to avoid unrealistic + cooling of the ocean and consequent runaway sea ice growth. +Only applies when melt_non_icesheet_ice_runoff is .true. Number of days before one considers the perennially snow-covered point 'land ice' -(and thus capable of generating a positive surface mass balance for CISM). +(and thus capable of generating a positive surface mass balance for the glacier model). This is meant to compensate for the fact that, with small values of h2osno_max, the onset of a snow-capped state (and thus conversion to land ice) can occur in an unrealistically short amount of time. @@ -499,7 +533,12 @@ Atkin, Fisher et al. (2008) and Lombardozzi et al. (2015) Switch to inihibit photosynthesis in daytime -Lloyd et al. 2010, & Metcalfe et al. 2012 +Lloyd et al. 2010, & Metcalfe et al. 2012 + + + +Modify photosynthesis and leaf maintence respiration for crop + +Stomatal conductance model method to use + + Ball-Berry1987 --- Ball Berry 1987 methodology + Medlyn2011 ------- Medlyn 2011 methodology + + + Scalar of leaf respiration to vcmax @@ -537,13 +585,13 @@ Override the start type from the driver: it can only be set to 3 meaning branch. - Toggle to turn on the ED (ED = 'on' is EXPERIMENTAL NOT SUPPORTED!) - Toggle to turn on spit fire (only relevant if ED is being used). @@ -579,6 +627,11 @@ Full pathname datafile with plant function type (PFT) constants combined with constants for biogeochem modules + +Full pathname datafile with fates parameters + + Full pathname of surface data file. @@ -1319,6 +1372,18 @@ Temperature above which all precipitation falls as rain, for non-glacier columns Only relevant if repartition_rain_snow is .true. + + + + + +If TRUE, ice runoff generated from non-glacier columns and glacier columns outside icesheet regions +is converted to liquid, with an appropriate sensible heat flux. +That is, the atmosphere (rather than the ocean) melts the ice. +(Exception: ice runoff generated to ensure conservation with dynamic landunits remains as ice.) + + @@ -1343,6 +1408,20 @@ Simulation year that aligns with stream_year_first_ndep value Filename of input stream data for Nitrogen Deposition + +Time interpolation mode to determine how to handle data before and after the times in the file + cycle = Always cycle over the data + extend = Use the first time before the available data, and use the last time after the available data + limit = Only use the data within the times available -- abort if the model tries to go outside it + + + +Colon delimited list of variables to read from the streams file for nitrogen deposition +(Normally just read the single variable NDEP_year or NDEP_month) + + Mapping method from Nitrogen deposition input file to the model resolution @@ -1354,6 +1433,16 @@ Mapping method from Nitrogen deposition input file to the model resolution copy = copy using the same indices + + + + + +Filename of input stream data for finundated inversion of observed (from Prigent dataset) +to hydrologic variables (either TWS or ZWT) + + @@ -1530,13 +1619,13 @@ Mapping file to go from one resolution/land-mask to another resolution/land-mask + valid_values="nomask,navy,AVHRR,MODIS,USGS,IGBPmergeICESatGIS,IGBP-GSDP,ISRIC-WISE,LandScan2004,GLOBE-Gardner,GLOBE-Gardner-mergeGIS,GRDC,HYDRO1K-merge-nomask,ORNL-Soil"> Land mask description for mksurfdata input files + valid_values="0.1x0.1,0.25x0.25,0.5x0.5,10x10min,5x5min,360x720cru,0.9x1.25,19basin,1km-merge-10min"> Horizontal grid resolutions for mksurfdata input files @@ -1545,6 +1634,13 @@ Horizontal grid resolutions for mksurfdata input files + +Resolution of finundated inversion streams dataset (stream_fldfilename_ch4finundated) +to use for methane model +(only applies when CN and methane model are turned on) + + Resolution of Lightning dataset to use for CN fire model @@ -1575,9 +1671,9 @@ CLM run type. +"512x1024,360x720cru,128x256,64x128,48x96,32x64,8x16,94x192,0.23x0.31,0.47x0.63,0.9x1.25,1.9x2.5,2.5x3.33,4x5,10x15,5x5_amazon,1x1_camdenNJ,1x1_vancouverCAN,1x1_mexicocityMEX,1x1_asphaltjungleNJ,1x1_brazil,1x1_urbanc_alpha,1x1_numaIA,1x1_smallvilleIA,0.1x0.1,0.25x0.25,0.5x0.5,3x3min,5x5min,10x10min,0.33x0.33,0.125x0.125,ne4np4,ne16np4,ne30np4,ne60np4,ne120np4,ne240np4,1km-merge-10min"> Horizontal resolutions -Note: 0.1x0.1, 0.5x0.5, 5x5min, 10x10min, 3x3min and 0.33x0.33 are only used for CLM tools +Note: 0.1x0.1, 0.25x0.25, 0.5x0.5, 5x5min, 10x10min, 3x3min and 0.33x0.33 are only used for CLM tools + valid_values="clm4_5_CRUNCEP,clm5_0_cam5.5,clm5_0_GSW3P"> General configuration of model version and atmospheric forcing to tune the model to run under. This sets the model to run with constants that were set to run well under the configuration of model version and atmospheric forcing. To run well constants would need to be changed to run with a different type of atmospheric forcing. - -If TRUE, irrigation will be active (find surface datasets with active irrigation). - - If 1, turn on the MEGAN model for BVOC's (Biogenic Volitile Organic Compounds) @@ -1614,7 +1705,7 @@ If 1, turn on the MEGAN model for BVOC's (Biogenic Volitile Organic Compounds) +"1000,850,1100,1350,1600,1850,1855,1865,1875,1885,1895,1905,1915,1925,1935,1945,1955,1965,1975,1980,1985,1995,2000,2005,2015,2025,2035,2045,2055,2065,2075,2085,2095,2105"> Year to simulate and to provide datasets for (such as surface datasets, initial conditions, aerosol-deposition, Nitrogen deposition rates etc.) A sim_year of 1000 corresponds to data used for testing only, NOT corresponding to any real datasets. A sim_year greater than 2005 corresponds to rcp scenario data @@ -1624,7 +1715,7 @@ CLM datasets exist for years: 1000 (for testing), 1850, and 2000 +"constant,1000-1002,1000-1004,850-1100,1100-1350,1350-1600,1600-1850,1850-1855,1850-2000,1850-2005,1850-2100,1980-2015,2000-2100"> Range of years to simulate transitory datasets for (such as dynamic: land-use datasets, aerosol-deposition, Nitrogen deposition rates etc.) Constant means simulation will be held at a constant year given in sim_year. A sim_year_range of 1000-1002 or 1000-1004 corresponds to data used for testing only, NOT corresponding to any real datasets. @@ -1641,6 +1732,21 @@ Namelist entries to demand be provided on the namelist. Description of the use case selected. + +Attributes to use when looking for an initial condition file (finidat) if interpolation is turned on (use_init_interp is .true.) + + + +How close in years to use when looking for an initial condition file (finidat) if interpolation is turned on (use_init_interp is .true.) + + + +Simulation years you can look for in initial condition files (finidat) if interpolation is turned on (use_init_interp is .true.) + + Command line argument for setting up your simulation in a mode for faster @@ -1651,8 +1757,8 @@ NOTE: THIS CORRESPONDS DIRECTLY TO THE env_run.xml VARIABLE OF THE SAME NAME. Set the env_run variable, rather than setting this directly. - + Command line arguement for biogeochemistry mode for CLM4.5 sp = Satellitte Phenology cn = Carbon Nitrogen model @@ -1661,7 +1767,7 @@ Command line arguement for biogeochemistry mode for CLM4.5 Nitrification/De-nitrification Methane model Vertically resolved Carbon - ed = ED (Ecosystem Demography) model with below ground BGC: + fates = FATES/ED ecosystem demography model with below ground BGC: @@ -1742,6 +1848,12 @@ If true, no denitrification or nitrification in frozen soil layers. Number of days over which to use exponential relaxation of NPP in N fixation calculation + + +Flag to reseed any dead plants on startup from reading the initial conditions file + + @@ -1755,13 +1867,25 @@ Enable C14 model -Flag to use the atmospheric time series of C14 concentrations from bomb fallout, rather than natural abundance C14 (nominally set as 10^-12 mol C14 / mol C) +Flag to use the atmospheric time series of C14 concentrations from bomb fallout and Seuss effect, rather than natural abundance C14 (nominally set as 10^-12 mol C14 / mol C) (EXPERIMENTAL and NOT tested) - -Filename with time series of atmospheric Delta C14 data. variables in file are "time" and "atm_delta_c14". time variable is in format 1950.0, and time values must be monotonically increasing for interpolation, however spacing can be unequal. atm_delta_c14 variable has units of permil. + +Filename with time series of atmospheric Delta C14 data. variables in file are "time" and "Delta14co2_in_air". time variable is in format: years since 1850-01-01 0:0:0.0 units are permil. +(EXPERIMENTAL and NOT tested) + + + +Flag to use the atmospheric time series of C13 concentrations from natural abundance and the Seuss Effect, rather than static values. +(EXPERIMENTAL and NOT tested) + + + +Filename with time series of atmospheric Delta C13 data, which use CMIP6 format. variables in file are "time" and "delta13co2_in_air". time variable is in format: years since 1850-01-01 0:0:0.0. units are permil. (EXPERIMENTAL and NOT tested) @@ -1806,6 +1930,11 @@ Allow the CN ratio to flexibly change with the simulation, rather than being fix Michaelis Menten nitrogen uptake kinetics + +How much Carbon to initialize vegetation pools (leafc/frootc and storage) to when -- Michaelis Menten nitrogen uptake kinetics is on + + GPP downregulation for use_flexibleCN option @@ -1965,12 +2094,17 @@ so the coupled system will NOT conserve carbon in this mode if the methane model (EXPERIMENTAL and NOT tested) - -If TRUE, use the saturated fraction (fsat) calculated in Soil Hydrology to diagnose the inundated fraction (finundated) -for the CH4 submodel (possibly affecting soil heterotrophic respiration and denitrification depending on the configuration), -rather than using the inversion to satellite-observed inundated fraction, which requires additional surface data. -(EXPERIMENTAL and NOT tested) + +Inundated fraction method type to use for the CH4 submodel (possibly affecting soil +heterotrophic respiration and denitrification depending on the configuration), + +h2osfc ----------- Use prognostic saturated fraction h2osfc value calculated in Soil Hydrology +ZWT_inversion ---- Use inversion of Prigent Satellite data to model ZWT +TWS_inversion ---- Use inversion of Prigent Satellite data to model TWS + +Inversion options require additional data on fsurdat or use of stream_fldfilename_ch4finundated files. +(h2osfc option is EXPERIMENTAL and NOT tested) + +If TRUE, set the dynbal water and energy fluxes to zero. This should typically +only be done for testing: This is needed in some tests where we have daily +rather than annual glacier dynamics: if we allow the true dynbal adjustment +fluxes in those tests, we end up with sensible heat fluxes of thousands of W m-2 +or more, which causes CAM to blow up. However, note that setting it to true will +break water and energy conservation! + + @@ -2126,6 +2270,62 @@ Not used for snow_overburden_compaction_method=Vionnet2012 Minimum wind speed tht results in compaction (m/s) + +maximum warm (at freezing) fresh snow effective radius [microns] + + + +If set to .true., then reset the snow pack over non-glacier columns to a small value. +This is useful when transitioning from a spinup under one set of atmospheric forcings +to a run under a different set of atmospheric forcings: By resetting too-large snow packs, +we make it more likely that points will remain only seasonally snow-covered under the new +atmospheric forcings. (This is particularly true in a coupled run, where starting with a +too-large snow pack can cool the atmosphere, thus maintaining the too-large snow pack.) + +WARNING: Setting this to .true. will break water conservation for approximately the first +day of the new run. This is by design: The excess snow is completely removed from the system. + + + +If set to .true., then reset the snow pack over glacier columns to a small value. +This is useful when transitioning from a spinup under one set of atmospheric forcings +to a run under a different set of atmospheric forcings: By resetting too-large snow packs, +we make it more likely that points will remain only seasonally snow-covered under the new +atmospheric forcings. (This is particularly true in a coupled run, where starting with a +too-large snow pack can cool the atmosphere, thus maintaining the too-large snow pack.) + +See also reset_snow_glc_ela, which controls the elevation below which +glacier columns are reset. + +WARNING: Setting this to .true. will break water conservation for approximately the first +day of the new run. This is by design: The excess snow is completely removed from the system. + +WARNING: This variable is intended for short test runs, and generally +should not be used for scientific production runs. By resetting snow +below a given elevation, you risk forcing the system to evolve +differently in areas below and above reset_snow_glc_ela. + + + +Only relevant if reset_snow_glc is .true. + +When resetting snow pack over glacier columns, one can choose to do this over all glacier +columns, or only those below a certain elevation. A typical use case is to reset only those +columns that have a seasonal snow pack in the real world, i.e. SMB less than 0, also known as +the equilibrium line altitude (ELA). This parameter sets a single global ELA value. By +setting this parameter to a large value (i.e. 10000 m), all glacier columns will be reset. + +WARNING: This variable is intended for short test runs, and generally +should not be used for scientific production runs. By resetting snow +below a given elevation, you risk forcing the system to evolve +differently in areas below and above reset_snow_glc_ela. + + + diff --git a/bld/namelist_files/namelist_definition_drv.xml b/bld/namelist_files/namelist_definition_drv.xml new file mode 100644 index 0000000000..493f2f2a01 --- /dev/null +++ b/bld/namelist_files/namelist_definition_drv.xml @@ -0,0 +1,17 @@ + + + + + 1.0 + + + + + + + + + diff --git a/bld/namelist_files/namelist_definition_drv_flds.xml b/bld/namelist_files/namelist_definition_drv_flds.xml new file mode 100644 index 0000000000..b54082981a --- /dev/null +++ b/bld/namelist_files/namelist_definition_drv_flds.xml @@ -0,0 +1,131 @@ + + + + + + + + List of files to merge together that contains drv_flds_in namelists + The paths are relative to the case directory. drv_flds_in include the namelists that + the driver reads and gives information on additional fields to be passed to different + components that need to look at the same data. + + + + + + + + File containing MEGAN emissions factors. Includes the list of MEGAN compounds that can be + used in the Comp_Name variable on the file. + + + + MEGAN specifier. This is in the form of: Chem-compound = megan_compound(s) + where megan_compound(s) can be the sum of megan compounds with a "+" between them. + In each equation, the item to the left of the equal sign is a CAM chemistry compound, the + items to the right are compounds known to the MEGAN model (single or combinations). + For example: megan_specifier = 'ISOP = isoprene', 'C10H16 = pinene_a + carene_3 + thujene_a' + + + + MEGAN mapped isoprene emissions factors switch + If TRUE then use mapped MEGAN emissions factors for isoprene. + + + + List of possible MEGAN compounds to use + (the list used by the simulation is on the megan_factors_file as the Comp_Name) + + + + + + + + Where dry deposition is calculated (from land, atmosphere, or from a table) + This specifies the method used to calculate dry + deposition velocities of gas-phase chemical species. The available methods + are: + 'table' - prescribed method in CAM + 'xactive_atm' - interactive method in CAM + 'xactive_lnd' - interactive method in CLM + + + + List of species that undergo dry deposition. + + + + + + + + + File containing fire emissions factors. + Default: none + + + + Fire emissions specifier. + Default: none + + + + If ture fire emissions are input into atmosphere as elevated forcings. + Otherwise they are treated as surface emissions. + Default: TRUE + + + + + + + + List of fluxes needed by the CARMA model, from CLM to CAM. + + + diff --git a/bld/namelist_files/use_cases/1850-2100_rcp2.6_glacierMEC_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp2.6_glacierMEC_transient.xml deleted file mode 100644 index c7da5b57a9..0000000000 --- a/bld/namelist_files/use_cases/1850-2100_rcp2.6_glacierMEC_transient.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - -Simulate transient land-use, and aerosol deposition changes with historical data from 1850 to 2005 and then with the RCP2.6 scenario from IMAGE - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP2.6 scenario from IMAGE - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP2.6 scenario from IMAGE - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP2.6 scenario from IMAGE - - -1850 - -1850-2100 - -2.6 - -flanduse_timeseries - -10 - -arb_ic - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2010 -1850 - -1850 -2010 -1850 - -1850 -2100 -1850 - - diff --git a/bld/namelist_files/use_cases/1850-2100_rcp2.6_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp2.6_transient.xml index 4fea7fd453..fce8ffe566 100644 --- a/bld/namelist_files/use_cases/1850-2100_rcp2.6_transient.xml +++ b/bld/namelist_files/use_cases/1850-2100_rcp2.6_transient.xml @@ -20,6 +20,10 @@ flanduse_timeseries +.true. +.false. +.false. + arb_ic 1850 diff --git a/bld/namelist_files/use_cases/1850-2100_rcp4.5_glacierMEC_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp4.5_glacierMEC_transient.xml deleted file mode 100644 index 3e8abe7ef7..0000000000 --- a/bld/namelist_files/use_cases/1850-2100_rcp4.5_glacierMEC_transient.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - -Simulate transient land-use, and aerosol deposition changes with historical data from 1850 to 2005 and then with the RCP4.5 scenario from MINICAM - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP4.5 scenario from MINICAM - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP4.5 scenario from MINICAM - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP4.5 scenario from MINICAM - - -1850 - -1850-2100 - -4.5 - -flanduse_timeseries - -10 - -arb_ic - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2010 -1850 - -1850 -2010 -1850 - -1850 -2100 -1850 - - diff --git a/bld/namelist_files/use_cases/1850-2100_rcp4.5_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp4.5_transient.xml index 03905a6de0..615472604f 100644 --- a/bld/namelist_files/use_cases/1850-2100_rcp4.5_transient.xml +++ b/bld/namelist_files/use_cases/1850-2100_rcp4.5_transient.xml @@ -22,6 +22,10 @@ arb_ic +.true. +.false. +.false. + 1850 2100 1850 diff --git a/bld/namelist_files/use_cases/1850-2100_rcp6_glacierMEC_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp6_glacierMEC_transient.xml deleted file mode 100644 index af01393c97..0000000000 --- a/bld/namelist_files/use_cases/1850-2100_rcp6_glacierMEC_transient.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - -Simulate transient land-use, and aerosol deposition changes with historical data from 1850 to 2005 and then with the RCP6 scenario from AIM - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP6 scenario from AIM - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP6 scenario from AIM - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP6 scenario from AIM - - -1850 - -1850-2100 - -6 - -flanduse_timeseries - -10 - -arb_ic - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2010 -1850 - -1850 -2010 -1850 - -1850 -2100 -1850 - - diff --git a/bld/namelist_files/use_cases/1850-2100_rcp6_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp6_transient.xml index c218f56509..5887842a30 100644 --- a/bld/namelist_files/use_cases/1850-2100_rcp6_transient.xml +++ b/bld/namelist_files/use_cases/1850-2100_rcp6_transient.xml @@ -20,6 +20,10 @@ 6 +.true. +.false. +.false. + flanduse_timeseries arb_ic diff --git a/bld/namelist_files/use_cases/1850-2100_rcp8.5_glacierMEC_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp8.5_glacierMEC_transient.xml deleted file mode 100644 index e2b8d1b199..0000000000 --- a/bld/namelist_files/use_cases/1850-2100_rcp8.5_glacierMEC_transient.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - -Simulate transient land-use, and aerosol deposition changes with historical data from 1850 to 2005 and then with the RCP8.5 scenario from MESSAGE - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP8.5 scenario from MESSAGE - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP8.5 scenario from MESSAGE - -Simulate transient land-use, aerosol and Nitrogen deposition changes with historical data from 1850 to 2005 and then with the RCP8.5 scenario from MESSAGE - - -1850 - -1850-2100 - -8.5 - -flanduse_timeseries - -10 - -arb_ic - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2100 -1850 - -1850 -2010 -1850 - -1850 -2010 -1850 - -1850 -2100 -1850 - - diff --git a/bld/namelist_files/use_cases/1850-2100_rcp8.5_transient.xml b/bld/namelist_files/use_cases/1850-2100_rcp8.5_transient.xml index acd68e515a..25f0c254f8 100644 --- a/bld/namelist_files/use_cases/1850-2100_rcp8.5_transient.xml +++ b/bld/namelist_files/use_cases/1850-2100_rcp8.5_transient.xml @@ -18,6 +18,10 @@ 8.5 +.true. +.false. +.false. + flanduse_timeseries arb_ic diff --git a/bld/namelist_files/use_cases/1850_control.xml b/bld/namelist_files/use_cases/1850_control.xml index 16b35e9d8f..b5628d870f 100644 --- a/bld/namelist_files/use_cases/1850_control.xml +++ b/bld/namelist_files/use_cases/1850_control.xml @@ -8,6 +8,9 @@ constant +.false. +.false. + 1850 1850 diff --git a/bld/namelist_files/use_cases/1850_glacierMEC_control.xml b/bld/namelist_files/use_cases/1850_glacierMEC_control.xml deleted file mode 100644 index d6aeea42f3..0000000000 --- a/bld/namelist_files/use_cases/1850_glacierMEC_control.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - -Running an IG case for 1850 conditions with the ice sheet model glimmer - -1850 - -constant - -1850 -1850 - -1850 -1850 - -1850 -1850 - -1850 -1850 - -1850 -1850 - -1850 -1850 - -1850 -1850 - -10 - - diff --git a/bld/namelist_files/use_cases/2000-2100_rcp8.5_transient.xml b/bld/namelist_files/use_cases/2000-2100_rcp8.5_transient.xml index e14c3a5678..9094e6b27b 100644 --- a/bld/namelist_files/use_cases/2000-2100_rcp8.5_transient.xml +++ b/bld/namelist_files/use_cases/2000-2100_rcp8.5_transient.xml @@ -17,6 +17,10 @@ 8.5 +.true. +.false. +.false. + flanduse_timeseries arb_ic diff --git a/bld/namelist_files/use_cases/2000_control.xml b/bld/namelist_files/use_cases/2000_control.xml index 0d0380700f..ca7c1ac5cd 100644 --- a/bld/namelist_files/use_cases/2000_control.xml +++ b/bld/namelist_files/use_cases/2000_control.xml @@ -8,6 +8,10 @@ constant +.true. +.false. +.false. + 2000 2000 diff --git a/bld/namelist_files/use_cases/2000_glacierMEC_control.xml b/bld/namelist_files/use_cases/2000_glacierMEC_control.xml deleted file mode 100644 index 362613c180..0000000000 --- a/bld/namelist_files/use_cases/2000_glacierMEC_control.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - -Running an IG case for 2000 conditions with the ice sheet model glimmer - -2000 - -constant - -2000 -2000 - -2000 -2000 - -2000 -2000 - -2000 -2000 - -2000 -2000 - -2000 -2000 - -2000 -2000 - -10 - - diff --git a/bld/namelist_files/use_cases/20thC_glacierMEC_transient.xml b/bld/namelist_files/use_cases/20thC_glacierMEC_transient.xml deleted file mode 100644 index 0fb5806ac1..0000000000 --- a/bld/namelist_files/use_cases/20thC_glacierMEC_transient.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - -Simulate transient land-use, and aerosol deposition changes from 1850 to 2005 -Simulate transient land-use, aerosol deposition, and Nitrogen deposition changes from 1850 to 2005 -Simulate transient land-use, aerosol deposition, and Nitrogen deposition changes from 1850 to 2005 -Simulate transient land-use, aerosol deposition, and Nitrogen deposition changes from 1850 to 2005 - -1850 - -1850-2000 - -arb_ic - -flanduse_timeseries - -10 - -1850 -2005 -1850 - -1850 -2005 -1850 - -1850 -2005 -1850 - -1850 -2005 -1850 - -1850 -2010 -1850 - -1850 -2010 -1850 - -1850 -2005 -1850 - - diff --git a/bld/namelist_files/use_cases/20thC_transient.xml b/bld/namelist_files/use_cases/20thC_transient.xml index 51d97829ca..3ee0134b9b 100644 --- a/bld/namelist_files/use_cases/20thC_transient.xml +++ b/bld/namelist_files/use_cases/20thC_transient.xml @@ -15,6 +15,10 @@ flanduse_timeseries +.true. +.false. +.false. + 1850 2005 1850 diff --git a/bld/namelist_files/use_cases/glacierMEC_pd.xml b/bld/namelist_files/use_cases/glacierMEC_pd.xml deleted file mode 100644 index 214edc8df9..0000000000 --- a/bld/namelist_files/use_cases/glacierMEC_pd.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - -Running an IG case with the ice sheet model glimmer - -10 - - diff --git a/bld/namelist_files/use_cases/stdurbpt_pd.xml b/bld/namelist_files/use_cases/stdurbpt_pd.xml index 90301b890d..9114742e66 100644 --- a/bld/namelist_files/use_cases/stdurbpt_pd.xml +++ b/bld/namelist_files/use_cases/stdurbpt_pd.xml @@ -18,4 +18,8 @@ 'OFF' +.true. +.false. +.false. + diff --git a/bld/queryDefaultNamelist.pl b/bld/queryDefaultNamelist.pl index a0c0a0ce1a..97cd3d4394 100755 --- a/bld/queryDefaultNamelist.pl +++ b/bld/queryDefaultNamelist.pl @@ -60,7 +60,7 @@ sub usage { OPTIONS -config "file" CLM build configuration file created by configure. -cesm CESM mode set csmdata to \$DIN_LOC_ROOT. - -usrname "name" Dataset resolution/descriptor for personal datasets. + -usrname "name" Dataset resolution/descriptor for personal datasets. Default : not used Example: 1x1pt_boulderCO to describe location, number of pts @@ -107,13 +107,13 @@ sub usage { #----------------------------------------------------------------------------------------------- - my %opts = ( + my %opts = ( namelist => $namelist, model => "clm4_5", var => undef, hgrid => undef, config => undef, - cesm => undef, + cesm => undef, csmdata => undef, demand => undef, test => undef, @@ -179,14 +179,9 @@ sub usage { # List of input options my %inputopts; # This namelist files under the cime directories are in version 2 format and can't be read by perl code EBK 11/15/2016 - my $datmcimedir = "$cfgdir/../../../cime/components/data_comps/datm/cime_config"; - my $drvcimedir = "$cfgdir/../../../cime/driver_cpl/cime_config"; - my $drvblddir = "$cfgdir/../../../cime/driver_cpl/bld"; my $model = $opts{'model'}; - my @nl_definition_files = ( #"$datmcimedir/namelist_definition_datm.xml", # can't be read by perl see above - "$drvblddir/namelist_files/namelist_definition_drv.xml", - #"$drvcimedir/namelist_definition_drv.xml", # can't be read by perl see above - "$cfgdir/namelist_files/namelist_definition_$model.xml" + my @nl_definition_files = ("$cfgdir/namelist_files/namelist_definition_drv.xml", + "$cfgdir/namelist_files/namelist_definition_$model.xml" ); $inputopts{empty_cfg_file} = "$cfgdir/config_files/config_definition_$model.xml"; $inputopts{nldef_files} = \@nl_definition_files; @@ -252,12 +247,10 @@ sub usage { $settings{'notest'} = ! $opts{'test'}; $settings{'csmdata'} = $inputopts{csmdata}; } else { - my @files = ( "$cfgdir/namelist_files/namelist_defaults_${model}.xml", - "$cfgdir/namelist_files/namelist_defaults_${model}_tools.xml", - "$drvblddir/namelist_files/namelist_defaults_drv.xml", - #"$drvcimedir/namelist_defaults_drv.xml", + my @files = ( "$cfgdir/namelist_files/namelist_defaults_${model}.xml", + "$cfgdir/namelist_files/namelist_defaults_${model}_tools.xml", + "$cfgdir/namelist_files/namelist_defaults_drv.xml", "$cfgdir/namelist_files/namelist_defaults_drydep.xml", - #"$datmcimedir/namelist_defaults_datm.xml", ); push( @nl_defaults_files, @files ); } diff --git a/bld/test_build_namelist/t/input/namelist_defaults_clm4_5_test.xml b/bld/test_build_namelist/t/input/namelist_defaults_clm4_5_test.xml index dc58f1fa46..17dae65eeb 100644 --- a/bld/test_build_namelist/t/input/namelist_defaults_clm4_5_test.xml +++ b/bld/test_build_namelist/t/input/namelist_defaults_clm4_5_test.xml @@ -61,7 +61,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). OFF .false. -.true. .false. @@ -74,17 +73,18 @@ attributes from the config_cache.xml file (with keys converted to upper-case). for the CLM2 data in the CESM distribution --> lnd/clm2/paramdata/clm_params.c130821.nc +lnd/clm2/paramdata/fates_params.c170331.nc - + -.true. -.true. -.true. -.false. -.false. +.true. +.true. +.true. +.false. +.false. @@ -247,9 +245,6 @@ lnd/clm2/surfdata_map/surfdata_1.9x2.5_simyr1850_c130927.nc lnd/clm2/surfdata_map/surfdata_10x15_simyr1850_c130927.nc - -lnd/clm2/surfdata_map/surfdata_1x1_tropicAtl_simyr1850_c130927.nc - lnd/clm2/surfdata_map/surfdata_ne30np4_simyr1850_c130927.nc @@ -270,9 +265,6 @@ lnd/clm2/surfdata_map/surfdata_ne30np4_simyr1850_c130927.nc lnd/clm2/surfdata_map/surfdata.pftdyn_48x96_rcp8.5_simyr1850-2100_c130524.nc -lnd/clm2/surfdata_map/surfdata.pftdyn_1x1_tropicAtl_hist_simyr1850-2005_c130627.nc - lnd/clm2/surfdata_map/surfdata.pftdyn_ne30np4_rcp8.5_simyr1850-2100_c130524.nc @@ -382,7 +374,6 @@ lnd/clm2/surfdata_map/surfdata_ne30np4_simyr1850_c130927.nc nn nn nn -nn nn @@ -399,7 +390,6 @@ lnd/clm2/surfdata_map/surfdata_ne30np4_simyr1850_c130927.nc nn nn nn -nn nn @@ -437,7 +427,6 @@ lnd/clm2/surfdata_map/surfdata_ne30np4_simyr1850_c130927.nc nn nn nn -nn nn @@ -701,41 +690,6 @@ lnd/clm2/surfdata_map/surfdata_ne30np4_simyr1850_c130927.nc - - -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_AVHRR_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_MODIS_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.5x0.5_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_10x10min_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_MODIS_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_USGS_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_LandScan2004_to_1x1_tropicAtl_nomask_aave_da_c121114.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_IGBP-GSDP_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_ISRIC-WISE_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_5x5min_nomask_to_1x1_tropicAtl_nomask_aave_da_c120718.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_GLOBE-Gardner_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_3x3min_GLOBE-Gardner-mergeGIS_to_1x1_tropicAtl_nomask_aave_da_c120927.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_0.9x1.25_GRDC_to_1x1_tropicAtl_nomask_aave_da_c130309.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_360x720_cruncep_to_1x1_tropicAtl_nomask_aave_da_c130326.nc -lnd/clm2/mappingdata/maps/1x1_tropicAtl/map_1km-merge-10min_HYDRO1K-merge-nomask_to_1x1_tropicAtl_nomask_aave_da_c130403.nc - - - Default: .true. - Toggle to turn on the ED (ED = 'on' is EXPERIMENTAL NOT SUPPORTED!) - Toggle to turn on spit fire (only relevant if ED is being used). @@ -191,6 +191,11 @@ Full pathname datafile with plant function type (PFT) constants combined with constants for biogeochem modules + +Full pathname to fates parameter file + + Full pathname of surface data file. @@ -945,7 +950,7 @@ CLM run type. +"512x1024,360x720cru,128x256,64x128,48x96,32x64,8x16,94x192,0.23x0.31,0.9x1.25,1.9x2.5,2.5x3.33,4x5,10x15,5x5_amazon,1x1_camdenNJ,1x1_vancouverCAN,1x1_mexicocityMEX,1x1_asphaltjungleNJ,1x1_brazil,1x1_urbanc_alpha,1x1_numaIA,1x1_smallvilleIA,0.1x0.1,0.5x0.5,3x3min,5x5min,10x10min,0.33x0.33,ne4np4,ne16np4,ne30np4,ne60np4,ne120np4,ne240np4,1km-merge-10min"> Horizontal resolutions Note: 0.1x0.1, 0.5x0.5, 5x5min, 10x10min, 3x3min and 0.33x0.33 are only used for CLM tools @@ -1002,8 +1007,8 @@ Description of the use case selected. Command line arguement for turning on CN spinup mode. - + Command line arguement for biogeochemistry mode for CLM4.5 sp = Satellitte Phenology cn = Carbon Nitrogen model @@ -1144,13 +1149,25 @@ Enable C14 model -Flag to use the atmospheric time series of C14 concentrations from bomb fallout, rather than natural abundance C14 (nominally set as 10^-12 mol C14 / mol C) +Flag to use the atmospheric time series of C14 concentrations from bomb fallout and Seuss effect, rather than natural abundance C14 (nominally set as 10^-12 mol C14 / mol C) (EXPERIMENTAL and NOT tested) -Filename with time series of atmospheric Delta C14 data. variables in file are "time" and "atm_delta_c14". time variable is in format 1950.0, and time values must be monotonically increasing for interpolation, however spacing can be unequal. atm_delta_c14 variable has units of permil. +Filename with time series of atmospheric Delta C14 data. variables in file are "time" and "Delta14co2_in_air". time variable is in format: years since 1850-01-01 0:0:0.0 units are permil. +(EXPERIMENTAL and NOT tested) + + + +Flag to use the atmospheric time series of C13 concentrations from natural abundance and the Seuss Effect, rather than static values. +(EXPERIMENTAL and NOT tested) + + + +Filename with time series of atmospheric Delta C13 data, which use CMIP6 format. variables in file are "time" and "delta13co2_in_air". time variable is in format: years since 1850-01-01 0:0:0.0 units are permil (EXPERIMENTAL and NOT tested) diff --git a/bld/test_build_namelist/t/test_do_harvest.pm b/bld/test_build_namelist/t/test_do_harvest.pm index 09a417a610..f82e1d6023 100644 --- a/bld/test_build_namelist/t/test_do_harvest.pm +++ b/bld/test_build_namelist/t/test_do_harvest.pm @@ -47,8 +47,8 @@ sub setup : Test(setup => 1) { $self->{nl} = Build::Namelist->new(); isnt($self->{nl}, undef, (caller(0))[3] . " : empty namelist object created."); - # Set use_ed so that it doesn't conflict with do_harvest - $self->set_value('use_ed', '.false.'); + # Set use_fates so that it doesn't conflict with do_harvest + $self->set_value('use_fates', '.false.'); } sub teardown : Test(teardown) { @@ -162,7 +162,7 @@ sub test_do_harvest__default_ed : Tests { $self->set_transient; $self->set_cn_true; - $self->set_value('use_ed', '.true.'); + $self->set_value('use_fates', '.true.'); $self->setup_logic_do_harvest; my $result = $self->get_do_harvest; diff --git a/bld/test_build_namelist/t/test_do_transient_crops.pm b/bld/test_build_namelist/t/test_do_transient_crops.pm index 1dcad39af5..19f85fca28 100644 --- a/bld/test_build_namelist/t/test_do_transient_crops.pm +++ b/bld/test_build_namelist/t/test_do_transient_crops.pm @@ -47,8 +47,8 @@ sub setup : Test(setup => 1) { $self->{nl} = Build::Namelist->new(); isnt($self->{nl}, undef, (caller(0))[3] . " : empty namelist object created."); - # Set use_ed so that it doesn't conflict with do_transient_crops - $self->set_value('use_ed', '.false.'); + # Set use_fates so that it doesn't conflict with do_transient_crops + $self->set_value('use_fates', '.false.'); } sub teardown : Test(teardown) { diff --git a/bld/test_build_namelist/t/test_do_transient_pfts.pm b/bld/test_build_namelist/t/test_do_transient_pfts.pm index cadcee5019..b2ac27fe6e 100644 --- a/bld/test_build_namelist/t/test_do_transient_pfts.pm +++ b/bld/test_build_namelist/t/test_do_transient_pfts.pm @@ -47,9 +47,9 @@ sub setup : Test(setup => 1) { $self->{nl} = Build::Namelist->new(); isnt($self->{nl}, undef, (caller(0))[3] . " : empty namelist object created."); - # Set use_cndv and use_ed so that they don't conflict with do_transient_pfts + # Set use_cndv and use_fates so that they don't conflict with do_transient_pfts $self->set_value('use_cndv', '.false.'); - $self->set_value('use_ed', '.false.'); + $self->set_value('use_fates', '.false.'); } sub teardown : Test(teardown) { @@ -143,7 +143,7 @@ sub test_do_transient_pfts__default_ed : Tests { my $msg = "Test default value for do_transient_pfts in an ED case.\n"; $self->set_transient; - $self->set_value('use_ed', '.true.'); + $self->set_value('use_fates', '.true.'); $self->setup_logic_do_transient_pfts; my $result = $self->get_do_transient_pfts; is($result, undef) || diag($msg); diff --git a/bld/test_build_namelist/t/test_ed_mode.pm b/bld/test_build_namelist/t/test_fates_mode.pm similarity index 54% rename from bld/test_build_namelist/t/test_ed_mode.pm rename to bld/test_build_namelist/t/test_fates_mode.pm index 6a49828372..2d832679cc 100644 --- a/bld/test_build_namelist/t/test_ed_mode.pm +++ b/bld/test_build_namelist/t/test_fates_mode.pm @@ -1,6 +1,6 @@ -package test_ed_mode; +package test_fates_mode; -# Unit tests for function: ed_mode +# Unit tests for function: fates_mode use Data::Dumper; use Test::More; @@ -8,8 +8,8 @@ use Test::Exception; use parent qw(Test::Class); -use CLMBuildNamelist qw(setup_cmdl_ed_mode); -use CLMBuildNamelist qw(setup_logic_ed); +use CLMBuildNamelist qw(setup_cmdl_fates_mode); +use CLMBuildNamelist qw(setup_logic_fates); #------------------------------------------------------------------------------- @@ -72,19 +72,19 @@ sub set_value { # #------------------------------------------------------------------------------- -# Test 1: use_century_decomp is default with ed_mode -sub test_ed_mode__use_century_decomp : Tests { +# Test 1: use_century_decomp is default with fates_mode +sub test_fates_mode__use_century_decomp : Tests { my $self = shift; - my $msg = "Test that use_century_decomp is the default on ed_mode.\n"; + my $msg = "Test that use_century_decomp is the default on fates_mode.\n"; - my $opts = { bgc => "ed" }; - my $nl_flags = { crop => "off"}; # the setup_cmdl_ed_mode code requires this logic + my $opts = { bgc => "fates" }; + my $nl_flags = { crop => "off"}; # the setup_cmdl_fates_mode code requires this logic # include bgc because they have mutually exclusive functionality that needs to be tested CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); my $group = $self->{definition}->get_group_name("use_century_decomp"); my $result = $self->{nl}->get_variable_value($group, "use_century_decomp"); @@ -92,149 +92,149 @@ sub test_ed_mode__use_century_decomp : Tests { } -# Test 2: use_vertsoilc is default with ed_mode -sub test_ed_mode__use_vertsoilc : Tests { +# Test 2: use_vertsoilc is default with fates_mode +sub test_fates_mode__use_vertsoilc : Tests { my $self = shift; - my $msg = "Tests that use_vertsoilc is default on ed_mode.\n"; + my $msg = "Tests that use_vertsoilc is default on fates_mode.\n"; - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); my $group = $self->{definition}->get_group_name("use_vertsoilc"); my $result = $self->{nl}->get_variable_value($group, "use_vertsoilc"); is($result, '.true.' ) || diag($msg); } -# Test 3: use_ed_spit_fire is default with ed_mode -sub test_ed_mode__use_ed_spit_fire : Tests { +# Test 3: use_fates_spitfire is default with fates_mode +sub test_fates_mode__use_fates_spitfire : Tests { my $self = shift; - my $msg = "Tests that use_ed_spit_fire is default on ed_mode.\n"; + my $msg = "Tests that use_fates_spitfire is default on fates_mode.\n"; - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - my $group = $self->{definition}->get_group_name("use_ed_spit_fire"); - my $result = $self->{nl}->get_variable_value($group, "use_ed_spit_fire"); + my $group = $self->{definition}->get_group_name("use_fates_spitfire"); + my $result = $self->{nl}->get_variable_value($group, "use_fates_spitfire"); is($result, '.true.' ) || diag($msg); } -# Test 4: use_nitrif_denitrif is not default with ed_mode -sub test_ed_mode__use_nitrif_denitrif: Tests { +# Test 4: use_nitrif_denitrif is not default with fates_mode +sub test_fates_mode__use_nitrif_denitrif: Tests { my $self = shift; - my $msg = "Tests that us_nitrif_denitfif e i nots default on ed_mode.\n"; + my $msg = "Tests that us_nitrif_denitfif e i nots default on fates_mode.\n"; - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); my $group = $self->{definition}->get_group_name("use_nitrif_denitrif"); my $result = $self->{nl}->get_variable_value($group, "use_nitrif_denitrif"); is($result, '.false.' ) || diag($msg); } -# Test 5: use_lch4 is not default with ed_mode -sub test_ed_mode__use_lch4: Tests { +# Test 5: use_lch4 is not default with fates_mode +sub test_fates_mode__use_lch4: Tests { my $self = shift; - my $msg = "Tests that use_lch4 is not default on ed_mode.\n"; + my $msg = "Tests that use_lch4 is not default on fates_mode.\n"; - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); my $group = $self->{definition}->get_group_name("use_lch4"); my $result = $self->{nl}->get_variable_value($group, "use_lch4"); is($result, '.false.' ) || diag($msg); } -# Test 6: use_ed=false will crash on ed_mode -sub test_ed_mode__use_ed_nl_contradicts_cmdl : Tests { +# Test 6: use_fates=false will crash on fates_mode +sub test_fates_mode__use_fates_nl_contradicts_cmdl : Tests { my $self = shift; - my $msg = "Tests that use_ed=false will fail on ed_mode.\n"; + my $msg = "Tests that use_fates=false will fail on fates_mode.\n"; my $opts = { }; - my $nl_flags = { crop => "off", use_ed => ".false.", , bgc_mode => 'ed',}; + my $nl_flags = { crop => "off", use_fates => ".false.", , bgc_mode => 'fates',}; - my $group = $self->{definition}->get_group_name("use_ed"); - $self->{nl}->set_variable_value($group, "use_ed", '.false.' ); + my $group = $self->{definition}->get_group_name("use_fates"); + $self->{nl}->set_variable_value($group, "use_fates", '.false.' ); - dies_ok(sub { CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, + dies_ok(sub { CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}) }) || diag($msg); } -# Test 7: crop=on will crash on ed_mode -sub test_ed_mode__crop_on_nl_contradicts_cmdl : Tests { +# Test 7: crop=on will crash on fates_mode +sub test_fates_mode__crop_on_nl_contradicts_cmdl : Tests { my $self = shift; - my $msg = "Tests that crop=on will fail on ed_mode.\n"; + my $msg = "Tests that crop=on will fail on fates_mode.\n"; my $opts = { }; - my $nl_flags = { crop => "on", bgc_mode => 'ed'}; + my $nl_flags = { crop => "on", bgc_mode => 'fates'}; my $group = $self->{definition}->get_group_name("crop"); $self->{nl}->set_variable_value($group, "crop", 'on' ); - dies_ok(sub { CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, + dies_ok(sub { CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}) }) || diag($msg); } -# Test 8: test that use_ed_spit_fire = false generates a false -sub test_ed_mode__use_ed_spit_fire_false : Tests { +# Test 8: test that use_fates_spitfire = false generates a false +sub test_fates_mode__use_fates_spitfire_false : Tests { my $self = shift; - my $msg = "Tests that use_ed_spit_fire can be turned to false.\n"; + my $msg = "Tests that use_fates_spitfire can be turned to false.\n"; - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; - my $group = $self->{definition}->get_group_name("use_ed_spit_fire"); - $self->{nl}->set_variable_value($group, "use_ed_spit_fire", '.false.' ); + my $group = $self->{definition}->get_group_name("use_fates_spitfire"); + $self->{nl}->set_variable_value($group, "use_fates_spitfire", '.false.' ); CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - my $result = $self->{nl}->get_variable_value($group, "use_ed_spit_fire"); + my $result = $self->{nl}->get_variable_value($group, "use_fates_spitfire"); is($result, '.false.' ) || diag($msg); } # Test 9: test that use_versoilc = false generates a false -sub test_ed_mode__use_vertsoilc_false : Tests { +sub test_fates_mode__use_vertsoilc_false : Tests { my $self = shift; my $msg = "Tests that use_vertsoilc can be turned to false.\n"; - use CLMBuildNamelist qw(setup_cmdl_ed_mode); - use CLMBuildNamelist qw(setup_logic_ed); + use CLMBuildNamelist qw(setup_cmdl_fates_mode); + use CLMBuildNamelist qw(setup_logic_fates); - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; my $group = $self->{definition}->get_group_name("use_vertsoilc"); $self->{nl}->set_variable_value($group, "use_vertsoilc", '.false.' ); CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); my $result = $self->{nl}->get_variable_value($group, "use_vertsoilc"); is($result, '.false.' ) || diag($msg); @@ -242,20 +242,20 @@ sub test_ed_mode__use_vertsoilc_false : Tests { } # Test 10: test that use_century_decomp = false generates a false -sub test_ed_mode__use_century_decomp_false : Tests { +sub test_fates_mode__use_century_decomp_false : Tests { my $self = shift; my $msg = "Tests that use_vertsoilc can be turned to false.\n"; - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; my $group = $self->{definition}->get_group_name("use_century_decomp"); $self->{nl}->set_variable_value($group, "use_century_decomp", '.false.' ); CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); my $result = $self->{nl}->get_variable_value($group, "use_century_decomp"); is($result, '.false.' ) || diag($msg); @@ -263,22 +263,22 @@ sub test_ed_mode__use_century_decomp_false : Tests { } # Test 11: test that use_lch4 = true generates a true -sub test_ed_mode__use_lch4_true : Tests { +sub test_fates_mode__use_lch4_true : Tests { my $self = shift; my $msg = "Tests that use_vertsoilc can be turned to false.\n"; - my $opts = { bgc => "ed"}; + my $opts = { bgc => "fates"}; my $nl_flags = { crop => "off", }; my $group = $self->{definition}->get_group_name("use_lch4"); $self->{nl}->set_variable_value($group, "use_lch4", '.true.' ); CLMBuildNamelist::setup_cmdl_bgc($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{cfg},$self->{physv}); - CLMBuildNamelist::setup_cmdl_ed_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); - $nl_flags->{"use_ed"} = $self->{nl}->get_value("use_ed"); + CLMBuildNamelist::setup_cmdl_fates_mode($opts, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + $nl_flags->{"use_fates"} = $self->{nl}->get_value("use_fates"); - CLMBuildNamelist::setup_logic_ed($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); + CLMBuildNamelist::setup_logic_fates($self->{test_files}, $nl_flags, $self->{definition}, $self->{defaults}, $self->{nl}, $self->{physv}); my $result = $self->{nl}->get_variable_value($group, "use_lch4"); is($result, '.true.' ) || diag($msg); diff --git a/bld/unit_testers/NMLTest/CompFiles.pm b/bld/unit_testers/NMLTest/CompFiles.pm index 5a18a72d98..c29d1b24a9 100644 --- a/bld/unit_testers/NMLTest/CompFiles.pm +++ b/bld/unit_testers/NMLTest/CompFiles.pm @@ -57,7 +57,7 @@ sub checkfilesexist { my $confdir = $self->{'dir'}; foreach my $file ( @$filesref ) { my $exists = ( -f "$confdir/$file" ); - ok( $exists, "$file file exists" ); + ok( $exists, "$type $mode: $file file exists" ); if ( $exists ) { $self->dodiffonfile( $file, $type, $mode ); } else { diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index ae8c9a1acc..b0d3fb2203 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -123,9 +123,9 @@ sub make_env_run { # # Figure out number of tests that will run # -my $ntests = 742; +my $ntests = 840; if ( defined($opts{'compare'}) ) { - $ntests += 468; + $ntests += 525; } plan( tests=>$ntests ); @@ -144,12 +144,12 @@ sub make_env_run { print "ERROR: unrecognized arguments: @ARGV\n"; usage(); } -my $mode = "-phys clm4_0"; +my $mode = "-phys clm5_0"; system( "../configure -s $mode" ); my $DOMFILE = "$inputdata_rootdir/atm/datm7/domain.lnd.T31_gx3v7.090928.nc"; my $real_par_file = "user_nl_clm_real_parameters"; -my $bldnml = "../build-namelist -verbose -csmdata $inputdata_rootdir -lnd_frac $DOMFILE -no-note -output_reals $real_par_file"; +my $bldnml = "../build-namelist -verbose -csmdata $inputdata_rootdir -lnd_frac $DOMFILE -glc_nec 10 -no-note -output_reals $real_par_file"; if ( $opts{'test'} ) { $bldnml .= " -test"; } @@ -217,7 +217,7 @@ sub make_env_run { print "==================================================\n"; # Exercise a bunch of options -my $options = "-co2_ppmv 250 -glc_nec 10 -glc_present"; +my $options = "-co2_ppmv 250 "; $options .= " -res 0.9x1.25 -rcp 2.6 -envxml_dir ."; &make_env_run(); @@ -265,7 +265,7 @@ sub make_env_run { } &cleanup(); } -$mode = "-phys clm4_0"; +$mode = "-phys clm5_0"; system( "../configure -s $mode" ); print "\n==================================================\n"; @@ -274,9 +274,9 @@ sub make_env_run { # irrig, verbose, clm_demand, rcp, test, sim_year, use_case, l_ncpl my $startfile = "clmrun.clm2.r.1964-05-27-00000.nc"; -foreach my $options ( "-irrig .true. ", "-verbose", "-rcp 2.6", "-test", "-sim_year 1850", +foreach my $options ( "-namelist '&a irrigate=.true./'", "-verbose", "-rcp 2.6", "-test", "-sim_year 1850", "-use_case 1850_control", "-l_ncpl 1", - "-clm_start_type startup", + "-clm_start_type startup", "-namelist '&a irrigate=.false./' -crop -bgc bgc", "-envxml_dir . -infile myuser_nl_clm", ) { my $file = $startfile; @@ -309,11 +309,11 @@ sub make_env_run { $mode = "-phys clm5_0"; system( "../configure -s $mode" ); foreach my $options ( - "-bgc bgc -use_case 1850-2100_rcp2.6_transient", - "-bgc sp -use_case 1850-2100_rcp4.5_transient", - "-bgc bgc -use_case 1850-2100_rcp6_transient", - "-bgc ed -use_case 2000_control -no-megan", - "-bgc cn -use_case 1850-2100_rcp8.5_transient", + "-bgc bgc -use_case 1850-2100_rcp2.6_transient -namelist '&a start_ymd=20100101/'", + "-bgc sp -use_case 1850-2100_rcp4.5_transient -namelist '&a start_ymd=18501223/'", + "-bgc bgc -use_case 1850-2100_rcp6_transient -namelist '&a start_ymd=20701029/'", + "-bgc fates -use_case 2000_control -no-megan", + "-bgc cn -use_case 1850-2100_rcp8.5_transient -namelist '&a start_ymd=19201023/'", "-bgc bgc -use_case 2000_control -namelist \"&a fire_method='nofire'/\" -crop", ) { my $file = $startfile; @@ -350,6 +350,21 @@ sub make_env_run { GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"", }, + "clm_demand on finidat" =>{ options=>"-clm_demand finidat -envxml_dir .", + namelst=>"", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"", + }, + "blank IC file, not cold" =>{ options=>"-clm_start_type startup -envxml_dir .", + namelst=>"finidat=' '", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"", + }, + "startup without interp" =>{ options=>"-clm_start_type startup -envxml_dir . -bgc sp -sim_year 1850", + namelst=>"use_init_interp=.false., start_ymd=19200901", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, "l_ncpl is zero" =>{ options=>"-l_ncpl 0 -envxml_dir .", namelst=>"", GLC_TWO_WAY_COUPLING=>"FALSE", @@ -405,7 +420,7 @@ sub make_env_run { GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, - "baset_map without crop" =>{ options=>"-bgc bgc -envxml_dir .", + "baset_map without crop" =>{ options=>"-bgc bgc -envxml_dir .", namelst=>"baset_mapping='constant'", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm5_0", @@ -415,20 +430,25 @@ sub make_env_run { GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm5_0", }, - "irrigate=T without -irr op"=>{ options=>"-crop -bgc cn -envxml_dir .", - namelst=>"irrigate=.true.", + "-irrig with clm5_0" =>{ options=>"-bgc bgc -crop -irrig .true. -envxml_dir .", + namelst=>"", GLC_TWO_WAY_COUPLING=>"FALSE", - conopts=>"-phys clm4_5", + conopts=>"-phys clm5_0", }, - "irrigate=F with -irrg op" =>{ options=>"-crop -bgc cn -irrig .true. -envxml_dir .", - namelst=>"irrigate=.false.", + "-irrig with -crop" =>{ options=>"-irrig .true. -envxml_dir .", + namelst=>"", GLC_TWO_WAY_COUPLING=>"FALSE", - conopts=>"-phys clm4_5", + conopts=>"-phys clm4_0 -bgc cn -crop on", + }, + "-irrigate=T without -crop" =>{ options=>"-bgc cn -irrig .true. -envxml_dir .", + namelst=>"irrigate=.true.", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm4_5", }, - "-irrig without -crop" =>{ options=>"-bgc cn -irrig .true. -envxml_dir .", - namelst=>"", + "interp without finidat" =>{ options=>"-bgc sp -envxml_dir .", + namelst=>"use_init_interp=.true. finidat=' '", GLC_TWO_WAY_COUPLING=>"FALSE", - conopts=>"-phys clm4_5", + conopts=>"-phys clm5_0", }, "sp and c13" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_c13=.true.", @@ -440,20 +460,20 @@ sub make_env_run { GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, - "crop and c13" =>{ options=>"-crop -bgc bgc -envxml_dir .", - namelst=>"use_c13=.true.", + "bombspike no c14" =>{ options=>"-bgc bgc -envxml_dir .", + namelst=>"use_c14=.false. use_c14_bombspike=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", - conopts=>"-phys clm4_5", + conopts=>"-phys clm5_0", }, - "crop and c14" =>{ options=>"-crop -bgc cn -envxml_dir .", - namelst=>"use_c14=.true.", + "use c13 timeseries no cn" =>{ options=>"-bgc sp -envxml_dir .", + namelst=>"use_c13_timeseries=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, - "bombspike no c14" =>{ options=>"-bgc bgc -envxml_dir .", - namelst=>"use_c14=.false. use_c14_bombspike=.true.", + "use c13 timeseries no c13"=>{ options=>"-bgc bgc -envxml_dir .", + namelst=>"use_c13=.false. use_c13_timeseries=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", - conopts=>"-phys clm5_0", + conopts=>"-phys clm4_5", }, "bombspike no cn" =>{ options=>"-bgc sp -envxml_dir .", namelst=>"use_c14_bombspike=.true.", @@ -500,6 +520,11 @@ sub make_env_run { GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, + "finundated and not methane"=>{ options=>"-bgc cn -envxml_dir .", + namelst=>"use_lch4=.false.,finundation_method='h2osfc'", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, "bgc=bgc and cn-only set" =>{ options=>"-bgc bgc -envxml_dir .", namelst=>"use_lch4=.false.,use_nitrif_denitrif=.false.,use_vertsoilc=.false.,use_century_decomp=.false.", GLC_TWO_WAY_COUPLING=>"FALSE", @@ -515,6 +540,26 @@ sub make_env_run { GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, + "lower=aqu-45 with/o Zeng" =>{ options=>"-envxml_dir .", + namelst=>"lower_boundary_condition=4,soilwater_movement_method=1,use_bedrock=.false.", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, + "Zeng w lower=flux" =>{ options=>"-envxml_dir .", + namelst=>"lower_boundary_condition=1,soilwater_movement_method=0,use_bedrock=.false.", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm4_5", + }, + "Zeng w lower=zeroflux" =>{ options=>"-envxml_dir .", + namelst=>"lower_boundary_condition=2,soilwater_movement_method=0", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm4_5", + }, + "Zeng w lower=table" =>{ options=>"-envxml_dir .", + namelst=>"lower_boundary_condition=3,soilwater_movement_method=0,use_bedrock=.false.", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm4_5", + }, "vichydro without clm4_5" =>{ options=>"-vichydro -envxml_dir .", namelst=>"", GLC_TWO_WAY_COUPLING=>"FALSE", @@ -690,62 +735,67 @@ sub make_env_run { GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"", }, - "glc_nec inconsistent" =>{ options=>"-glc_nec 10 -glc_present -envxml_dir .", + "glc_nec inconsistent" =>{ options=>"-envxml_dir .", namelst=>"maxpatch_glcmec=5", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"", }, - "UpdateGlcNoGLCMec" =>{ options=>"-envxml_dir .", + "NoGLCMec" =>{ options=>"-envxml_dir . -glc_nec 0", namelst=>"", - GLC_TWO_WAY_COUPLING=>"TRUE", + GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, - "UpdateGlcContradict" =>{ options=>"-glc_nec 10 -glc_present -envxml_dir .", + "UpdateGlcContradict" =>{ options=>"-envxml_dir .", namelst=>"glc_do_dynglacier=.false.", GLC_TWO_WAY_COUPLING=>"TRUE", conopts=>"-phys clm4_5", }, - "clm40andUpdateGlc" =>{ options=>"-glc_nec 10 -glc_present -envxml_dir .", + "clm40andUpdateGlc" =>{ options=>"-envxml_dir .", namelst=>"", GLC_TWO_WAY_COUPLING=>"TRUE", conopts=>"-phys clm4_0", }, - "useEDContradict" =>{ options=>"-bgc ed -envxml_dir . -no-megan", - namelst=>"use_ed=.false.", + "useEDContradict" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"use_fates=.false.", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, "useEDContradict2" =>{ options=>"-envxml_dir . -no-megan", - namelst=>"use_ed=.true.", + namelst=>"use_fates=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, - "useEDWCN" =>{ options=>"-bgc ed -envxml_dir . -no-megan", + "useEDWCN" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_cn=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm5_0", }, - "useEDWTransient" =>{ options=>"-bgc ed -use_case 20thC_transient -envxml_dir . -no-megan -res 10x15", + "useEDWcreatecrop" =>{ options=>"-bgc fates -envxml_dir . -no-megan", + namelst=>"create_crop_landunit=.true.", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, + "useEDWTransient" =>{ options=>"-bgc fates -use_case 20thC_transient -envxml_dir . -no-megan -res 10x15", namelst=>"", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm5_0", }, - "useEDclm40" =>{ options=>"-bgc ed -envxml_dir . -no-megan", + "useEDclm40" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_0", }, "usespitfireButNOTED" =>{ options=>"-envxml_dir . -no-megan", - namelst=>"use_ed_spit_fire=.true.", + namelst=>"use_fates_spitfire=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, - "useMEGANwithED" =>{ options=>"-bgc ed -envxml_dir . -megan", + "useMEGANwithED" =>{ options=>"-bgc fates -envxml_dir . -megan", namelst=>"", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm4_5", }, - "useHYDSTwithED" =>{ options=>"-ed_mode -envxml_dir . -no-megan", + "useHYDSTwithED" =>{ options=>"-bgc fates -envxml_dir . -no-megan", namelst=>"use_hydrstress=.true.", GLC_TWO_WAY_COUPLING=>"FALSE", conopts=>"-phys clm5_0", @@ -862,6 +912,7 @@ sub make_env_run { }, ); foreach my $key ( keys(%failtest) ) { + print( "$key\n" ); system( "../configure -s ".$failtest{$key}{"conopts"}); my $options = $failtest{$key}{"options"}; my $namelist = $failtest{$key}{"namelst"}; @@ -871,12 +922,69 @@ sub make_env_run { system( "cat $tempfile" ); } + +print "\n===============================================================================\n"; +print "Start Warning testing. These should fail unless -ignore_warnings option is used \n"; +print "=================================================================================\n"; + +# Warning testing, do things that give warnings, unless -ignore_warnings option is used + +my %warntest = ( + # Warnings without the -ignore_warnings option given + "coldwfinidat" =>{ options=>"-envxml_dir . -clm_start_type cold", + namelst=>"finidat = 'testfile.nc'", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, + "bgcspin_w_suplnitro" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup on", + namelst=>"suplnitro='ALL'", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, + "use_c13_wo_bgc" =>{ options=>"-envxml_dir . -bgc cn", + namelst=>"use_c13=.true.", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, + "use_c14_wo_bgc" =>{ options=>"-envxml_dir . -bgc cndv", + namelst=>"use_c14=.true.", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, + "maxpft_wrong" =>{ options=>"-envxml_dir . -bgc cndv", + namelst=>"maxpatch_pft=19", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm5_0", + }, + "bad_megan_spec" =>{ options=>"-envxml_dir . -bgc bgc -megan", + namelst=>"megan_specifier='ZZTOP=zztop'", + GLC_TWO_WAY_COUPLING=>"FALSE", + conopts=>"-phys clm4_5", + }, + ); +foreach my $key ( keys(%warntest) ) { + print( "$key\n" ); + system( "../configure -s ".$warntest{$key}{"conopts"}); + my $options = $warntest{$key}{"options"}; + my $namelist = $warntest{$key}{"namelst"}; + &make_env_run( GLC_TWO_WAY_COUPLING=>$warntest{$key}{"GLC_TWO_WAY_COUPLING"} ); + eval{ system( "$bldnml $options -namelist \"&clmexp $namelist /\" > $tempfile 2>&1 " ); }; + isnt( $?, 0, $key ); + system( "cat $tempfile" ); + # Now run with -ignore_warnings and make sure it works + $options .= " -ignore_warnings"; + eval{ system( "$bldnml $options -namelist \"&clmexp $namelist /\" > $tempfile 2>&1 " ); }; + is( $@, '', "$options" ); + system( "cat $tempfile" ); +} + + print "\n==================================================\n"; -print "Test ALL resolutions with CLM4.0 and CN \n"; +print "Test ALL resolutions with CLM5.0 and SP \n"; print "==================================================\n"; -# Check for ALL resolutions with CN -$mode = "-bgc cn -phys clm4_0"; +# Check for ALL resolutions with CLM50SP +$mode = "-phys clm5_0"; system( "../configure -s $mode" ); my $reslist = `../queryDefaultNamelist.pl -res list -s`; my @resolutions = split( / /, $reslist ); @@ -884,14 +992,15 @@ sub make_env_run { foreach my $res ( @resolutions ) { chomp($res); print "=== Test $res === \n"; - my $options = "-res $res -envxml_dir ."; + my $options = "-res $res -bgc sp -envxml_dir ."; - if ( $res eq "512x1024" ) { - $options .= " -sim_year 1850"; - } elsif ( $res =~ /^([0-9]+x[0-9]+_[a-zA-Z]+)$/ ) { + # Regional single point resolutions + if ( $res =~ /^([0-9]+x[0-9]+_[a-zA-Z]+)$/ ) { push( @regional, $res ); next; + # Resolutions for mksurfdata mapping } elsif ( $res eq "0.5x0.5" || + $res eq "0.25x0.25" || $res eq "0.1x0.1" || $res eq "3x3min" || $res eq "5x5min" || @@ -900,6 +1009,18 @@ sub make_env_run { $res eq "0.33x0.33" || $res eq "1km-merge-10min" ) { next; + # Resolutions supported in clm40 but NOT clm45/clm50 + } elsif ( $res eq "ne240np4" || + $res eq "ne60np4" || + $res eq "ne4np4" || + $res eq "2.5x3.33" || + $res eq "0.23x0.31" || + $res eq "94x192" || + $res eq "8x16" || + $res eq "32x64" || + $res eq "128x256" || + $res eq "512x1024" ) { + next; } &make_env_run(); @@ -927,7 +1048,7 @@ sub make_env_run { $mode = "-phys clm4_5"; system( "../configure -s $mode" ); -my @resolutions = ( "10x15", "ne30np4", "ne120np4", "ne16np4", "0.125x0.125", "1.9x2.5", "0.9x1.25" ); +my @resolutions = ( "4x5", "10x15", "ne30np4", "ne120np4", "ne16np4", "1.9x2.5", "0.9x1.25" ); my @regional; my $nlbgcmode = "bgc"; my $mode = "clm45-$nlbgcmode"; @@ -1012,11 +1133,11 @@ sub make_env_run { print "==================================================\n"; # Check for crop resolutions -$mode = "-crop on -bgc cn -phys clm4_0"; +$mode = "-phys clm5_0"; system( "../configure -s $mode" ); -my @crop_res = ( "10x15", "1.9x2.5" ); +my @crop_res = ( "1x1_numaIA", "1x1_smallvilleIA", "4x5", "10x15", "0.9x1.25", "1.9x2.5", "ne30np4", "ne120np4" ); foreach my $res ( @crop_res ) { - $options = "-res $res -envxml_dir ."; + $options = "-bgc bgc -crop -res $res -envxml_dir ."; &make_env_run(); eval{ system( "$bldnml $options > $tempfile 2>&1 " ); }; is( $@, '', "$options" ); @@ -1037,21 +1158,30 @@ sub make_env_run { print "==================================================\n"; # Check for glc_mec resolutions -$mode = "-phys clm4_5 -bgc bgc"; +# +# NOTE(wjs, 2017-12-17) I'm not sure if these glc_mec-specific tests are +# still needed: are they covered with other tests now that we always run +# with glc_mec? Some historical notes: (1) The three resolutions listed +# here used to be the only three with which you could run glc_mec; now +# you can run glc_mec with all resolutions. (2) This used to point to +# all of the glacierMEC use cases; now we don't have glacierMEC-specific +# use cases, but I've kept these pointing to the equivalent normal use +# cases; I'm not sure if it's actually important to test this with all +# of the different use cases. +$mode = "-phys clm4_5"; system( "../configure -s $mode" ); my @glc_res = ( "48x96", "0.9x1.25", "1.9x2.5" ); -my @use_cases = ( "1850-2100_rcp2.6_glacierMEC_transient", - "1850-2100_rcp4.5_glacierMEC_transient", - "1850-2100_rcp6_glacierMEC_transient", - "1850-2100_rcp8.5_glacierMEC_transient", - "1850_glacierMEC_control", - "2000_glacierMEC_control", - "20thC_glacierMEC_transient", +my @use_cases = ( "1850-2100_rcp2.6_transient", + "1850-2100_rcp4.5_transient", + "1850-2100_rcp6_transient", + "1850-2100_rcp8.5_transient", + "1850_control", + "2000_control", + "20thC_transient", ); -my $GLC_NEC = 10; foreach my $res ( @glc_res ) { foreach my $usecase ( @usecases ) { - $options = "-glc_nec -glc_present $GLC_NEC -res $res -use_case $usecase -envxml_dir . "; + $options = "-bgc bgc -res $res -use_case $usecase -envxml_dir . "; &make_env_run(); eval{ system( "$bldnml $options > $tempfile 2>&1 " ); }; is( $@, '', "$options" ); @@ -1068,11 +1198,11 @@ sub make_env_run { } } # Transient 20th Century simulations -$mode = "-phys clm4_0"; +$mode = "-phys clm5_0"; system( "../configure -s $mode" ); -my @tran_res = ( "48x96", "0.9x1.25", "1.9x2.5", "ne30np4", "ne60np4", "ne120np4", "10x15", "1x1_tropicAtl" ); +my @tran_res = ( "48x96", "0.9x1.25", "1.9x2.5", "ne30np4", "ne120np4", "10x15" ); my $usecase = "20thC_transient"; -my $GLC_NEC = 0; +my $GLC_NEC = 10; foreach my $res ( @tran_res ) { $options = "-res $res -use_case $usecase -envxml_dir . "; &make_env_run(); @@ -1091,12 +1221,12 @@ sub make_env_run { &cleanup(); } # Transient rcp scenarios -$mode = "-phys clm4_0"; +$mode = "-phys clm5_0"; system( "../configure -s $mode" ); my @tran_res = ( "48x96", "0.9x1.25", "1.9x2.5", "ne30np4", "10x15" ); foreach my $usecase ( "1850-2100_rcp2.6_transient", "1850-2100_rcp4.5_transient", "1850-2100_rcp6_transient", "1850-2100_rcp8.5_transient" ) { foreach my $res ( @tran_res ) { - $options = "-res $res -use_case $usecase -envxml_dir . "; + $options = "-res $res -bgc bgc -crop -use_case $usecase -envxml_dir . "; &make_env_run(); eval{ system( "$bldnml $options > $tempfile 2>&1 " ); }; is( $@, '', "$options" ); @@ -1121,10 +1251,32 @@ sub make_env_run { foreach my $phys ( "clm4_5", 'clm5_0' ) { my $mode = "-phys $phys"; system( "../configure -s $mode" ); - my @clmoptions = ( "-bgc bgc -envxml_dir .", "-bgc bgc -envxml_dir . -clm_accelerated_spinup=on", + my @clmoptions = ( "-bgc bgc -envxml_dir .", "-bgc bgc -envxml_dir . -clm_accelerated_spinup=on", "-bgc bgc -envxml_dir . -light_res 360x720", + "-bgc sp -envxml_dir . -vichydro", "-bgc bgc -dynamic_vegetation", "-bgc bgc -clm_demand flanduse_timeseries -sim_year 1850-2000", "-bgc bgc -envxml_dir . -namelist '&a use_c13=.true.,use_c14=.true.,use_c14_bombspike=.true./'" ); foreach my $clmopts ( @clmoptions ) { - my @clmres = ( "ne16np4", "ne120np4", "10x15", "48x96", "0.9x1.25", "1.9x2.5", "360x720cru" ); + my @clmres = ( "ne120np4", "10x15", "0.9x1.25", "1.9x2.5" ); + foreach my $res ( @clmres ) { + $options = "-res $res -envxml_dir . "; + &make_env_run( ); + eval{ system( "$bldnml $options $clmopts > $tempfile 2>&1 " ); }; + is( $@, '', "$options $clmopts" ); + $cfiles->checkfilesexist( "$options $clmopts", $mode ); + $cfiles->shownmldiff( "default", "standard" ); + if ( defined($opts{'compare'}) ) { + $cfiles->doNOTdodiffonfile( "$tempfile", "$options $clmopts", $mode ); + $cfiles->comparefiles( "$options $clmopts", $mode, $opts{'compare'} ); + } + if ( defined($opts{'generate'}) ) { + $cfiles->copyfiles( "$options $clmopts", $mode ); + } + &cleanup(); + } + } + my @clmoptions = ( "-bgc bgc -envxml_dir .", + "-bgc sp -envxml_dir .", ); + foreach my $clmopts ( @clmoptions ) { + my @clmres = ( "ne16np4", "360x720cru" ); foreach my $res ( @clmres ) { $options = "-res $res -envxml_dir . "; &make_env_run( ); @@ -1145,7 +1297,7 @@ sub make_env_run { system( "../configure -s $mode" ); my $clmopts = "-bgc cn -crop"; my $res = "1.9x2.5"; - $options = "-res $res -irrig .true. -crop -bgc cn -envxml_dir ."; + $options = "-res $res -namelist '&a irrigate=.true./' -crop -bgc cn -envxml_dir ."; &make_env_run(); eval{ system( "$bldnml $options $clmopts > $tempfile 2>&1 " ); }; is( $@, '', "$options $clmopts" ); @@ -1161,7 +1313,7 @@ sub make_env_run { &cleanup(); # Run ED mode for several resolutions and configurations system( "../configure -s $mode" ); - my $clmoptions = "-bgc ed -envxml_dir . -no-megan"; + my $clmoptions = "-bgc fates -envxml_dir . -no-megan"; my @clmres = ( "1x1_brazil", "5x5_amazon", "10x15", "1.9x2.5" ); foreach my $res ( @clmres ) { $options = "-res $res"; diff --git a/cime_config/SystemTests/lii.py b/cime_config/SystemTests/lii.py new file mode 100644 index 0000000000..0bf371ee9a --- /dev/null +++ b/cime_config/SystemTests/lii.py @@ -0,0 +1,56 @@ +""" +Implementation of the CIME LII test. + +This is a CLM specific test: +Verifies that interpolation of initial conditions onto an identical +configuration gives identical results: +(1) do a run with use_init_interp true (suffix base) +(2) do a run with use_init_interp false (suffix no_interp) + +It is more intuitive to think of the no_interp test as the "base". However, we +do the use_init_interp=true test first to facilitate updating initial conditions +whenever this is necessary, as documented below. + +The LII test needs to point to an initial conditions file that is compatible +with the given model configuration. Thus, the pointed-to initial conditions file +needs to be updated whenever surface datasets are changed, or the land-mask is +changed, or an imporant change is made to model physics (for example where new +fields are added to the restart file). The procedure for updating the initial +conditions files used by the LII test is as follows: + +(1) Run the LII test; the 'base' case should run to completion even if the +no_interp test fails. + +(2) Copy the finidat_interp_dest.nc file from the 'base' case to the inputdata +space. Rename this to be similar to the name of the file pointed to in this +test's user_nl_clm file, but with a new creation date. + +(3) Update this test's user_nl_clm file (in the appropriate testmods directory) +to point to the new finidat file. +""" + +from CIME.SystemTests.system_tests_compare_two import SystemTestsCompareTwo +from CIME.XML.standard_module_setup import * +from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files + +logger = logging.getLogger(__name__) + +class LII(SystemTestsCompareTwo): + + def __init__(self, case): + SystemTestsCompareTwo.__init__(self, case, + separate_builds = False, + run_two_suffix = 'no_interp', + run_one_description = 'use_init_interp set to true', + run_two_description = 'use_init_interp set to false') + + def _case_one_setup(self): + append_to_user_nl_files(caseroot = self._get_caseroot(), + component = "clm", + contents = "use_init_interp = .true.") + + def _case_two_setup(self): + append_to_user_nl_files(caseroot = self._get_caseroot(), + component = "clm", + contents = "use_init_interp = .false.") + diff --git a/cime_config/SystemTests/lvg.py b/cime_config/SystemTests/lvg.py new file mode 100644 index 0000000000..36fae196b2 --- /dev/null +++ b/cime_config/SystemTests/lvg.py @@ -0,0 +1,37 @@ +""" +Implementation of the CIME LVG (Land Virtual Glacier) test. + +This is a CLM specific test: +Verifies that adding virtual glacier columns doesn't change answers +(1) do a run with the standard set of virtual columns (suffix base) +(2) add virtual columns over Antarctica (suffix more_virtual) + +This will only pass if there are no column or patch-level outputs in CLM's +history files. +""" + +from CIME.SystemTests.system_tests_compare_two import SystemTestsCompareTwo +from CIME.XML.standard_module_setup import * +from CIME.SystemTests.test_utils.user_nl_utils import append_to_user_nl_files + +logger = logging.getLogger(__name__) + +class LVG(SystemTestsCompareTwo): + + def __init__(self, case): + SystemTestsCompareTwo.__init__(self, case, + separate_builds = False, + run_two_suffix = 'more_virtual', + run_one_description = 'standard set of virtual columns', + run_two_description = 'add virtual columns over Antarctica') + + def _case_one_setup(self): + append_to_user_nl_files(caseroot = self._get_caseroot(), + component = "clm", + contents = "glacier_region_behavior = 'single_at_atm_topo', 'virtual', 'virtual', 'multiple'") + + def _case_two_setup(self): + append_to_user_nl_files(caseroot = self._get_caseroot(), + component = "clm", + contents = "glacier_region_behavior = 'single_at_atm_topo', 'virtual', 'virtual', 'virtual'") + diff --git a/cime_config/SystemTests/ssp.py b/cime_config/SystemTests/ssp.py new file mode 100644 index 0000000000..444c2866bf --- /dev/null +++ b/cime_config/SystemTests/ssp.py @@ -0,0 +1,99 @@ +""" +Implementation of the CIME SSP test. This class inherits from SystemTestsCommon + +This is a CLM specific test: +Verifies that spinup works correctly +this test is only valid for CLM compsets with CLM45 or CLM50 +(1) do an initial spin test + - set CLM_ACCELERATED_SPINUP to on + - write restarts at the end of the run, turn on short term archiving + - turn MOSART off +(2) do a hybrid non-spinup simulation run + - start from the restart files generated in (1) + - turn MOSART off +""" +from CIME.XML.standard_module_setup import * +from CIME.SystemTests.system_tests_common import SystemTestsCommon +import shutil, glob, os + +logger = logging.getLogger(__name__) + +class SSP(SystemTestsCommon): + + def __init__(self, case): + """ + initialize an object interface to the SSP system test + """ + SystemTestsCommon.__init__(self, case) + rof = self._case.get_value("COMP_ROF") + expect(rof == "mosart", "ERROR: SSP test requires that ROF component be mosart") + + def run_phase(self): + caseroot = self._case.get_value("CASEROOT") + orig_case = self._case + orig_casevar = self._case.get_value("CASE") + + # clone the main case to create ref1 + clone_path = "{}.ref1".format(caseroot) + if os.path.exists(clone_path): + shutil.rmtree(clone_path) + clone = self._case.create_clone(clone_path, keepexe=True) + + # determine run lengths needed below + stop_nf = self._case.get_value("STOP_N") + stop_n1 = stop_nf / 2 + stop_n2 = stop_nf - stop_n1 + + #------------------------------------------------------------------- + # (1) do a spinup run in the main case in the cloned ref case + # (short term archiving is on) + #------------------------------------------------------------------- + os.chdir(clone_path) + self._set_active_case(clone) + + logger.info("startup: doing a {} {} 00000 seconds startup run".format(stop_n1, stop_nf)) + logger.info(" writing restarts at end of run") + logger.info(" short term archiving is on ") + + clone.set_value("CLM_ACCELERATED_SPINUP", "on") + clone.set_value("MOSART_MODE", "NULL") + clone.set_value("STOP_N",stop_n1) + clone.flush() + + dout_sr = clone.get_value("DOUT_S_ROOT") + # No history files expected, set suffix=None to avoid compare error + self.run_indv(suffix=None, st_archive=True) + + #------------------------------------------------------------------- + # (2) do a hybrid, non-spinup run in orig_case + #------------------------------------------------------------------- + os.chdir(caseroot) + self._set_active_case(orig_case) + + refdate = run_cmd_no_fail(r'ls -1dt {}/rest/*-00000* | head -1 | sed "s/-00000.*//" | sed "s/^.*rest\///"'.format(dout_sr)) + refsec = "00000" + + # obtain rpointer files and necessary restart files from short term archiving directory + rundir = self._case.get_value("RUNDIR") + + rest_path = os.path.join(dout_sr, "rest", "{}-{}".format(refdate, refsec)) + + for item in glob.glob("{}/*{}*".format(rest_path, refdate)): + os.symlink(item, os.path.join(rundir, os.path.basename(item))) + + for item in glob.glob("{}/*rpointer*".format(rest_path)): + shutil.copy(item, rundir) + + self._case.set_value("CLM_ACCELERATED_SPINUP", "off") + self._case.set_value("RUN_TYPE", "hybrid") + self._case.set_value("GET_REFCASE", False) + self._case.set_value("RUN_REFCASE", "{}.ref1".format(orig_casevar)) + self._case.set_value("MOSART_MODE", "NULL") + + self._case.set_value("RUN_REFDATE", refdate) + self._case.set_value("STOP_N", stop_n2) + self._case.set_value("DOUT_S", False) + self._case.flush() + + # do the restart run (short term archiving is off) + self.run_indv() diff --git a/cime_config/buildlib b/cime_config/buildlib index 754eb4ded0..105e3ce1b4 100755 --- a/cime_config/buildlib +++ b/cime_config/buildlib @@ -77,11 +77,11 @@ def _main_func(): os.path.join(srcroot,"components","clm","src","soilbiogeochem"), os.path.join(srcroot,"components","clm","src","dyn_subgrid"), os.path.join(srcroot,"components","clm","src","init_interp"), - os.path.join(srcroot,"components","clm","src","ED"), - os.path.join(srcroot,"components","clm","src","ED","main"), - os.path.join(srcroot,"components","clm","src","ED","biogeophys"), - os.path.join(srcroot,"components","clm","src","ED","biogeochem"), - os.path.join(srcroot,"components","clm","src","ED","fire"), + os.path.join(srcroot,"components","clm","src","fates"), + os.path.join(srcroot,"components","clm","src","fates","main"), + os.path.join(srcroot,"components","clm","src","fates","biogeophys"), + os.path.join(srcroot,"components","clm","src","fates","biogeochem"), + os.path.join(srcroot,"components","clm","src","fates","fire"), os.path.join(srcroot,"components","clm","src","utils"), os.path.join(srcroot,"components","clm","src","cpl")] with open(filepath_file, "w") as filepath: diff --git a/cime_config/buildnml b/cime_config/buildnml index a8e88de0d6..682510e07a 100755 --- a/cime_config/buildnml +++ b/cime_config/buildnml @@ -124,16 +124,22 @@ def buildnml(case, caseroot, compname): startfile_type = "finidat" start_type = "default" - if run_type == "startup": - if clm_force_coldstart == "on": - start_type = "cold" - else: - if run_type == "hybrid": - start_type = "startup" - else: - start_type = run_type + if run_type == "hybrid": + start_type = "startup" + elif run_type != "startup": + start_type = run_type + if run_type == "branch": startfile_type = "nrevsn" + if clm_force_coldstart == "on": + clm_force_coldstart = "off" + logger.warning( "WARNING: You've turned on CLM_FORCE_COLDSTART for a branch run_type, which is a contradiction, the coldstart will be ignored\n" + + " turn off CLM_FORCE_COLDSTART, or set RUN_TYPE=hybrid to get rid of this warning" + ) + + if (clm_force_coldstart == "on"): + logger.warning( "WARNING: CLM is starting up from a cold state" ) + start_type = "cold" if lnd_grid == 'T31': lnd_grid = '48x96' @@ -150,11 +156,6 @@ def buildnml(case, caseroot, compname): lnd_grid = clm_usrdat_name clmusr = " -clm_usr_name %s "%clm_usrdat_name - if comp_glc != "sglc": - glc_opts = "-glc_present" - else: - glc_opts = "" - if comp_atm != "datm": nomeg = "-no-megan" else: @@ -227,11 +228,11 @@ def buildnml(case, caseroot, compname): cmd = os.path.join(srcroot, "components","clm","bld","build-namelist") command = ("%s -infile %s -csmdata %s -inputdata %s %s -namelist \"&clm_inparm start_ymd=%s %s/ \" " - "%s %s %s -res %s %s -clm_start_type %s -envxml_dir %s -l_ncpl %s " + "%s %s -res %s %s -clm_start_type %s -envxml_dir %s -l_ncpl %s " "-lnd_frac %s -glc_nec %s -co2_ppmv %s -co2_type %s -config %s " "%s %s %s" %(cmd, infile, din_loc_root, inputdata_file, ignore, start_ymd, clm_namelist_opts, - nomeg, usecase, glc_opts, lnd_grid, clmusr, start_type, caseroot, lnd_ncpl, + nomeg, usecase, lnd_grid, clmusr, start_type, caseroot, lnd_ncpl, lndfrac_file, glc_nec, ccsm_co2_ppmv, clm_co2_type, config_cache_file, clm_bldnml_opts, spinup, tuning)) diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index bbc385a21c..15ccae73a4 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -2,7 +2,34 @@ - + + + + + + + clm4.0: + clm4.5: + clm5.0: + Satellite phenology: + CN: Carbon Nitrogen model + CNDV: CN with Dynamic Vegetation + CN with prognostic crop: + CNDV with prognostic crop: + + Satellite phenology with VIC hydrology: + BGC (vert. resol. CN and methane): + BGC (vert. resol. CN and methane) with prognostic crop: + FATES (Functionally Assembled Terrestrial Ecosystem Simulator) Ecosystem Demography model: (experimental) + BGC (vert. resol. CN and methane) with dynamic vegetation: + BGC (vert. resol. CN and methane) with dynamic vegetation and prognostic crop: + char @@ -34,6 +61,8 @@ clm4_0_default clm4_5_CRUNCEP clm5_0_cam5.5 + clm5_0_GSW3P + clm5_0_GSW3P clm5_0_cam5.5 @@ -66,31 +95,13 @@ 2000_control - 2000_control - 1850-2100_rcp4.5_transient - 1850-2100_rcp6_transient - 1850-2100_rcp8.5_transient - 1850-2100_rcp4.5_transient - 1850-2100_rcp6_transient - 1850-2100_rcp4.5_transient 1850_control 20thC_transient 1850-2100_rcp6_transient 1850-2100_rcp4.5_transient 1850-2100_rcp2.6_transient 1850-2100_rcp8.5_transient - 1850_glacierMEC_control - 2000_glacierMEC_control - 2000_glacierMEC_control - 20thC_glacierMEC_transient - 1850-2100_rcp8.5_glacierMEC_transient - 1850-2100_rcp6_glacierMEC_transient - 1850-2100_rcp4.5_glacierMEC_transient - 1850-2100_rcp2.6_glacierMEC_transient - 1850-2100_rcp4.5_glacierMEC_transient - 20thC_transient 20thC_transient - glacierMEC_pd 1850-2100_rcp4.5_transient run_component_clm @@ -107,23 +118,29 @@ char - -ignore_ic_year - -bgc sp - -bgc cn - -bgc bgc - -bgc cn -crop - -bgc bgc -crop - -bgc cn -dynamic_vegetation - -bgc bgc -dynamic_vegetation - -bgc cn -dynamic_vegetation -crop - -bgc bgc -dynamic_vegetation -crop - -bgc ed -no-megan - - -bgc sp - -bgc bgc - -bgc bgc -dynamic_vegetation - -bgc bgc -crop - -bgc bgc -dynamic_vegetation -crop + -bgc sp + -bgc cn + -bgc bgc + -bgc cn -crop + -bgc bgc -crop + -bgc cn -dynamic_vegetation + -bgc bgc -dynamic_vegetation + -bgc cn -dynamic_vegetation -crop + -bgc bgc -dynamic_vegetation -crop + -bgc sp -vichydro + -bgc fates -no-megan + + -bgc sp + -bgc bgc + -bgc bgc -dynamic_vegetation + -bgc bgc -crop + -bgc cn + -bgc cn -crop + -bgc cn -dynamic_vegetation + -bgc cn -dynamic_vegetation -crop + -bgc bgc -dynamic_vegetation -crop + -bgc sp -vichydro + -bgc fates -no-megan run_component_clm env_run.xml @@ -133,7 +150,6 @@ char constant,diagnostic,prognostic - 1 constant diagnostic @@ -202,29 +218,6 @@ precedence over any settings for finidat in the $CASEROOT/user_clm_clm file. - - clm4.0 physics: - clm4.0 Satellite phenology: - clm4.0 cn: - clm4.0 cndv: - clm4.0 prognostic crop: - clm4.5 physics: - clm4.5 Satellite phenology: - clm4.5 cn: - clm4.5 cn with dynamic vegetation: - clm4.5 bgc (cn and methane): - clm4.5 prognostic crop: - clm4.5 vic hydrology: - clm4.5 ED (Ecosystem Demography): (experimental) - clm4.5 bgc (cn and methane) with dynamic vegetation: - clm4.5 bgc (cn and methane) with dynamic vegetation and prognostic crop: - clm5.0 physics: - clm5.0 Satellite phenology: - clm5.0 bgc (cn and methane): - clm5.0 bgc with prognostic crop: - clm5.0 bgc (cn and methane) with dynamic vegetation and prognostic crop: - - ========================================= CLM naming conventions @@ -233,4 +226,4 @@ (in other words make sure there is NOT a underbar before the string afterwards) - + diff --git a/cime_config/config_compsets.xml b/cime_config/config_compsets.xml index c7acf00de6..c98bf7b72b 100644 --- a/cime_config/config_compsets.xml +++ b/cime_config/config_compsets.xml @@ -1,6 +1,6 @@ - + ========================================= @@ -18,7 +18,7 @@ ICE = [CICE, DICE, SICE] OCN = [DOCN, ,AQUAP, SOCN] ROF = [RTM, SROF] - GLC = [CISM1, CISM2, SGLC] + GLC = [CISM1, CISM2] WAV = [SWAV] BGC = optional BGC scenario @@ -31,406 +31,260 @@ Each compset node is associated with the following elements - lname - alias - - support (optional description of the support level for this compset) - Each compset node can also have the following attributes - - grid (optional regular expression match for grid to work with the compset) + - science_support (if this compset is supported scientifically with control simulations) - + - I1PT - 2000_DATM%1PT_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV + I1PtClm50SpGs + 2000_DATM%1PT_CLM50%SP_SICE_SOCN_MOSART_SGLC_SWAV + - I1PTCLM45 + I1PtClm45SpGs 2000_DATM%1PT_CLM45%SP_SICE_SOCN_RTM_SGLC_SWAV - - I1PTCLM50 - 2000_DATM%1PT_CLM50%SP_SICE_SOCN_RTM_SGLC_SWAV - - + - ITEST - 2003_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV_TEST - - - ICNTEST - 2003_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV_TEST - - - ICLM45CNTEST - 2003_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_SGLC_SWAV_TEST - - - I1850 - 1850_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV - - - I1850CLM45 - 1850_DATM%QIA_CLM45%SP_SICE_SOCN_RTM_SGLC_SWAV - - - I - 2000_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV - - - ICLM45 - 2000_DATM%QIA_CLM45%SP_SICE_SOCN_RTM_SGLC_SWAV - - - I4804 - 4804_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV - - - I4804CLM45 - 4804_DATM%QIA_CLM45%SP_SICE_SOCN_RTM_SGLC_SWAV - - - IHIST - HIST_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV - - - IHISTCLM45 - HIST_DATM%QIA_CLM45%SP_SICE_SOCN_RTM_SGLC_SWAV - - - ICN - 2000_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - I1850CN - 1850_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - I1850CLM45CN - 1850_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_SGLC_SWAV - - - I1850CLM45ED - 1850_DATM%QIA_CLM45%ED_SICE_SOCN_RTM_SGLC_SWAV - "Experimental, under development" - - - I1850CLM45CNF - 1850_DATM%QIA_CLM45%CN_SICE_SOCN_RTM%FLOOD_SGLC_SWAV - - - IHISTCN - HIST_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP85CN - RCP8_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP85CLM45CN - RCP8_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP60CN - RCP6_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP60CLM45CN - RCP6_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP45CN - RCP4_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP26CN - RCP2_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP26CLM45CN - RCP2_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_SGLC_SWAV - - - ICNCROP - 2000_DATM%QIA_CLM40%CN-CROP_SICE_SOCN_RTM_SGLC_SWAV - - - ICLM45CNCROP - 2000_DATM%QIA_CLM45%CN-CROP_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP45CLM45BGC - RCP4_DATM%QIA_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV - - - IRCP85CLM45BGC - RCP8_DATM%QIA_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50Sp + 2000_DATM%GSWP3v1_CLM50%SP_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV - - - - ICRUCLM45 - 2000_DATM%CRU_CLM45_SICE_SOCN_RTM_SGLC_SWAV - - ICRUCN - 2000_DATM%CRU_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50BgcCru + 2000_DATM%CRUv7_CLM50%BGC_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + - I1850CRUCLM45CN - 1850_DATM%CRU_CLM45%CN_SICE_SOCN_RTM_SGLC_SWAV - - - I1850CRUCLM45BGCDV - 1850_DATM%CRU_CLM45%BGCDV_SICE_SOCN_RTM_SGLC_SWAV - - - ICRUCLM45BGCCROP - 2000_DATM%CRU_CLM45%BGC-CROP_SICE_SOCN_RTM_SGLC_SWAV - - - ICRUCLM45BGCTEST - 2003_DATM%CRU_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV_TEST - - - ICRUCLM45BGC - 2000_DATM%CRU_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV - - - I1850CRUCLM45BGC - 1850_DATM%CRU_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV - - - IHISTCRUCLM45BGC - HIST_DATM%CRU_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50BgcCropRtm + 2000_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - ICRUCLM50BGC - 2000_DATM%CRU_CLM50%BGC_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50BgcCrop + 2000_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + - ICRUCLM50BGCCROP - 2000_DATM%CRU_CLM50%BGC-CROP_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50Cn + 2000_DATM%GSWP3v1_CLM50%CN_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV - I1850CRUCLM50BGCCROP - 1850_DATM%CRU_CLM50%BGC-CROP_SICE_SOCN_RTM_SGLC_SWAV + I1850Clm50BgcCrop + 1850_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + + - IMCRUCLM50BGC - 2000_DATM%CRU_CLM50%BGC_SICE_SOCN_MOSART_SGLC_SWAV + I2000Clm50SpGs + 2000_DATM%GSWP3v1_CLM50%SP_SICE_SOCN_MOSART_SGLC_SWAV - - - - ICNDVCROP - 2000_DATM%QIA_CLM40%CNDV-CROP_SICE_SOCN_RTM_SGLC_SWAV - - - ICLM45CNDV - 2000_DATM%QIA_CLM45%CNDV_SICE_SOCN_RTM_SGLC_SWAV - - - ICLM45BGCDVCROP - 2000_DATM%QIA_CLM45%BGCDV-CROP_SICE_SOCN_RTM_SGLC_SWAV - + - ICLM50BGCDVCROP - 2000_DATM%CRU_CLM50%BGCDV-CROP_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50BgcCropGs + 2000_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_MOSART_SGLC_SWAV + - ICLM45VIC - 2000_DATM%QIA_CLM45%SP-VIC_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50BgcCruGs + 2000_DATM%CRUv7_CLM50%BGC_SICE_SOCN_MOSART_SGLC_SWAV + + - ICLM45BGC - 2000_DATM%QIA_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50SpRtmFl + 2000_DATM%GSWP3v1_CLM50%SP_SICE_SOCN_RTM%FLOOD_CISM2%NOEVOLVE_SWAV + - ICLM45ED - 2000_DATM%QIA_CLM45%ED_SICE_SOCN_RTM_SGLC_SWAV - Experimental, under development + I2000Clm50Fates + 2000_DATM%GSWP3v1_CLM50%FATES_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + + - I1850CLM45ED - 1850_DATM%QIA_CLM45%ED_SICE_SOCN_RTM_SGLC_SWAV - Experimental, under development + I2000Clm50FatesGs + 2000_DATM%GSWP3v1_CLM50%FATES_SICE_SOCN_MOSART_SGLC_SWAV + - I1850CLM45BGC - 1850_DATM%QIA_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV - + I1850Clm50Bgc + 1850_DATM%GSWP3v1_CLM50%BGC_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + + - ICLM45BGCCROP - 2000_DATM%QIA_CLM45%BGC-CROP_SICE_SOCN_RTM_SGLC_SWAV + IHistClm50BgcCrop + HIST_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + - ICLM45CRUBGC - 2000_DATM%CRU_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV + IHistClm50Bgc + HIST_DATM%GSWP3v1_CLM50%BGC_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + + - IHISTCLM45BGCCROP - HIST_DATM%QIA_CLM45%BGC-CROP_SICE_SOCN_RTM_SGLC_SWAV + IHistClm50BgcQianGs + HIST_DATM%QIA_CLM50%BGC_SICE_SOCN_MOSART_SGLC_SWAV + + - IHISTCLM50BGCCROP - HIST_DATM%CRU_CLM50%BGC-CROP_SICE_SOCN_RTM_SGLC_SWAV + IHistClm50BgcCropGs + HIST_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_MOSART_SGLC_SWAV + + - IHISTCLM45BGC - HIST_DATM%QIA_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50BgcDvCrop + 2000_DATM%GSWP3v1_CLM50%BGCDV-CROP_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV + + - IHISTCLM50BGC - HIST_DATM%CRU_CLM50%BGC_SICE_SOCN_RTM_SGLC_SWAV + I2000Clm50BgcDvCropQianGs + 2000_DATM%QIA_CLM50%BGCDV-CROP_SICE_SOCN_MOSART_SGLC_SWAV - + - I1850SPINUPCN - 1850_DATM%S1850_CLM40%CN_SICE_SOCN_RTM_SGLC_SWAV - - - I1850SPINUPCLM45BGC - 1850_DATM%S1850_CLM45%BGC_SICE_SOCN_RTM_SGLC_SWAV + I1850Clm50BgcSpinup + 1850_DATM%S1850_CLM50%BGC_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV - - - IG1850 - 1850_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_CISM2_SWAV - + - - IG1850CLM45 - 1850_DATM%QIA_CLM45%SP_SICE_SOCN_RTM_CISM2_SWAV + + I1850Clm45BgcCrop + 1850_DATM%GSWP3v1_CLM45%BGC-CROP_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IG - 2000_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_CISM2_SWAV + + + IHistClm45BgcCrop + HIST_DATM%GSWP3v1_CLM45%BGC-CROP_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IGCLM45 - 2000_DATM%QIA_CLM45%SP_SICE_SOCN_RTM_CISM2_SWAV + + + IHistClm45BgcCropQianGs + HIST_DATM%QIA_CLM45%BGC-CROP_SICE_SOCN_RTM_SGLC_SWAV - - IGHIST - HIST_DATM%QIA_CLM40%SP_SICE_SOCN_RTM_CISM2_SWAV + + I2000Clm45Sp + 2000_DATM%GSWP3v1_CLM45%SP_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IGHISTCLM45 - HIST_DATM%QIA_CLM45%SP_SICE_SOCN_RTM_CISM2_SWAV + + I2000Clm45BgcCrop + 2000_DATM%GSWP3v1_CLM45%BGC-CROP_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IGHISTCLM50 - HIST_DATM%CRU_CLM50%SP_SICE_SOCN_RTM_CISM2_SWAV + + I2000Clm45Fates + 2000_DATM%GSWP3v1_CLM45%FATES_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IGHISTCLM45CN - HIST_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_CISM2_SWAV + + + I2000Clm45FatesGs + 2000_DATM%GSWP3v1_CLM45%FATES_SICE_SOCN_RTM_SGLC_SWAV - - IGHISTCN - HIST_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_CISM2_SWAV + + I1850Clm45Cn + 1850_DATM%GSWP3v1_CLM45%CN_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IG1850CN - 1850_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_CISM2_SWAV + + I1850Clm45Bgc + 1850_DATM%GSWP3v1_CLM45%BGC_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IG1850CLM50 - 1850_DATM%QIA_CLM50%SP_SICE_SOCN_RTM_CISM2_SWAV + + I1850Clm45BgcCru + 1850_DATM%CRUv7_CLM45%BGC_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IGCN - 2000_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_CISM2_SWAV + + IHistClm45Bgc + HIST_DATM%GSWP3v1_CLM45%BGC_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IGCLM45BGC - 2000_DATM%QIA_CLM45%BGC_SICE_SOCN_RTM_CISM2_SWAV + + + I2000Clm50Vic + 2000_DATM%GSWP3v1_CLM50%SP-VIC_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - - IG1850CRUCLM50BGC - 1850_DATM%CRU_CLM50%BGC_SICE_SOCN_RTM_CISM2_SWAV + + I2000Clm45VicCru + 2000_DATM%CRUv7_CLM45%SP-VIC_SICE_SOCN_RTM_CISM2%NOEVOLVE_SWAV - - IG1850CRUCLM50BGCCROP - 1850_DATM%CRU_CLM50%BGC-CROP_SICE_SOCN_RTM_CISM2_SWAV - + - - IGM1850CRUCLM50BGCCROP - 1850_DATM%CRU_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2_SWAV + + I1850Clm50SpG + 1850_DATM%GSWP3v1_CLM50%SP_SICE_SOCN_MOSART_CISM2%EVOLVE_SWAV - - IGMHISTCRUCLM50BGCCROP - HIST_DATM%CRU_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2_SWAV + + IHistClm50SpG + HIST_DATM%GSWP3v1_CLM50%SP_SICE_SOCN_MOSART_CISM2%EVOLVE_SWAV - - IGM1850CRUCLM50BGC - 1850_DATM%CRU_CLM50%BGC_SICE_SOCN_MOSART_CISM2_SWAV + + I1850Clm50BgcCropG + 1850_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2%EVOLVE_SWAV - - IGRCP85CN - RCP8_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_CISM2_SWAV + + IHistClm50BgcCropG + HIST_DATM%GSWP3v1_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2%EVOLVE_SWAV - - IGRCP60CN - RCP6_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_CISM2_SWAV + + + I2000Clm40SpCruGs + 2000_DATM%CRU_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV - - IGRCP45CN - RCP4_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_CISM2_SWAV + + I1850Clm40SpCruGs + 2000_DATM%CRU_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV - - IGRCP26CN - RCP2_DATM%QIA_CLM40%CN_SICE_SOCN_RTM_CISM2_SWAV + + IHistClm40SpCruGs + 2000_DATM%CRU_CLM40%SP_SICE_SOCN_RTM_SGLC_SWAV - - IGRCP85CLM45CN - RCP8_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_CISM2_SWAV - - - IGRCP45CLM45CN - RCP4_DATM%QIA_CLM45%CN_SICE_SOCN_RTM_CISM2_SWAV - + + - 2005-01-01 1850-01-01 - 0001-01-01 1980-01-15 1997-12-31 1993-12-01 @@ -455,119 +309,6 @@ - - - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - hybrid - - - - - - I1850CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I1850CN_f19_g16_c100503 - I1850CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I1850CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f19_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I1850CN_f09_g16_c100503 - I1850CN_f09_g16_c100503 - I1850CLM40CRUCN_f09_g16_clm4500_c130514 - I1850CLM40CRUCN_f09_g16_clm4500_c130514 - I2000CN_f09_g16_c100503 - I1850CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - I2000CN_f09_g16_c100503 - - - - - - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 1122-01-01 - 1122-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - 0001-01-01 - - - - - - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - ccsm4_init - - - - diff --git a/cime_config/config_pes.xml b/cime_config/config_pes.xml index 47210cbae4..c68b181a04 100644 --- a/cime_config/config_pes.xml +++ b/cime_config/config_pes.xml @@ -77,6 +77,80 @@ + + + + none + + -1 + -9 + -9 + -9 + -9 + -9 + -9 + -9 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + + + + + + + + none + + -1 + -16 + -16 + -16 + -16 + -16 + -16 + -16 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + + + + @@ -151,6 +225,43 @@ + + + + none + + -1 + -50 + -50 + -50 + -50 + -50 + -50 + -50 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + + + + @@ -225,6 +336,43 @@ + + + + none + + -1 + -60 + -60 + -60 + -60 + -60 + -60 + -60 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + + + + @@ -597,5 +745,58 @@ + + + + none + + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + -1 + + + 1> + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + + + + + + 1 + + + 1 + + + + + diff --git a/cime_config/config_tests.xml b/cime_config/config_tests.xml new file mode 100644 index 0000000000..c829c8421f --- /dev/null +++ b/cime_config/config_tests.xml @@ -0,0 +1,58 @@ + + + + + + + + CLM initial condition interpolation test (requires configuration with non-blank finidat) + 1 + FALSE + FALSE + never + $STOP_OPTION + $STOP_N + + + + CLM test: Verify that adding virtual glacier columns doesn't change answers + 1 + FALSE + FALSE + never + + never + + + + smoke CLM spinup test (only valid for CLM45 or CLM50 compsets) + 1 + ndays + startup + 4 + FALSE + + + diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index bd0e52ca97..a065dba020 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -1,10 +1,15 @@ - FAIL RUN ERP_D_Ld5.f09_g16.ICLM45VIC.yellowstone_intel.clm-vrtlay_interp - FAIL RUN ERP_Ld5.f09_g16.ICLM45VIC.yellowstone_pgi.clm-vrtlay_interp - PEND RUN SMS_D_Ld1_P24x1.f10_f10.ICRUCLM45.hobart_nag.clm-af_bias_v5 - FAIL SMS_Lm25.f19_g16.ICLM45BGCCROP.yellowstone_gnu.clm-cropMonthOutput BASELINE - FAIL ERS_D_Ld5.f10_f10.ICLM45ED.hobart_nag.clm-edTest BASELINE - FAIL SMS_D_Ld5.f10_f10.ICLM45ED.hobart_nag.clm-edTest BASELINE + FAIL ERP_D_Lm9.f10_f10_musgs.IHistClm50BgcCrop.cheyenne_intel.clm-ciso_monthly RUN + FAIL SMS_D_Lm13.f10_f10_musgs.I1850Clm50BgcCrop.yellowstone_intel.clm-ciso_monthly RUN + FAIL SMS_D_Lm13.f10_f10_musgs.IHistClm50BgcCrop.yellowstone_intel.clm-ciso_monthly RUN + FAIL NCK_Ld1.f10_f10_musgs.I2000Clm50Sp.cheyenne_intel.clm-default COMPARE_base_multiinst + FAIL NCK_Ld1.f10_f10_musgs.I2000Clm50Sp.yellowstone_intel.clm-default COMPARE_base_multiinst + FAIL ERI_N2_Ld9.f19_g17.I2000Clm50BgcCrop.cheyenne_intel.clm-default RUN + FAIL SMS_Ld5_D_P24x1.f10_f10_musgs.IHistClm50Bgc.hobart_nag.clm-decStart RUN + FAIL ERP_D_P24x1.f10_f10_musgs.IHistClm50Bgc.hobart_nag.clm-decStart RUN + FAIL ERP_D.f10_f10_musgs.IHistClm50Bgc.yellowstone_gnu.clm-decStart RUN + FAIL ERS_Ly5_P72x1.f10_f10_musgs.IHistClm45BgcCrop.cheyenne_intel.clm-cropMonthOutput RUN + FAIL ERS_Lm20_Mmpi-serial.1x1_smallvilleIA.I2000Clm50BgcCropGs.yellowstone_pgi.clm-monthly RUN diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 57c8b1ce29..dba4c93085 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -1,1456 +1,1146 @@ - - - - null - - - - - hobart + + + + cheyenne + yellowstone - - - - yellowstone + + cheyenne + yellowstone - - yellowstone - yellowstone + + cheyenne + yellowstone - - - hobart - hobart - janus - yellowstone - yellowstone - yellowstone - - - yellowstone - yellowstone - yellowstone + cheyenne + yellowstone - - - - yellowstone - - - - - null - - - - - null + + + + yellowstone - - - null + + + + + cheyenne - - - - null + + cheyenne - - - - yellowstone + + hobart - - - - null + + yellowstone - - - null + + + + + yellowstone - - - - null + + cheyenne - - - null + + + + + yellowstone - - - null + + + hobart - - - - null + + + + yellowstone - - - hobart + + + cheyenne + yellowstone - - hobart - - - - - yellowstone - yellowstone - - - null + + cheyenne - - - + - yellowstone + yellowstone - hobart + hobart - yellowstone - yellowstone - yellowstone + cheyenne + yellowstone + yellowstone + yellowstone - hobart - hobart + hobart + hobart - yellowstone - yellowstone - - - yellowstone + yellowstone - yellowstone + yellowstone - + - yellowstone + cheyenne + yellowstone - yellowstone + cheyenne + yellowstone - hobart - yellowstone - yellowstone + hobart + yellowstone + yellowstone + + + + + cheyenne + yellowstone - + - - null + + cheyenne - + - yellowstone - yellowstone + ed - - hobart + + cheyenne - - - - - - hobart + + cheyenne - - - - - null + + + cheyenne + yellowstone - - hobart + + cheyenne - - - yellowstone + + + hobart - - yellowstone + + cheyenne + cheyenne + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone - - - - yellowstone + + cheyenne + cheyenne + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone - - - - edison - hopper + + cheyenne + yellowstone - - - - - - yellowstone + + yellowstone - - - - null + + cheyenne + cheyenne + ed + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone - - - - - null + + + cheyenne - - - - - yellowstone + + + cheyenne + yellowstone + + + cheyenne + yellowstone - - - - - null + + + hobart - - - - null + + + + cheyenne + yellowstone - - - - - janus - yellowstone - yellowstone - yellowstone + + + yellowstone - - hobart + + cheyenne + yellowstone + yellowstone + yellowstone - - - null + + + + + cheyenne + yellowstone + + - hobart + cheyenne + yellowstone + + + hobart - + - hobart + hobart hobart - - yellowstone + + cheyenne + yellowstone - - - - null + + cheyenne + yellowstone + + + cheyenne + yellowstone - yellowstone + cheyenne + yellowstone - hobart - yellowstone + hobart + yellowstone + yellowstone - yellowstone + yellowstone yellowstone - - - - yellowstone + + + + cheyenne + cheyenne + janus + yellowstone - - - yellowstone + + + cheyenne + yellowstone - - hobart + + cheyenne + yellowstone - - - - - - null + + cheyenne + yellowstone + + + cheyenne + yellowstone - - null + + edison + hobart + hobart + hopper + + + + + cheyenne + cheyenne + edison + hopper + janus + yellowstone + cheyenne + cheyenne + hobart + hobart + janus janus - yellowstone - yellowstone yellowstone - - - null + + + + + hobart - - - - null + + + + cheyenne + yellowstone - - - null + + + cheyenne + hobart + yellowstone - - - - - - null + + cheyenne + hobart + yellowstone + yellowstone + yellowstone - - - - null + + cheyenne + yellowstone + yellowstone - - - yellowstone + + + cheyenne + yellowstone + yellowstone - - - yellowstone + + + cheyenne + yellowstone + + + cheyenne + yellowstone - - - yellowstone + + + + + cheyenne + hobart + yellowstone - - - hobart + + + cheyenne + yellowstone - - yellowstone - yellowstone + + cheyenne + hobart + yellowstone - - - hobart - yellowstone - yellowstone - - - hobart - hobart - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone + + + + + yellowstone - - - - ed - yellowstone - yellowstone + + + + cheyenne + yellowstone - - yellowstone - yellowstone + + cheyenne + yellowstone - - yellowstone + + cheyenne + yellowstone - - - - yellowstone - yellowstone - yellowstone + + cheyenne - - hobart + + yellowstone - - yellowstone - yellowstone + + yellowstone - - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone + + cheyenne - - hobart - yellowstone - yellowstone + + cheyenne - - hobart + + cheyenne - - hobart + + hobart - - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone + + hobart + hobart - - hobart + + hobart + hobart - ed - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - - - - - yellowstone - - - yellowstone + yellowstone - - yellowstone + + hobart - - yellowstone - yellowstone + + cheyenne + yellowstone - - - yellowstone + + + cheyenne + yellowstone - - hobart + + yellowstone - - yellowstone + + + + cheyenne - + - - yellowstone + + yellowstone + + + cheyenne + yellowstone - - yellowstone + + hobart - - hobart + + cheyenne + yellowstone - - yellowstone + + yellowstone - - - yellowstone - - - yellowstone + + + + + cheyenne - - yellowstone + + + + + + cheyenne - - yellowstone - yellowstone - - - yellowstone + + + + cheyenne + yellowstone + yellowstone - - hobart + + cheyenne + yellowstone + yellowstone - - yellowstone + + cheyenne + yellowstone - - yellowstone + + + + cheyenne + yellowstone + yellowstone - - yellowstone + + hobart - - - - yellowstone + + cheyenne + cheyenne + yellowstone + yellowstone + yellowstone + yellowstone - - - - - - yellowstone + + cheyenne + yellowstone + yellowstone + yellowstone - - yellowstone + + cheyenne + cheyenne + yellowstone + yellowstone + yellowstone - - - - yellowstone + + hobart - - - - yellowstone + + cheyenne + cheyenne + cheyenne + cheyenne + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone + yellowstone - - - - - - yellowstone + + cheyenne + yellowstone - - - - - - yellowstone + + hobart + hobart + hobart + hobart - - - - - - ed - hobart - yellowstone - yellowstone - yellowstone + + cheyenne + cheyenne + yellowstone + yellowstone + yellowstone + yellowstone - - - ed - yellowstone + cheyenne + yellowstone - - ed - hobart - yellowstone - yellowstone + + cheyenne + cheyenne + cheyenne + cheyenne + cheyenne - - - - ed - yellowstone + + hobart - - - - ed - ed - hobart - yellowstone + + cheyenne + yellowstone + yellowstone + yellowstone - ed - hobart - yellowstone - yellowstone - yellowstone - - - ed - yellowstone - yellowstone + cheyenne + cheyenne + cheyenne - - - ed - - - ed - yellowstone - yellowstone + + + cheyenne + cheyenne + yellowstone + yellowstone + yellowstone - - - - ed - yellowstone + + cheyenne + yellowstone + yellowstone - - ed - yellowstone + + cheyenne + edison + hopper + janus - - ed + + cheyenne + yellowstone - - - + - yellowstone - - - yellowstone + yellowstone - - - yellowstone - - - yellowstone + + + cheyenne + yellowstone - - - - yellowstone + + cheyenne + yellowstone - - - - yellowstone + + + + yellowstone - - - - - - hobart + + cheyenne - - - yellowstone + + + yellowstone - + - - hobart - - - janus - yellowstone - yellowstone - yellowstone + + cheyenne + yellowstone - - yellowstone + + yellowstone - - - edison - eos - hopper - titan + + + + + cheyenne + yellowstone - - - - yellowstone + + hobart - - - yellowstone + + + yellowstone - - - - - - yellowstone + + cheyenne + yellowstone - - - - null + + + + cheyenne + yellowstone - - - - - yellowstone + + + cheyenne + hobart + yellowstone - - - - yellowstone - yellowstone + + cheyenne + hobart + yellowstone + yellowstone + yellowstone - - hobart + + cheyenne + yellowstone + yellowstone - - - null + + + cheyenne + yellowstone + yellowstone - - - - - edison - hopper - janus + + + cheyenne + yellowstone - - - - yellowstone + + cheyenne - - null + + yellowstone - - - - yellowstone + + + + cheyenne + hobart + yellowstone + yellowstone + yellowstone + + + + + cheyenne + yellowstone + + + cheyenne + hobart + yellowstone + yellowstone - - + + - yellowstone - yellowstone + cheyenne + yellowstone - hobart + hobart - - yellowstone - yellowstone - yellowstone + + + + hobart - yellowstone - - - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - - - yellowstone - - - hobart - hobart - hobart - hobart + cheyenne + yellowstone + yellowstone - - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - - - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - yellowstone - - - - - yellowstone - yellowstone - yellowstone + + hobart - - yellowstone - yellowstone + + cheyenne + yellowstone - - - yellowstone + + + cheyenne + yellowstone - - - - yellowstone - - - hobart - - - yellowstone - - - - - yellowstone - - - yellowstone - - - yellowstone + + + + cheyenne + cheyenne + hobart + hobart + yellowstone + yellowstone + yellowstone - - hobart + + cheyenne + hobart + yellowstone + yellowstone + yellowstone + yellowstone - - - - null + + + + hobart - - - - - - null + + yellowstone - - - - null - - - - - yellowstone + + + + cheyenne + yellowstone - - yellowstone + + yellowstone - - - - - yellowstone + + + cheyenne + yellowstone + + + yellowstone - - - - - yellowstone + + + cheyenne + yellowstone - - - - yellowstone + + + + ed + hobart - - - yellowstone + + + ed + hobart - - - - yellowstone + + ed + hobart - - - - - yellowstone + + + ed - - - yellowstone + + + ed + ed + hobart - - - - - - null + + ed + hobart - - - - - - yellowstone + + ed - - - - - null + + + ed - - - - null + + ed - - - - - null + + + ed - - - - - - null + + ed - - - - - yellowstone + + + ed - - - - null + + + + ed + hobart - - - - - yellowstone - yellowstone + + + ed + hobart - - - - - - null + + ed + hobart - - - - - null + + + ed - - - null + + + ed + ed + hobart - - - - - - null + + ed + hobart - - - - null + + ed - - - - - null + + + ed - - - - yellowstone + + ed - - - - - null + + + ed - - - - null + + ed - - - - - null + + + ed - + hobart - - - null - - - - - null + + + cheyenne + yellowstone - - - - null + + cheyenne + yellowstone - - - - null + + cheyenne + yellowstone - - - - null + + cheyenne + yellowstone - - - - null + + + + hobart + + + yellowstone - - - - hobart + + + + cheyenne - + - yellowstone + yellowstone - - - - yellowstone - - - - - yellowstone - - - yellowstone - - - yellowstone - - - + + - yellowstone - yellowstone - - - yellowstone + yellowstone + yellowstone - hobart + hobart - yellowstone - yellowstone + cheyenne + yellowstone + yellowstone - hobart - - - - - - - yellowstone - - - yellowstone - - - yellowstone - - - - - yellowstone - - - - - - - yellowstone - yellowstone - - - - - bluewaters - edison - eos - hopper - titan - - - - - null - - - - - - - null - - - - - - - yellowstone - - - - - - - null - - - - - - - null - - - - - null - - - - - hobart - - - - - null - - - - - null + hobart + hobart - - - null - - - - - - - hobart + + + yellowstone - - - yellowstone - yellowstone + cheyenne + yellowstone + yellowstone - - - - null - - - - - null + + + + cheyenne - - - - hobart - - - - - yellowstone + + cheyenne - - - - null + + cheyenne + yellowstone - - - - null + + yellowstone - - - - null + + + + cheyenne - - - - null - - - - - null - - - - - null - - - - - null - - - - - null + + + + cheyenne - - - - - null + + + cheyenne + yellowstone - - - - yellowstone + + yellowstone - - - - - - null + + yellowstone - - - - null - - - - - null - - - - - yellowstone - - - - - null - - - - - null + + + + cheyenne + yellowstone - - - - null - - - - - null - - - janus - yellowstone - yellowstone - yellowstone - - - - - edison - hobart - hobart - hopper - - - - - edison - hopper - janus - yellowstone - yellowstone - yellowstone - - - - - hobart - hobart - janus - janus + + + + cheyenne + yellowstone diff --git a/cime_config/testdefs/testmods_dirs/clm/40ptsRLA/shell_commands b/cime_config/testdefs/testmods_dirs/clm/40ptsRLA/shell_commands index db39aa0b54..48287a2998 100644 --- a/cime_config/testdefs/testmods_dirs/clm/40ptsRLA/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/40ptsRLA/shell_commands @@ -1 +1,2 @@ ./xmlchange PTS_LAT=42,PTS_LON=260 +./xmlchange --force CLM_FORCE_COLDSTART=on diff --git a/cime_config/testdefs/testmods_dirs/clm/40ptsRLB/shell_commands b/cime_config/testdefs/testmods_dirs/clm/40ptsRLB/shell_commands index 40722f2340..15fd1cced4 100644 --- a/cime_config/testdefs/testmods_dirs/clm/40ptsRLB/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/40ptsRLB/shell_commands @@ -1 +1,2 @@ ./xmlchange PTS_LAT=-5,PTS_LON=290 +./xmlchange --force CLM_FORCE_COLDSTART=on diff --git a/cime_config/testdefs/testmods_dirs/clm/40ptsROA/shell_commands b/cime_config/testdefs/testmods_dirs/clm/40ptsROA/shell_commands index ce89f9ce25..d5be09e860 100644 --- a/cime_config/testdefs/testmods_dirs/clm/40ptsROA/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/40ptsROA/shell_commands @@ -1 +1,2 @@ ./xmlchange PTS_LAT=30,PTS_LON=315 +./xmlchange --force CLM_FORCE_COLDSTART=on diff --git a/cime_config/testdefs/testmods_dirs/clm/USUMB/shell_commands b/cime_config/testdefs/testmods_dirs/clm/USUMB/shell_commands index cb73e24e21..446125abf9 100755 --- a/cime_config/testdefs/testmods_dirs/clm/USUMB/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/USUMB/shell_commands @@ -1,17 +1,19 @@ # shell commands to execute xmlchange commands written by PTCLMmkdata: -# ./PTCLMmkdata -s US-UMB -d /glade/p/cesmdata/cseg/inputdata --mydatadir /glade/p/cesmdata/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c160208 --phys=clm4_5 +# ./PTCLMmkdata --cesm_root ../../../.. -s US-UMB -d /glade/p/cesm/cseg/inputdata --mydatadir=/glade/p/cesm/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c171024 ./xmlchange CLM_USRDAT_NAME=1x1pt_US-UMB ./xmlchange DATM_CLMNCEP_YR_START=1999 ./xmlchange DATM_CLMNCEP_YR_END=2006 -./xmlchange CLM_BLDNML_OPTS='-mask navy' +# Comment this out if NINST_LND is greater than 1 (see: http://bugs.cgd.ucar.edu/show_bug.cgi?id=2521) ./xmlchange MPILIB=mpi-serial -./xmlchange ATM_DOMAIN_PATH='$DIN_LOC_ROOT/lnd/clm2/PTCLMmydatafiles.c160208/1x1pt_US-UMB' -./xmlchange LND_DOMAIN_PATH='$DIN_LOC_ROOT/lnd/clm2/PTCLMmydatafiles.c160208/1x1pt_US-UMB' -./xmlchange ATM_DOMAIN_FILE=domain.lnd.1x1pt_US-UMB_navy.160208.nc -./xmlchange LND_DOMAIN_FILE=domain.lnd.1x1pt_US-UMB_navy.160208.nc +./xmlchange ATM_DOMAIN_PATH=/glade/p/cesm/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c171024/1x1pt_US-UMB +./xmlchange LND_DOMAIN_PATH=/glade/p/cesm/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c171024/1x1pt_US-UMB +./xmlchange ATM_DOMAIN_FILE=domain.lnd.1x1pt_US-UMB_navy.171024.nc +./xmlchange LND_DOMAIN_FILE=domain.lnd.1x1pt_US-UMB_navy.171024.nc +./xmlchange --append CLM_BLDNML_OPTS='-mask navy -no-crop' ./xmlchange CALENDAR=GREGORIAN ./xmlchange DOUT_S=FALSE ./xmlchange ATM_NCPL=24 ./xmlchange RUN_STARTDATE=1999-01-01 ./xmlchange DATM_CLMNCEP_YR_ALIGN=1999 -./xmlchange DIN_LOC_ROOT_CLMFORC='$DIN_LOC_ROOT/lnd/clm2/PTCLMmydatafiles.c160208' +./xmlchange DIN_LOC_ROOT=/glade/p/cesm/cseg/inputdata +./xmlchange DIN_LOC_ROOT_CLMFORC=/glade/p/cesm/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c171024 diff --git a/cime_config/testdefs/testmods_dirs/clm/USUMB/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/USUMB/user_nl_clm index ceffc8a8aa..38ce400297 100644 --- a/cime_config/testdefs/testmods_dirs/clm/USUMB/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/USUMB/user_nl_clm @@ -1,5 +1,5 @@ ! user_nl_clm namelist options written by PTCLMmkdata: -! ./PTCLMmkdata -s US-UMB -d /glade/p/cesmdata/cseg/inputdata --mydatadir /glade/p/cesmdata/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c160208 --phys=clm4_5 - fsurdat = '$DIN_LOC_ROOT/lnd/clm2/PTCLMmydatafiles.c160208/1x1pt_US-UMB/surfdata_1x1pt_US-UMB_simyr2000_clm4_5_c160208.nc' +! ./PTCLMmkdata --cesm_root ../../../.. -s US-UMB -d /glade/p/cesm/cseg/inputdata --mydatadir=/glade/p/cesm/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c171024 + fsurdat = '/glade/p/cesm/cseg/inputdata/lnd/clm2/PTCLMmydatafiles.c171024/1x1pt_US-UMB/surfdata_1x1pt_US-UMB_16pfts_Irrig_CMIP6_simyr2000_c171024.nc' hist_nhtfrq = 0 hist_mfilt = 1200 diff --git a/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/shell_commands b/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/shell_commands deleted file mode 100644 index 5f4b42eb3c..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/shell_commands +++ /dev/null @@ -1 +0,0 @@ -./xmlchange DATM_MODE=CLMCRUNCEP_V5 diff --git a/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/shell_commands b/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/shell_commands new file mode 100644 index 0000000000..a78d32d227 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/shell_commands @@ -0,0 +1 @@ +./xmlchange DATM_MODE=CLMCRUNCEPv7 diff --git a/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/af_bias_v5/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/af_bias_v7/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/user_nl_datm b/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/user_nl_datm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/af_bias_v5/user_nl_datm rename to cime_config/testdefs/testmods_dirs/clm/af_bias_v7/user_nl_datm diff --git a/cime_config/testdefs/testmods_dirs/clm/allActive/shell_commands b/cime_config/testdefs/testmods_dirs/clm/allActive/shell_commands new file mode 100644 index 0000000000..d64ca2d377 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/allActive/shell_commands @@ -0,0 +1,13 @@ +#!/bin/bash +# This namelist tests turning all points to 'active'; the point of +# this is to make sure that all points in memory could conceivably +# become active in a dynamic landunit run without causing any +# trouble. This should be tested with a _D test. + +# Note that we don't necessarily expect this to work with an initial +# conditions file that wasn't itself generated with all_active = +# .true., so we set CLM_FORCE_COLDSTART=on for this + +./xmlchange CLM_BLDNML_OPTS="-fire_emis" --append +./xmlchange CLM_FORCE_COLDSTART="on" + diff --git a/cime_config/testdefs/testmods_dirs/clm/allActive/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/allActive/user_nl_clm index 8317963619..0f04ae0de7 100644 --- a/cime_config/testdefs/testmods_dirs/clm/allActive/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/allActive/user_nl_clm @@ -5,7 +5,6 @@ ! Note that we don't necessarily expect this to work with an initial ! conditions file that wasn't itself generated with all_active = -! .true., so we set finidat = ' ' for this test. +! .true., so we set CLM_FORCE_COLDSTART=on for this (in shell_commands) all_active = .true. -finidat = ' ' diff --git a/cime_config/testdefs/testmods_dirs/clm/ciso_bombspike1963/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/ciso_bombspike1963/user_nl_clm index 7497e1d2f0..37b7c1ac3d 100644 --- a/cime_config/testdefs/testmods_dirs/clm/ciso_bombspike1963/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/ciso_bombspike1963/user_nl_clm @@ -1,4 +1,5 @@ use_c14_bombspike=.true. +use_c13_timeseries = .true. ! This testmod is used in a long test, so change output frequency hist_nhtfrq = 0,-240 diff --git a/cime_config/testdefs/testmods_dirs/clm/ciso_rtmColdSSP/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/ciso_rtmColdSSP/include_user_mods new file mode 100644 index 0000000000..7cded6662d --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/ciso_rtmColdSSP/include_user_mods @@ -0,0 +1,2 @@ +../ciso +../rtmColdSSP diff --git a/cime_config/testdefs/testmods_dirs/clm/snowlayers_12/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/clm50CMIP6frc/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/snowlayers_12/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/clm50CMIP6frc/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50CMIP6frc/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm50CMIP6frc/user_nl_clm new file mode 100644 index 0000000000..588fa7d7a9 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/clm50CMIP6frc/user_nl_clm @@ -0,0 +1,3 @@ +ndep_varlist = 'NDEP_month' +ndep_taxmode = 'cycle' +stream_fldfilename_ndep = '$DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_hist_simyr1850_0.9x1.25_CMIP6alpha01_c170330.nc' diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50KSinkMOut/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm50KSinkMOut/user_nl_clm index 500c204e3b..b2a51bd5d5 100644 --- a/cime_config/testdefs/testmods_dirs/clm/clm50KSinkMOut/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/clm50KSinkMOut/user_nl_clm @@ -1,3 +1,2 @@ hist_nhtfrq = 0,-240 hist_mfilt = 1,1 - init_interp_fill_missing_with_natveg = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50KitchenSink/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm50KitchenSink/user_nl_clm index 708a765285..b99b882838 100644 --- a/cime_config/testdefs/testmods_dirs/clm/clm50KitchenSink/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/clm50KitchenSink/user_nl_clm @@ -1,9 +1,6 @@ -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IG1850CRUCLM50BGC.0481-01-01.1.9x2.5_g1v6_gl5_simyr1850_c160127.nc' limit_irrigation_if_rof_enabled = .false. leaf_mr_vcm = 0.015d00 use_bedrock = .true. -use_init_interp = .true. -use_hydrstress = .true. use_luna = .true. use_flexibleCN = .true. use_fun = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/shell_commands b/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/shell_commands deleted file mode 100755 index 0470d46a28..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/shell_commands +++ /dev/null @@ -1 +0,0 @@ -./xmlchange CLM_BLDNML_OPTS="-irrig .true." -append diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm index adb7e61f9d..44bf6a9457 100644 --- a/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm @@ -1,6 +1,6 @@ use_init_interp = .true. -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IGM1850GSWP3CLM50BGCCROPIRR.0031-01-01.1.9x2.5_g1v6_gl5_simyr1850_c170219.nc' -init_interp_fill_missing_with_natveg = .true. ! need this as IC file is glc_mec -use_hydrstress = .false. hist_fincl1 += 'QIRRIG_DEMAND' + +! Turn irrigation on +irrigate = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/cmip6/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/cmip6/include_user_mods new file mode 100644 index 0000000000..0caefd70b4 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/cmip6/include_user_mods @@ -0,0 +1 @@ +../../../../usermods_dirs/cmip6 diff --git a/cime_config/testdefs/testmods_dirs/clm/cropColdStart/shell_commands b/cime_config/testdefs/testmods_dirs/clm/cropColdStart/shell_commands new file mode 100755 index 0000000000..2a9f09bd75 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/cropColdStart/shell_commands @@ -0,0 +1 @@ +./xmlchange CLM_FORCE_COLDSTART="on" diff --git a/cime_config/testdefs/testmods_dirs/clm/cropColdStart/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/cropColdStart/user_nl_clm deleted file mode 100644 index 34d3453450..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/cropColdStart/user_nl_clm +++ /dev/null @@ -1,2 +0,0 @@ -finidat = ' ' - diff --git a/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm index 8cd96140ba..b2a51bd5d5 100644 --- a/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm @@ -1,4 +1,2 @@ hist_nhtfrq = 0,-240 hist_mfilt = 1,1 - use_dynroot = .true. - use_hydrstress = .false. diff --git a/cime_config/testdefs/testmods_dirs/clm/decStart/user_nl_cism b/cime_config/testdefs/testmods_dirs/clm/decStart/user_nl_cism new file mode 100644 index 0000000000..85f5789000 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/decStart/user_nl_cism @@ -0,0 +1,9 @@ +! The need for this is subtle. The problem is that this decStart testmod is used in short +! (multi-day) ERP tests, whose length is such that the end of the year occurs in the +! initial run but not in the restart run. Without setting history_option = 'coupler', this +! would mean that CISM outputs a history file in the initial run but not in the restart +! run, which causes the test to fail because the test system requires any component's +! final history file in one case to have a counterpart in the other case. Setting +! history_option = 'coupler' forces CISM to output a history file only at the end of the +! run. +history_option = 'coupler' diff --git a/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/README b/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/README index 00bff9ea72..102dd97840 100644 --- a/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/README +++ b/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/README @@ -1,8 +1,8 @@ This testmods directory was created for the sake of the smallville transient -test case. We need to use finidat = ' ' to avoid this error message: +test case. We need to use a cold-start to avoid this error message: ERROR : CLM build-namelist::CLMBuildNamelist::setup_logic_initial_conditions() : using ignore_ic_date is incompatable with crop! -Once the above problem is fixed, we should stop setting finidat = ' ' in this +Once the above problem is fixed, we should stop doing a coldstart in this testmods diff --git a/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/shell_commands b/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/shell_commands index 7ab0f1693f..006ef22a12 100755 --- a/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/shell_commands @@ -1 +1,2 @@ ./xmlchange RUN_STARTDATE=1851-12-30 +./xmlchange CLM_FORCE_COLDSTART="on" diff --git a/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/user_nl_clm deleted file mode 100644 index 708d7fe83a..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -finidat = ' ' diff --git a/cime_config/testdefs/testmods_dirs/clm/edNoFire/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/edNoFire/include_user_mods deleted file mode 100644 index 53cabb16d0..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/edNoFire/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../edTest diff --git a/cime_config/testdefs/testmods_dirs/clm/edNoFire/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/edNoFire/user_nl_clm deleted file mode 100644 index 05070adc21..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/edNoFire/user_nl_clm +++ /dev/null @@ -1,2 +0,0 @@ -use_ed_spit_fire = .false. - diff --git a/cime_config/testdefs/testmods_dirs/clm/edTest/shell_commands b/cime_config/testdefs/testmods_dirs/clm/fates/shell_commands old mode 100755 new mode 100644 similarity index 56% rename from cime_config/testdefs/testmods_dirs/clm/edTest/shell_commands rename to cime_config/testdefs/testmods_dirs/clm/fates/shell_commands index d81ed7dbc5..cbe7a32650 --- a/cime_config/testdefs/testmods_dirs/clm/edTest/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/fates/shell_commands @@ -1 +1,2 @@ ./xmlchange CLM_BLDNML_OPTS="-no-megan" --append +./xmlchange CLM_FORCE_COLDSTART="on" diff --git a/cime_config/testdefs/testmods_dirs/clm/edTest/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/fates/user_nl_clm similarity index 94% rename from cime_config/testdefs/testmods_dirs/clm/edTest/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/fates/user_nl_clm index 4480dd595b..4dab7ec39e 100644 --- a/cime_config/testdefs/testmods_dirs/clm/edTest/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/fates/user_nl_clm @@ -1,4 +1,3 @@ -finidat = '' hist_mfilt = 365 hist_nhtfrq = -24 hist_empty_htapes = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/fatesFire/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/fatesFire/include_user_mods new file mode 100644 index 0000000000..fb35ec8c90 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/fatesFire/include_user_mods @@ -0,0 +1 @@ +../fates diff --git a/cime_config/testdefs/testmods_dirs/clm/edNoFire/shell_commands b/cime_config/testdefs/testmods_dirs/clm/fatesFire/shell_commands similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/edNoFire/shell_commands rename to cime_config/testdefs/testmods_dirs/clm/fatesFire/shell_commands diff --git a/cime_config/testdefs/testmods_dirs/clm/fatesFire/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/fatesFire/user_nl_clm new file mode 100644 index 0000000000..e3a3b76d71 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/fatesFire/user_nl_clm @@ -0,0 +1,2 @@ +use_fates_spitfire = .true. + diff --git a/cime_config/testdefs/testmods_dirs/clm/glcMEC/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/glcMEC/user_nl_clm index 23452cfa65..0ba5e4892b 100644 --- a/cime_config/testdefs/testmods_dirs/clm/glcMEC/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/glcMEC/user_nl_clm @@ -2,6 +2,3 @@ hist_fincl1 += 'SNO_EXISTENCE', 'SNO_ABS', 'SNO_T:M', 'SNO_GS:X', 'QICE_FORC' ! similarly, add a glc-specific field to the second history tape hist_fincl2 += 'QICE' - -! Set max snow persistence to a small number so that smb from bare land can potentially be triggered - glc_snow_persistence_max_days = 2 diff --git a/cime_config/testdefs/testmods_dirs/clm/glcMEC_long/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/glcMEC_long/user_nl_clm index 16bce125d8..dd99ceba50 100644 --- a/cime_config/testdefs/testmods_dirs/clm/glcMEC_long/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/glcMEC_long/user_nl_clm @@ -1,6 +1,2 @@ hist_nhtfrq =0,0 hist_mfilt = 1,12 - -! Set max snow persistence to a small number so that smb from bare land can potentially be triggered -! (since this testmods directory is set up for long runs, use 1 year rather than just a couple of days) - glc_snow_persistence_max_days = 365 diff --git a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/README b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/README index fa8d685ddb..062dc84800 100644 --- a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/README +++ b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/README @@ -1,12 +1,27 @@ -This testmods directory allows testing glc_mec cases using (partially) spun-up -initial conditions. Once we have out-of-the-box initial conditions with glc_mec, -this will no longer be necessary. +This testmods directory is for running LII tests which compare the answers for a case where +initial condition interpolation is on (use_init_interp=T) to a case with it's off and ensures +they are exact. For the interpolated result to match uninterpolation, it needs to be a case that +essentially needs no interpolation so it's at the same resolution as the initial condition +file (finidat file). When surface datasets are changed, or the land-mask is changed, or an +imporant change is made to model physics (for example where new fields are added to the restart +file) -- you'll need to update the initial conditions file in this test (finidat file in +the user_nl_clm file). -Note that this uses an initial conditions file for f19_g16, year 1850. - -This also turns off the glc two-way coupling. This is done so that +This testmods also turns off the glc two-way coupling. This is done so that glacier areas are taken from the restart file rather than from CISM. This is partly so that changes in CISM don't affect the test results, but more importantly so that LII tests can pass even if CISM changes. (GLC two-way coupling was off in the generation of the initial conditions file used here, too.) + +To update the initial conditions (finidat) file for this test: + +(1) Run the LII test; the 'base' case should run to completion even if the +no_interp test fails. + +(2) Copy the finidat_interp_dest.nc file from the 'base' case to the inputdata +space. Rename this to be similar to the name of the file pointed to in this +test's user_nl_clm file, but with a new creation date. + +(3) Update this the user_nl_clm file in this directory to point to the new +finidat file. diff --git a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm index 989fb4d05c..cbbe700a57 100644 --- a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm @@ -1,4 +1,5 @@ -! This file provides partially-spun-up initial conditions for glc_mec. -! However, it is by no means entirely spun up, and should not be used for production runs. +! See more notes in the README file in this directory and in the comments in the test list. +! +! Initial condition file at the desired configuration to run, so can verify that interpolating from it gives the same result ! Note that this was generated with GLC_TWO_WAY_COUPLING=FALSE -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IG1850CLM45.0006-01-01.1.9x2.5_g1v6_simyr1850_c160127.nc' +finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.I2000Clm50BgcCrop.2000-01-01.1.9x2.5_gx1v7_gl4_simyr2000_c170831.nc' diff --git a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/README b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/README index 6d98819129..f6c97e00e6 100644 --- a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/README +++ b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/README @@ -6,8 +6,7 @@ In this test, glaciers: This also includes some extra bgc fields on the history file, because this test is meant to be used to test bgc evolution as glaciers grow and shrink. -This also includes spun-up initial conditions, in order to provide a more -reasonable test of BGC state variable evolution with dynamic landunits. (With a +This also ensures that spun-up initial conditions are used, in order to provide a more +reasonable test of BGC state variable evolution with dynamic landunits. With a cold start run, the state variables are evolving so fast that it's hard to see -the effects of dynamic landunits.) The explicitly-listed finidat file can be -removed once we have out-of-the-box initial conditions for this test. +the effects of dynamic landunits. diff --git a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/user_nl_clm index 5c8989069c..9ebe31d8e9 100644 --- a/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/user_nl_clm @@ -1,11 +1,5 @@ for_testing_allow_non_annual_changes = .true. -! Use spun-up initial conditions so that it's easier to confirm that dynamic landunits -! are working correctly. Once we have out-of-the-box initial conditions for this test, -! these lines can be removed -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IG1850CRUCLM50BGC.0481-01-01.1.9x2.5_g1v6_gl5_simyr1850_c160127.nc' -use_init_interp = .true. - ! Add 1-d output for all variables that are conserved with dynamic landunits ! ! Most of these are already on the primary history tape; for those that aren't, we add diff --git a/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/README b/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/README index 10169b5f48..9b2a8378d7 100644 --- a/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/README +++ b/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/README @@ -2,10 +2,3 @@ This testmods directory allows testing the interpolation of initial conditions from one resolution (or configuration) to another, using the out-of-the-box initial conditions file for f19 with crop. -Note: if we stop supporting out-of-the-box f19 initial conditions files, this -could be changed to f09 (or whatever resolution we provide initial conditions -for). - -Note: If this test fails, it may be because you need to update the -initial conditions file it uses (finidat). finidat should be updated -to match the out-of-the-box initial conditions file for f19 with crop. diff --git a/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/user_nl_clm index 51e69f7fc5..05c8a39983 100644 --- a/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/user_nl_clm @@ -1,2 +1 @@ -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.ICRUCLM45BGCCROP.78pfts.levis_reinterp.1.9x2.5_g1v6_simyr2000_c160127.nc' use_init_interp = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/interp_f19_noncrop/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/interp_f19_noncrop/user_nl_clm index a4e589da04..928df99e54 100644 --- a/cime_config/testdefs/testmods_dirs/clm/interp_f19_noncrop/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/interp_f19_noncrop/user_nl_clm @@ -1,2 +1,2 @@ -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.I1850CRUCLM45BGC.0241-01-01.1.9x2.5_g1v6_simyr1850_c160127.nc' +finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IGM1850GSWCLM50BGCCROP.0481-01-01.1.9x2.5_gx1v6_gl5_simyr1850_c170419.nc' use_init_interp = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/shell_commands b/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/shell_commands deleted file mode 100755 index 0470d46a28..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/shell_commands +++ /dev/null @@ -1 +0,0 @@ -./xmlchange CLM_BLDNML_OPTS="-irrig .true." -append diff --git a/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/user_nl_clm index 9666d313a7..ee85bb983a 100644 --- a/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/user_nl_clm @@ -6,3 +6,6 @@ hist_mfilt = 1,1 ! In contrast to the standard reduceOutput, use double-precision hist_ndens = 1,1 + +! Turn irrigation on +irrigate = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/shell_commands b/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/shell_commands deleted file mode 100755 index 0470d46a28..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/shell_commands +++ /dev/null @@ -1 +0,0 @@ -./xmlchange CLM_BLDNML_OPTS="-irrig .true." -append diff --git a/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm index 4fb55295df..44bf6a9457 100644 --- a/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm @@ -1,5 +1,6 @@ use_init_interp = .true. -finidat = '$DIN_LOC_ROOT/lnd/clm2/initdata_map/clmi.IGM1850GSWP3CLM50BGCCROPIRR.0031-01-01.1.9x2.5_g1v6_gl5_simyr1850_c170219.nc' -init_interp_fill_missing_with_natveg = .true. ! need this as IC file is glc_mec hist_fincl1 += 'QIRRIG_DEMAND' + +! Turn irrigation on +irrigate = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/shell_commands b/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/shell_commands new file mode 100755 index 0000000000..30c088bf92 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/shell_commands @@ -0,0 +1,4 @@ +# This is useful for testing cases that are not set up with +# out-of-the-box initial conditions files, and would fail if +# a Cold start wasn't being done +./xmlchange CLM_FORCE_COLDSTART="on" diff --git a/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/user_nl_clm deleted file mode 100644 index a933bc4080..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/user_nl_clm +++ /dev/null @@ -1,4 +0,0 @@ -! This is useful for testing cases that are not set up with -! out-of-the-box initial conditions files, and would fail if finidat -! were not explicitly set to blank here. -finidat = ' ' diff --git a/cime_config/testdefs/testmods_dirs/clm/no_vector_output/README b/cime_config/testdefs/testmods_dirs/clm/no_vector_output/README new file mode 100644 index 0000000000..055ad0b8b1 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/no_vector_output/README @@ -0,0 +1,2 @@ +This testmod is similar to the default test mod, but it empties out the 2nd +history tape, which is the vector-output tape. diff --git a/cime_config/testdefs/testmods_dirs/clm/no_vector_output/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/no_vector_output/include_user_mods new file mode 100644 index 0000000000..fe0e18cf88 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/no_vector_output/include_user_mods @@ -0,0 +1 @@ +../default diff --git a/cime_config/testdefs/testmods_dirs/clm/no_vector_output/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/no_vector_output/user_nl_clm new file mode 100644 index 0000000000..773d3738d9 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/no_vector_output/user_nl_clm @@ -0,0 +1 @@ +hist_fincl2 = ' ' diff --git a/cime_config/testdefs/testmods_dirs/clm/ptsRLA/shell_commands b/cime_config/testdefs/testmods_dirs/clm/ptsRLA/shell_commands index db39aa0b54..48287a2998 100644 --- a/cime_config/testdefs/testmods_dirs/clm/ptsRLA/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/ptsRLA/shell_commands @@ -1 +1,2 @@ ./xmlchange PTS_LAT=42,PTS_LON=260 +./xmlchange --force CLM_FORCE_COLDSTART=on diff --git a/cime_config/testdefs/testmods_dirs/clm/ptsRLB/shell_commands b/cime_config/testdefs/testmods_dirs/clm/ptsRLB/shell_commands index 40722f2340..15fd1cced4 100644 --- a/cime_config/testdefs/testmods_dirs/clm/ptsRLB/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/ptsRLB/shell_commands @@ -1 +1,2 @@ ./xmlchange PTS_LAT=-5,PTS_LON=290 +./xmlchange --force CLM_FORCE_COLDSTART=on diff --git a/cime_config/testdefs/testmods_dirs/clm/ptsROA/shell_commands b/cime_config/testdefs/testmods_dirs/clm/ptsROA/shell_commands index ce89f9ce25..d5be09e860 100644 --- a/cime_config/testdefs/testmods_dirs/clm/ptsROA/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/ptsROA/shell_commands @@ -1 +1,2 @@ ./xmlchange PTS_LAT=30,PTS_LON=315 +./xmlchange --force CLM_FORCE_COLDSTART=on diff --git a/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/shell_commands b/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/shell_commands new file mode 100644 index 0000000000..68c7a53e74 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/shell_commands @@ -0,0 +1 @@ +./xmlchange CLM_BLDNML_OPTS="-light_res 360x720" --append diff --git a/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/user_nl_datm b/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/user_nl_datm new file mode 100644 index 0000000000..c88c84629e --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/user_nl_datm @@ -0,0 +1 @@ +iradsw = -1 diff --git a/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/include_user_mods new file mode 100644 index 0000000000..fe0e18cf88 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/include_user_mods @@ -0,0 +1 @@ +../default diff --git a/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/user_nl_clm new file mode 100644 index 0000000000..c1c5ffe8d0 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/user_nl_clm @@ -0,0 +1,8 @@ + reseed_dead_plants = .true. + reset_snow = .true. + reset_snow_glc = .true. + + ! 1774 m was chosen by Leo van Kampenhout, based on the SMB field from the RACMO 2.3 + ! regional climate model, period 1960-1989. The elevation corresponds to the highest point + ! on the contiguous Greenland ice sheet (GrIS) where SMB <= 1 mmWE/yr + reset_snow_glc_ela = 1774. diff --git a/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/include_user_mods new file mode 100644 index 0000000000..fe0e18cf88 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/include_user_mods @@ -0,0 +1 @@ +../default diff --git a/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm b/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm new file mode 100644 index 0000000000..d1a0254a0b --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm @@ -0,0 +1,4 @@ +finidat_rtm = " " +rtmhist_mfilt = 1 +rtmhist_ndens = 2 +rtmhist_nhtfrq = 0 diff --git a/cime_config/testdefs/testmods_dirs/clm/snowlayers_12/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/snowlayers_12/user_nl_clm deleted file mode 100644 index 80d200eb25..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/snowlayers_12/user_nl_clm +++ /dev/null @@ -1,8 +0,0 @@ -nlevsno = 12 -h2osno_max = 20000. - -! Add some multi-layer snow history fields -hist_fincl1 += 'SNO_EXISTENCE', 'SNO_ABS', 'SNO_T:M', 'SNO_GS:X' - -! Need to set use_init_interp because initial conditions file has 5 snow layers -use_init_interp = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/README b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/README deleted file mode 100644 index aab790286d..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/README +++ /dev/null @@ -1,7 +0,0 @@ -This testmods directory is meant to be used in conjunction with a 20th -century transient case at resolution 1x1_tropicAtl. - -However, it generally should not be used directly. Instead, it should be -extended (i.e., included) by a testmods directory that sets the start date to a -desired year, either just before, in the middle of, or after the starting date -on this file. diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/shell_commands b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/shell_commands deleted file mode 100644 index 1edb792323..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/shell_commands +++ /dev/null @@ -1,2 +0,0 @@ -./xmlchange CLM_BLDNML_OPTS="-fire_emis" --append - diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/user_nl_clm deleted file mode 100644 index 81bd8c4938..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/user_nl_clm +++ /dev/null @@ -1,9 +0,0 @@ -flanduse_timeseries = '$DIN_LOC_ROOT/lnd/clm2/surfdata_map/landuse.timeseries_1x1_tropicAtl_TEST_simyr1939-1943_c141219.nc' - -! Need to set this to false because the landuse_timeseries file starts in 1939, disagreeing with the 1850 surface dataset -check_dynpft_consistency = .false. - -! more_vertlayers was a namelist default for this 1x1_tropAtl -! grid. DML didn't see any reason for that. Just making -! soil_layerstruct a testmod -soil_layerstruct = '23SL_3.5m' diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/README b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/README deleted file mode 100644 index 1a6bcd2761..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/README +++ /dev/null @@ -1,6 +0,0 @@ -This testmods directory is meant to be used in conjunction with a 20th -century transient case at resolution 1x1_tropicAtl. - -This starts the simulation prior to the first year defined on that -file, in order to test the logic for starting before the first landuse_timeseries -year. diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/include_user_mods deleted file mode 100644 index a04b982641..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../tropicAtl_subset diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/shell_commands b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/shell_commands deleted file mode 100644 index 99f956ee98..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/shell_commands +++ /dev/null @@ -1 +0,0 @@ -./xmlchange RUN_STARTDATE=1938-01-01 diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/README b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/README deleted file mode 100644 index 50d6a82e8d..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/README +++ /dev/null @@ -1,6 +0,0 @@ -This testmods directory is meant to be used in conjunction with a 20th -century transient case at resolution 1x1_tropicAtl. - -This starts the simulation just after the last year of data defined on -that file, in order to test the logic for starting past the end of the -landuse_timeseries file. diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/include_user_mods deleted file mode 100644 index a04b982641..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../tropicAtl_subset diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/shell_commands b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/shell_commands deleted file mode 100644 index 56c60229fd..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/shell_commands +++ /dev/null @@ -1 +0,0 @@ -./xmlchange RUN_STARTDATE=1943-01-01 diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/README b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/README deleted file mode 100644 index 3bc05089e0..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/README +++ /dev/null @@ -1,5 +0,0 @@ -This testmods directory is meant to be used in conjunction with a 20th -century transient case at resolution 1x1_tropicAtl. - -This starts the simulation in the middle of the dataset, in order to -test the logic for starting in the middle of the landuse_timeseries file. diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/include_user_mods deleted file mode 100644 index a04b982641..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../tropicAtl_subset diff --git a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/shell_commands b/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/shell_commands deleted file mode 100644 index 4fe46cd94a..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/shell_commands +++ /dev/null @@ -1 +0,0 @@ -./xmlchange RUN_STARTDATE=1941-01-01 diff --git a/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/README b/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/README deleted file mode 100644 index f8cf3a84cc..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/README +++ /dev/null @@ -1,14 +0,0 @@ -This testmods directory should be used for vrtlay tests that have an -out-of-the-box initial conditions file. init_interp needs to be run in this -case, because our current out-of-the-box initial conditions files were generated -with shallower soil. - -It does not work to specify use_init_interp = .true. for all vrtlay tests -because this raises an error for tests where there are no initial conditions -(use_init_interp = .true. cannot be used with finidat = ' '). Once we have -changed the namelist logic so that all cases pick up an initial conditions file -(specifying use_init_interp = .true. when needed), this testmods directory can -be removed: either use_init_interp = .true. can be specified for all vrtlay -tests, or (depending on how sophisticated the build-namelist logic is - -particularly, whether it recognizes the incompatibility in soil layer structure) -this may not be needed at all. diff --git a/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/include_user_mods deleted file mode 100644 index b18305eb0e..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../vrtlay diff --git a/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/user_nl_clm deleted file mode 100644 index 05c8a39983..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -use_init_interp = .true. diff --git a/cime_config/user_nl_clm b/cime_config/user_nl_clm index a51176ea1a..a4cfe51182 100644 --- a/cime_config/user_nl_clm +++ b/cime_config/user_nl_clm @@ -8,12 +8,14 @@ ! Set use_cn by the compset you use and CLM_BLDNML_OPTS -bgc setting ! Set use_crop by the compset you use and CLM_BLDNML_OPTS -crop setting ! Set spinup_state by the CLM_BLDNML_OPTS -bgc_spinup setting -! Set irrigate by the CLM_BLDNML_OPTS -irrig setting +! Set irrigate by the CLM_BLDNML_OPTS -irrig .true. setting ! Set co2_ppmv with CCSM_CO2_PPMV option ! Set dtime with L_NCPL option ! Set fatmlndfrc with LND_DOMAIN_PATH/LND_DOMAIN_FILE options ! Set finidat with RUN_REFCASE/RUN_REFDATE/RUN_REFTOD options for hybrid or branch cases ! (includes $inst_string for multi-ensemble cases) +! or with CLM_FORCE_COLDSTART to do a cold start +! or set it with an explicit filename here. ! Set maxpatch_glcmec with GLC_NEC option ! Set glc_do_dynglacier with GLC_TWO_WAY_COUPLING env variable !---------------------------------------------------------------------------------- diff --git a/cime_config/usermods_dirs/cmip6/include_user_mods b/cime_config/usermods_dirs/cmip6/include_user_mods new file mode 100644 index 0000000000..012ab60771 --- /dev/null +++ b/cime_config/usermods_dirs/cmip6/include_user_mods @@ -0,0 +1,2 @@ +../cmip6_glaciers +../cmip6_output diff --git a/cime_config/usermods_dirs/cmip6_glaciers/user_nl_clm b/cime_config/usermods_dirs/cmip6_glaciers/user_nl_clm new file mode 100644 index 0000000000..4963c4945a --- /dev/null +++ b/cime_config/usermods_dirs/cmip6_glaciers/user_nl_clm @@ -0,0 +1,5 @@ + +! This differs from the default in that it turns on virtual columns over Antarctica +! This is desired so that we have the output needed to drive a later offline CISM Antarctica simulation +! However, this increases the cost of CLM by about 10% +glacier_region_behavior = 'single_at_atm_topo', 'virtual', 'virtual', 'virtual' diff --git a/cime_config/usermods_dirs/cmip6_output/README b/cime_config/usermods_dirs/cmip6_output/README new file mode 100644 index 0000000000..f073548a51 --- /dev/null +++ b/cime_config/usermods_dirs/cmip6_output/README @@ -0,0 +1,5 @@ +This directory turns on a variety of extra output fields that are desired for +cmip6 runs. + +To use these mods, you must be using a configuration with CLM50%BGC-CROP using +glc_mec (which is the standard cmip6 configuration). diff --git a/cime_config/usermods_dirs/cmip6_output/shell_commands b/cime_config/usermods_dirs/cmip6_output/shell_commands new file mode 100644 index 0000000000..d742a80f83 --- /dev/null +++ b/cime_config/usermods_dirs/cmip6_output/shell_commands @@ -0,0 +1,4 @@ +#!/bin/bash + +./xmlchange CCSM_BGC=CO2A + diff --git a/cime_config/usermods_dirs/cmip6_output/user_nl_clm b/cime_config/usermods_dirs/cmip6_output/user_nl_clm new file mode 100644 index 0000000000..abbd6f22a6 --- /dev/null +++ b/cime_config/usermods_dirs/cmip6_output/user_nl_clm @@ -0,0 +1,39 @@ +!---------------------------------------------------------------------------------- +! Users should add all user specific namelist changes below in the form of +! namelist_var = new_namelist_value +! +! EXCEPTIONS: +! Set use_cndv by the compset you use and the CLM_BLDNML_OPTS -dynamic_vegetation setting +! Set use_vichydro by the compset you use and the CLM_BLDNML_OPTS -vichydro setting +! Set use_cn by the compset you use and CLM_BLDNML_OPTS -bgc setting +! Set use_crop by the compset you use and CLM_BLDNML_OPTS -crop setting +! Set spinup_state by the CLM_BLDNML_OPTS -bgc_spinup setting +! Set irrigate by the CLM_BLDNML_OPTS -irrig setting +! Set co2_ppmv with CCSM_CO2_PPMV option +! Set dtime with L_NCPL option +! Set fatmlndfrc with LND_DOMAIN_PATH/LND_DOMAIN_FILE options +! Set finidat with RUN_REFCASE/RUN_REFDATE/RUN_REFTOD options for hybrid or branch cases +! (includes $inst_string for multi-ensemble cases) +! Set maxpatch_glcmec with GLC_NEC option +! Set glc_do_dynglacier with GLC_TWO_WAY_COUPLING env variable +!---------------------------------------------------------------------------------- + +hist_fexcl1 = 'PCT_CFT', 'PCT_GLC_MEC', 'SOIL1C_vr', 'SOIL1N_vr', 'SOIL2C_vr', 'SOIL2N_vr', 'SOIL3C_vr', 'SOIL3N_vr', 'CWDC_vr', +'LITR1C_vr', 'LITR2C_vr', 'LITR3C_vr', 'LITR1N_vr', 'LITR2N_vr', 'LITR3N_vr','CWDN_vr' + +hist_fincl2 = 'GPP', 'NPP', 'AGNPP', 'TLAI', 'TOTVEGC', 'TSA','TREFMNAV','TREFMXAV', 'BTRANMN', 'NPP_NUPTAKE', 'GRAINC_TO_FOOD', +'Vcmx25Z', 'FSH', 'NFERTILIZATION', 'AR', 'VEGWP', 'FCTR', 'FCEV', 'FGEV', 'FIRE', 'FSR', 'HTOP' + +hist_fincl3 = 'FSR', 'H2OSNO', 'Q2M', 'SNOWDP', 'TSA', 'TREFMNAV', 'TREFMXAV', 'TG', 'QRUNOFF', 'FSH', 'FIRE', 'FIRA', 'FGR', +'EFLX_LH_TOT', 'RH2M', 'TLAI', 'GPP', 'NPP', 'SOILWATER_10CM', 'TOTSOILLIQ', 'TOTSOILICE', 'AR', 'HR', 'DWT_CONV_CFLUX_PATCH', +'WOOD_HARVESTC', 'U10', 'DWT_WOOD_PRODUCTC_GAIN_PATCH', 'GRAINC_TO_FOOD', 'SLASH_HARVESTC', 'TSOI_10CM', 'COL_FIRE_CLOSS', +'DWT_SLASH_CFLUX','TOTSOMC:I', 'TOTSOMC_1m:I', 'TOTECOSYSC:I', 'TOTVEGC:I', 'WOODC:I', 'TOTLITC:I', 'LIVECROOTC:I', 'DEADCROOTC:I', +'FROOTC:I' + +hist_fincl4 = 'PCT_CFT', 'PCT_GLC_MEC', 'SOIL1C_vr', 'SOIL1N_vr', 'SOIL2C_vr', 'SOIL2N_vr', 'SOIL3C_vr', 'SOIL3N_vr', 'CWDC_vr', +'LITR1C_vr', 'LITR2C_vr', 'LITR3C_vr', 'LITR1N_vr', 'LITR2N_vr', 'LITR3N_vr','CWDN_vr','QICE_FORC', 'TSRF_FORC', 'TOPO_FORC' + +hist_mfilt = 1,1,1,1 +hist_dov2xy = .true.,.false.,.false.,.true. +hist_nhtfrq = 0,0,0,-8760 +hist_type1d_pertape = '','','LAND','' diff --git a/doc/ChangeLog b/doc/ChangeLog index 1398de472e..ce20db0ca6 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,6990 @@ =============================================================== +Tag name: clm4_5_18_r270 +Originator(s): sacks (Bill Sacks) +Date: Wed Dec 20 12:04:25 MST 2017 +One-line Summary: Always use multiple elevation classes for glacier, even with stub glc + +Purpose of changes +------------------ + +Up until now, we have been using the glacier_mec (multiple elevation +class) scheme when running with CISM, but the old non-elevation class +scheme when running with a stub glacier model (SGLC). This is +problematic because it means that simply switching from CISM to SGLC +fundamentally changes CLM's glacier physics. (Note: with the current +configuration, the multiple elevation class scheme is enabled over +Greenland and Antarctica but not elsewhere.) + +There are a few use cases where this is important: + +- Single-point and regional runs over glacier regions: In this case, you + cannot use CISM. Members of the LIWG want to do runs like this so they + can do single-point testing with the multiple elevation class scheme. + +- Currently, CISM does not support a Gregorian calendar (i.e., with leap + years). So cases with a Gregorian calendar need to use SGLC. This + includes data assimilation and CAM specified dynamics runs. We want + the physics of these runs to match the standard CLM physics as closely + as is feasible. + +- There may be other cases where a user doesn't want to include CISM + because of the extra complexity this involves, such as when setting up + a new grid (which would require additional mapping files for + CISM). Again, we want the physics of these runs to match the standard + CLM physics as closely as is feasible. + +Note that runs with SGLC will still differ somewhat from runs with CISM, +even when CISM is running in the typical NOEVOLVE mode. This is because +there will be differences in % glacier and topographic heights over +Greenland: in a run with CISM, this information comes from CISM at the +start of the run so that CLM and CISM agree in this respect; in a run +with SGLC this information comes from CLM's surface dataset. + +However: Running with SGLC now gives the same answers as running with +CISM with GLC_TWO_WAY_COUPLING set to FALSE. (These both differ from the +standard configuration that uses CISM with GLC_TWO_WAY_COUPLING TRUE +just over Greenland.) + +Mostly-unrelated change: Remove tropicAtl grid + + +Bugs fixed or introduced +------------------------ + +Known bugs introduced in this tag (include bugzilla ID): +- https://github.com/ESCOMP/ctsm/issues/158 now causes test failures for + ERS_Lm20_Mmpi-serial.1x1_smallvilleIA.I2000Clm50BgcCropGs.yellowstone_pgi.clm-monthly, + since we're now using a new and buggy surface dataset for that case. + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): +- If you use an finidat file from an old run that used SGLC, you'll need + to run init_interp and will need to set + init_interp_fill_missing_with_natveg = .true. in user_nl_clm. Note + that this will initialize glacier_mec landunits with information from + vegetated landunits, which is not a very good initialization, so + you'll want to spin up for a while to spin up the new glacier_mec + landunits. + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): no + +Changes made to namelist defaults (e.g., changed parameter values): no + +Changes to the datasets (e.g., parameter, surface or initial files): +- New surface datasets for single-point and regional runs: These now + have the data necessary to run with the multiple elevation class + glacier scheme. None of our out-of-the-box single-point or regional + datasets have any glacier cover, so this doesn't lead to substantive + changes. Note, though, that the smallville datasets hadn't been + updated in a while, so there are bigger changes to the smallville + datasets. The new smallville datasets are buggy (due to + https://github.com/ESCOMP/ctsm/issues/158), but the old ones wouldn't + have worked with the new code due to missing glacier_mec + information. Note that I have NOT changed the landuse.timeseries + files, because those don't change in any substantive way with the + setting of -glc_nec in mksurfdata_map. + +- Runs with SGLC now point to different finidat files by default: they + now point to finidat files that were generated with glacier_mec, which + may differ substantially from the files that were generated without + glacier_mec (since I think these came from completely different + spinups). + +Substantial timing or memory changes: Expect some performance +degradation in SGLC runs, since now we're using multiple elevation +classes over Greenland and Antarctica, though I haven't investigated it +carefully. + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: Delete tropicAtl_subset tests: these tests +didn't provide much value, and the code they cover is also covered by +unit tests + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - ok + + prove test_build_namelist fails as on trunk + + main build-namelist tests pass, clm4_5 and clm5_0 lnd_in files + differ from trunk as expected + + unit-tests (components/clm/src): + + cheyenne - pass + + tools-tests (components/clm/test/tools): + + cheyenne - ok + + Tests pass other than these known issues: + + smfg4 TSMscript_tools.sh PTCLM PTCLMmkdata PTCLM_USUMB_Global_clm4_5^buildtools + See https://github.com/ESCOMP/ctsm/issues/188 + + blf84 TBLscript_tools.sh PTCLM PTCLMmkdata PTCLM_USUMB_clm4_5^buildtools + blfc4 TBLscript_tools.sh PTCLM PTCLMmkdata PTCLM_USUMB_Cycle_clm4_5^buildtools + See https://github.com/ESCOMP/ctsm/issues/187 + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - ok + + 1 failure, as on the trunk + + compare tests: 40 PASS, 1 Fail; on the trunk, all 41 Failed. I'm + not sure why my branch improves things in this respect. + + regular tests (aux_clm): + + yellowstone_intel - ok + yellowstone_pgi --- ok + yellowstone_gnu --- ok + cheyenne_intel ---- ok + cheyenne_gnu ------ ok + hobart_nag -------- ok + hobart_pgi -------- ok + hobart_intel ------ ok + + Tests pass. Baseline comparisons fail for compsets with SGLC (both + global tests and single-point and regional tests). This is expected + and is described in detail below. + +CLM tag used for the baseline comparisons: clm4_5_18_r269 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: All compsets with SGLC (as opposed to CISM) + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + Potentially new climate, though not investigated carefully + + Answers change in runs with SGLC due to the use of different + out-of-the-box finidat files: they now point to finidat files that + were generated with glacier_mec, which may differ substantially + from the files that were generated without glacier_mec (since I + think these came from completely different spinups). + + For global runs, even without finidat differences, answers change + over Greenland and Antarctica, since we're now using the + multiple-elevation-class scheme there. Answers are the same + outside of Greenland and Antarctica, where we still use a single + glacier elevation class. (Based on spot-checking FSH in a 3-year + cold start run.) + + (For single-point and regional runs, differences are mainly just + due to changes in finidat. One exception may be smallville tests, + since the smallville surface datasets have changed more + extensively; I did not investigate the smallville answer changes + carefully.) + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): +- cime: cime5.4.0-alpha.03 -> billsacks/always_glcmec_n01 + The changes here are: + - always use GLC_NEC=10, except for CLM40 + - delete references to tropicAtl + +List all files eliminated: + +========= These glacierMEC use cases weren't accomplishing anything: + compared with the similar non-glacierMEC use cases, they just + set the glc_nec namelist variable, but this variable didn't + even exist! So I have switched cases to use the corresponding + non-glacierMEC use cases +D components/clm/bld/namelist_files/use_cases/1850_glacierMEC_control.xml +D components/clm/bld/namelist_files/use_cases/1850-2100_rcp2.6_glacierMEC_transient.xml +D components/clm/bld/namelist_files/use_cases/1850-2100_rcp6_glacierMEC_transient.xml +D components/clm/bld/namelist_files/use_cases/1850-2100_rcp4.5_glacierMEC_transient.xml +D components/clm/bld/namelist_files/use_cases/1850-2100_rcp8.5_glacierMEC_transient.xml +D components/clm/bld/namelist_files/use_cases/20thC_glacierMEC_transient.xml +D components/clm/bld/namelist_files/use_cases/2000_glacierMEC_control.xml + +========= This use case appeared to be unused +D components/clm/bld/namelist_files/use_cases/glacierMEC_pd.xml + +========= These tropicAtl_subset tests were hard to maintain and didn't + provide much value: the code they covered is also covered via + unit tests +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/include_user_mods +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/shell_commands +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid/README +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetMid +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/include_user_mods +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/shell_commands +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly/README +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetEarly +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/README +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/include_user_mods +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate/shell_commands +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subsetLate +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/shell_commands +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/README +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset + + +List all files added and what they do: + +List all existing files that have been modified, and describe the changes: + +========= Always use -glc_nec 10, delete tropicAtl, and other minor fixes +M components/clm/tools/mksurfdata_map/Makefile.data + +========= Require glc_nec >= 1 when making surface datasets +M components/clm/tools/mksurfdata_map/src/mkfileMod.F90 +M components/clm/tools/mksurfdata_map/src/mkglcmecMod.F90 +M components/clm/tools/mksurfdata_map/src/mksurfdat.F90 +M components/clm/tools/mksurfdata_map/mksurfdata.pl + +========= Require glc_nec >= 1 for clm45/clm50 +M components/clm/bld/CLMBuildNamelist.pm +M components/clm/bld/unit_testers/build-namelist_test.pl +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml +M components/clm/cime_config/buildnml + +========= Remove istice; always use glacier_mec type +M components/clm/src/biogeochem/DryDepVelocity.F90 +M components/clm/src/main/controlMod.F90 +M components/clm/src/main/LandunitType.F90 +M components/clm/src/main/TopoMod.F90 +M components/clm/src/main/filterMod.F90 +M components/clm/src/main/lnd2glcMod.F90 +M components/clm/src/main/clm_varctl.F90 +M components/clm/src/main/clm_driver.F90 +M components/clm/src/main/subgridAveMod.F90 +M components/clm/src/main/initGridCellsMod.F90 +M components/clm/src/main/initVerticalMod.F90 +M components/clm/src/main/atm2lndMod.F90 +M components/clm/src/main/surfrdMod.F90 +M components/clm/src/main/clm_instMod.F90 +M components/clm/src/main/landunit_varcon.F90 +M components/clm/src/main/subgridWeightsMod.F90 +M components/clm/src/main/clm_initializeMod.F90 +M components/clm/src/main/subgridMod.F90 +M components/clm/src/main/ColumnType.F90 +M components/clm/src/main/histFileMod.F90 +M components/clm/src/main/restFileMod.F90 +M components/clm/src/biogeophys/WaterStateType.F90 +M components/clm/src/biogeophys/SnowHydrologyMod.F90 +M components/clm/src/biogeophys/HydrologyDrainageMod.F90 +M components/clm/src/biogeophys/BalanceCheckMod.F90 +M components/clm/src/biogeophys/TemperatureType.F90 +M components/clm/src/biogeophys/SurfaceAlbedoMod.F90 +M components/clm/src/biogeophys/PhotosynthesisMod.F90 +M components/clm/src/biogeophys/CanopyTemperatureMod.F90 +M components/clm/src/biogeophys/SoilHydrologyInitTimeConstMod.F90 +M components/clm/src/biogeophys/SurfaceResistanceMod.F90 +M components/clm/src/biogeophys/TotalWaterAndHeatMod.F90 +M components/clm/src/biogeophys/WaterfluxType.F90 +M components/clm/src/biogeophys/CanopyHydrologyMod.F90 +M components/clm/src/biogeophys/GlacierSurfaceMassBalanceMod.F90 +M components/clm/src/biogeophys/SoilStateInitTimeConstMod.F90 +M components/clm/src/biogeophys/SoilTemperatureMod.F90 +M components/clm/src/dyn_subgrid/dynInitColumnsMod.F90 +M components/clm/src/dyn_subgrid/dynLandunitAreaMod.F90 +M components/clm/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights.pf +M components/clm/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights_one_gcell.pf +M components/clm/src/dyn_subgrid/dynSubgridDriverMod.F90 +M components/clm/src/cpl/clm_cpl_indices.F90 +M components/clm/src/cpl/lnd_import_export.F90 +M components/clm/src/cpl/lnd_comp_mct.F90 + +========= In addition to supporting the main changes of this tag, also + do a fairly major refactor: set fields internally rather than + letting lnd_import set the fields +M components/clm/src/main/glc2lndMod.F90 + +========= Fixes to unit tests for changes in glc2lnd +M components/clm/src/main/test/topo_test/test_topo.pf + +========= Remove tropicAtl tests and references to tropicAtl grid (see + above for more notes on this) +M components/clm/cime_config/testdefs/testlist_clm.xml +M components/clm/bld/test_build_namelist/t/input/namelist_defaults_clm4_5_test.xml +M components/clm/bld/test_build_namelist/t/input/namelist_definition_clm4_5_test.xml +M components/clm/bld/namelist_files/namelist_definition_clm4_0.xml +M components/clm/bld/namelist_files/namelist_defaults_clm4_5_tools.xml +M components/clm/bld/namelist_files/namelist_defaults_overall.xml +M components/clm/bld/namelist_files/namelist_defaults_clm4_0.xml +M components/clm/bld/namelist_files/checkmapfiles.ncl +M components/clm/doc/UsersGuide/adding_files.xml + +========= No longer use glacierMEC-specific use cases (see above for + more notes on this) +M components/clm/cime_config/config_component.xml + +========= Fix creation date of files pointed to by tests +M components/clm/test/tools/nl_files/PTCLM_USUMB_clm4_5 +M components/clm/test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 +M components/clm/test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 + +========= No longer need init_interp_fill_missing_with_natveg (I think + this could have been removed a while ago) +M components/clm/cime_config/testdefs/testmods_dirs/clm/clm50KSinkMOut/user_nl_clm + +========= New expected failure: + ERS_Lm20_Mmpi-serial.1x1_smallvilleIA.I2000Clm50BgcCropGs.yellowstone_pgi.clm-monthly +M components/clm/cime_config/testdefs/ExpectedTestFails.xml + +=============================================================== +=============================================================== +Tag name: clm4_5_18_r269 +Originator(s): erik (Erik Kluzek,UCAR/TSS,303-497-1326) +Date: Sat Dec 16 19:49:41 MST 2017 +One-line Summary: Move externals to version in github + +Purpose of changes +------------------ + +Move the CLM externals to the version in github for MOSART, RTM and +PTCLM. For PTCLM this meant updating to a version that didn't take +advantage of subversion keywords. I also updated to a version that +can properly compare to the files it keeps even with differences +of user, machine, path, or date. + + +Bugs fixed or introduced None +------------------------ + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self,andre + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + + unit-tests (components/clm/src): + + cheyenne - PASS + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - OK + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_18_r268 + + +Answer changes +-------------- + +Changes answers relative to baseline: no bit-for-bit + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): rtm, mosart, PTCLM + + mosart1_0_28 to github version + rtm1_0_63 to github version + PTCLM to PTCLM2_171216c and github version + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: None + +=============================================================== +=============================================================== +Tag name: clm4_5_18_r268 +Originator(s): erik (Erik Kluzek) +Date: Mon Dec 11 16:47:24 MST 2017 +One-line Summary: Fix calculation of stomatal resistence used in dry-deposition, increase threshold of totvegc for soil decomposition to 0.1 + +Purpose of changes +------------------ + +Changes from Louisa Emmons to fix the calculation of stomatal resistence in the dry-deposition code so it's the inverse +of the previous calculation (and the arbitrary multiplicitive factor to reduce it was removed). Add new optional history +fields for dry-deposition. + +Increase the threshold of total vegetation carbon for when decomposition pools are reset from 1.e-8 to 0.1. This change comes from +Dave Lawrence and Keith Oleson. The code was also modified to use better names for this rather than ccrit and ncrit which came in +clm4_5_17_r264. Add some new checking for these settings at initialization. Add some changes to the default CMIP6 output from +Keith Oleson. + +Add in f05 fsurdat and one landuse.timeseries datasets. Add check in SSP test that makes sure the compset used includes MOSART as +expected. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): 2545, 2546 + 2526 -- Fix calculation of stomatal resistance for dry deposition + 2545 -- SSP test assumes that MOSART is being used, and dies inexplicably if not + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + Add new optional history fields when drydeposition is on: DRYDEPV_*, RS_DRYDEP_O3 + +Changes made to namelist defaults (e.g., changed parameter values): + +Changes to the datasets (e.g., parameter, surface or initial files) Add f05 fsurdat and one landuse.timeseries file: + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + RS_DRYDEP_O3 history field is hardcoded for Ozone. In most cases the same value would apply to other species, but it is + hardcoded to give values for Ozone. + +Changes to tests or testing: Add ciso SSP test + +Code reviewed by: self,tilmes,emmons,fvitt + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + + unit-tests (components/clm/src): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_18_r267 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes, but only for drydep and/or exit_spinup + + Summarize any changes to answers, i.e., + - what code configurations: with drydep on, or in exit_spinup mode for either clm4_5 or clm5_0 + - what platforms/compilers: All + - nature of change: modest + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: Add new ciso_rtmColdSSP testmod -- includes ciso and rtmColdSSP testmods + + A /clm/cime_config/testdefs/testmods_dirs/clm/ciso_rtmColdSSP/include_user_mods + +List all existing files that have been modified, and describe the changes: + + M components/clm/bld/unit_testers/build-namelist_test.pl -- Increase test numbers as now testing f05 datasets + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml ---- Add f05 fsurdat files and one landuse.timeseries file + M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml -- Add f05 to list of supported resolutions + + M components/clm/cime_config/testdefs/testlist_clm.xml --------------- Add SSP ciso test + M components/clm/cime_config/usermods_dirs/cmip6_output/user_nl_clm -- Added FCTR, FCEV, FGEV, FIRE, FSR, and HTOP; + and removed QVEGT; all from the h1 file (fincl2) (from Keith Oleson) + M /clm/cime_config/SystemTests/ssp.py ---------------------- Update comments, add expect that compset uses mosart + + M components/clm/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 --- Change ncrit to totvegcthresh and SetNCrit to SetTotVgCThresh + add abort if totvegcthresh is unset, and check that it's greater than zero + M components/clm/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 - Set totvegcthresh to 0.1 and pass down via setTotVgCThresh methods + M components/clm/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 ----- Change ccrit to totvegcthresh and SetNCrit to SetTotVgCThresh + add abort if totvegcthresh is unset, and check that it's greater than zero + M components/clm/src/biogeochem/DryDepVelocity.F90 ------------------------ Modifications from Louisa Emmons, Corrected the equation + calculating stomatal resistance from rssun and rssha, add new array rs_drydep_patch, add new history + output possibilities: DRYDEPV_*, RS_DRYDEP_O3, use spval instead of hardcoded magic number 1.e36 + +=============================================================== +=============================================================== +Tag name: clm4_5_18_r267 +Originator(s): sacks (Bill Sacks) +Date: Thu Dec 7 19:26:48 MST 2017 +One-line Summary: Fixes to accumulator fields + +Purpose of changes +------------------ + +(1) Only accumulate accumulators over active (typically, + non-zero-weight) patches/columns. This changes answers for transient + runs. Previously, accumulator fields were being accumulated even + when a patch/column was inactive. In many cases this was relatively + harmless, but in some cases it was accumulating garbage like + spval. Then, once the point became active, it could take a while for + the garbage accumulated values to be worked out. + + This changes answers for transient runs. I have examined all + accumulator fields used in a typical BgcCrop run (this does NOT + include fields that are only used for CNDV or FATES). Most changes + only last for the first month or so that a point is active, but + there are larger changes for: + + - PREC10 and PREC60: The changes in these are probably the most + extreme. In the old code, these started as spval (rather than a + blank slate) over newly-active patches. PREC10 is garbage for the + first few years after a point becomes active. I didn't look at + PREC60, but its logic is the same as PREC10, so I would expect it + to be garbage for about the first 20 years after a point becomes + active. PREC10 is used in the fire code and for stress deciduous + phenology. PREC60 is used in the fire code. + + - AnnET: In the old code, this started as 0 (rather than a blank + slate) over newly-active points. This affects answers for the + first year or two. This is used in N fixation code. + + - FSUN24 and FSUN240: In the old code, these started out as spval; + it takes a few years for the FSUN240 accumulator to come back down + to reasonable values (even though it's a 10-day accumulator, its + "exponential running average" behavior means that it takes much + longer for memory of a huge value like spval to disappear). These + are just used in VOCEmissionsMod. + + I have not investigated how much these changes in accumulators + affect the science of the model. The biggest effects will probably + be in the fire code in transient runs, but I haven't looked at how + big of an effect these errors in PREC60 have. + + There are also potentially very large changes in CNDV, due to change + in behavior of some patch-level accumulators which are needed for + PFT establishment (and thus should be available over inactive + patches, but no longer are valid for inactive patches). However, + these fields were already buggy (see bug 2537). + +(2) For startup/hybrid runs with non-blank finidat (including runs with + use_init_interp): Continue accumulating continuously from where + things were in the finidat file. Previously, many of the + accumulators were being reset in startup/hybrid runs. This appeared + to be an accident of the implementation details, whose fix was easy + as a side-effect of the fix for (1). This shouldn't have a huge + effect: most accumulators are order 10 days, with the longest being + 365 days, so differences should work themselves out within the first + year or so. But this could be important if you expect a spinup run + to transition continuously into a transient run (for example). + + This changes answers for any startup or hybrid case with non-blank + finidat, where the restart file is from this tag or later. It does + NOT change answers for old restart files. (These old files are + missing the new _NSTEPS fields associated with each accumulator + field, and so nsteps values are set to 0 in a startup/hybrid run, + similarly to the old behavior.) + +Also, a somewhat-unrelated change: Abort if a field is missing from the +restart file in a branch run (just as we do for a continue run); tell +the user to do a startup or hybrid run in this case. My reason for +folding this change into this tag was so that I don't need to worry +about backwards compatibility of branch runs with old restart files. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): +- 2526: Some CLM accumulated fields (via accumulMod) are incorrect with dynamic landunits + +Known bugs introduced in this tag (include bugzilla ID): +- The following pre-existing bugs may be somewhat worse now: + - 2537: Climate accumulator fields incorrect for CNDV + - 2539: CNDV logic for agdd20 and tmomin20 needs to be revised to + account for when a given patch/column becomes active + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + +- Can no longer do a branch run if some fields are missing from the + restart file, either due to code changes or configuration changes (need + to do hybrid or startup). + +- Cannot do a branch from restart files generated with prior tags, + because the _NSTEPS restart fields associated with accumulation fields + are missing. + +- Startup or hybrid runs using restart files that were generated from + prior tags will not take advantage of fix (2) above. + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - not run + + unit-tests (components/clm/src): + + cheyenne - pass + + tools-tests (components/clm/test/tools): + + cheyenne - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - not run + + regular tests (aux_clm): + + yellowstone_intel - ok + yellowstone_pgi --- ok + yellowstone_gnu --- ok + cheyenne_intel ---- ok + cheyenne_gnu ------ ok + hobart_nag -------- ok + hobart_pgi -------- ok + hobart_intel ------ ok + + ok means tests pass, answer changes as expected (see below) + +CLM tag used for the baseline comparisons: clm4_5_17_r266 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: + - Cases with transient vegetation (Hist, Dv) + - Startup / hybrid cases using restart files generated from this + code base. In the test suite, this just shows up as answer + changes in ERI and SSP tests, since other tests use old initial + conditions files. + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + Larger than roundoff. Not yet investigated as to whether this is + the same or different climate. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: + +========= Cover accumulMod with unit tests +A components/clm/src/main/test/accumul_test/test_accumul.pf +A components/clm/src/main/test/accumul_test/CMakeLists.txt +A components/clm/src/main/test/accumul_test + +List all existing files that have been modified, and describe the changes: + +========= Main changes, as described above +M components/clm/src/main/accumulMod.F90 +M components/clm/src/biogeophys/TemperatureType.F90 + +========= Change PREC365 to col-level: with these changes, when it was + at patch-level, it would be invalid over not-yet-active + patches - yet it's needed there for the sake of PFT + establishment in CNDV. Also initialize pbot to spval now that + bug 2526 is resolved. +M components/clm/src/main/atm2lndType.F90 +M components/clm/src/biogeochem/CNDVEstablishmentMod.F90 + +========= Need 'active' flag in gridcell_type (always true), so that + gridcell_type has the same interface as other subgrid types in + this respect +M components/clm/src/main/GridcellType.F90 + +========= Abort if a field is missing from the restart file in a branch + run (see above for details) +M components/clm/src/utils/restUtilMod.F90.in + +========= Cover accumulMod with unit tests +M components/clm/src/main/test/CMakeLists.txt + +========= Changes needed so that code under test can call get_proc_bounds +M components/clm/src/unit_test_shr/unittestSubgridMod.F90 + +=============================================================== +=============================================================== +Tag name: clm4_5_17_r266 +Originator(s): sacks (Bill Sacks) +Date: Mon Nov 27 19:43:39 MST 2017 +One-line Summary: Avoid negative snow densities + +Purpose of changes +------------------ + +For very low temperatures, fresh snow densities were negative. This was +only happening at extremely low temperatures (below -100 deg C), but +caused snow balance errors when it occurred. + +In exploring the LoTmpDnsSlater2017 parameterization in +NewSnowBulkDensity, I came away with the following thoughts: + + It seems like there should be a limit on the temperature-dependent + bifall value. I extracted this function into python and played with + it for a few minutes: + + else if (new_snow_density == LoTmpDnsSlater2017) then + ! Andrew Slater: A temp of about -15C gives the nicest + ! "blower" powder, but as you get colder the flake size decreases so + ! density goes up. e.g. the smaller snow crystals from the Arctic and Antarctic + ! winters + bifall(c) = -(50._r8/15._r8 + 0.0333_r8*15_r8)*(forc_t(c)-tfrz) - 0.0333_r8*(forc_t(c)-tfrz)**2 + end if + + It looks like the intention is to have snow densities that increase + with decreasing temperature (below -15 C), but the effect of this + parabolic function is to have densities start coming back down as + temperature decreases too low (below about -58 C). My sense is that + we should do one of the following in the above block of code: + + (1) Limit bifall(c) to be no less than 50... my read of this code is + that temperature-dependent bifall is never meant to go below 50. + + (2) For this cold-temperature-based bifall, use an "effective" forc_t + that is never colder than about -58 C – or the point at which this + function begins to decrease with further-decreasing temperatures. (We + could determine the exact temperature at which this function turns + over... -58 C is just an approximation.) I'm not positive that this + is what's intended, but my read of the comment suggests that + densities were never intended to start decreasing with + further-cooling temperatures. + +See comments and figures in +http://bugs.cgd.ucar.edu/show_bug.cgi?id=2536 for more details. + +Leo van Kampenhout and Jan Lenaerts support limitation option 2, which +is my preference as well. Thus, this tag implements that limitation. + +This change changes answers for (downscaled) atmospheric forcing +temperatures below -57.55 deg C. These very low temperatures are rare, +but they do sometimes occur, both in coupled runs and in offline runs. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): +- 2536: Snow balance error + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: Leo van Kampenhout + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - not run + + unit-tests (components/clm/src): + + cheyenne - pass + + tools-tests (components/clm/test/tools): + + cheyenne - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - not run + + regular tests (aux_clm): + + yellowstone_intel - ok + yellowstone_pgi --- ok + yellowstone_gnu --- ok + cheyenne_intel ---- ok + cheyenne_gnu ------ ok + hobart_nag -------- ok + hobart_pgi -------- ok + hobart_intel ------ ok + + ok means tests pass, answers change as expected + +CLM tag used for the baseline comparisons: clm4_5_17_r265 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: all + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + larger than roundoff/same climate + + Many (but not all) tests show answer changes. Answers should only + change for (downscaled) forcing temperatures below -57.55 deg C. I + spot-checked one test with answer changes + (SMS_D_Ld3.f10_f10_musgs.I1850Clm50BgcCrop.cheyenne_intel.clm-default). I + checked H2OSNO and FSH in this test, in the last day's h0 file; + these fields differ (relative to the baseline) in only one + gridcell. TBOT was about -55 deg C in the daily average of the + last day, so it seems reasonable that this forcing temperature was + below -57.55 deg C at some point in the 3-day simulation. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +M components/clm/src/biogeophys/SnowHydrologyMod.F90 +M components/clm/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_newSnowBulkDensity.pf + +=============================================================== +=============================================================== +Tag name: clm4_5_17_r265 +Originator(s): erik (Erik Kluzek) +Date: Sat Nov 18 12:40:20 MST 2017 +One-line Summary: Update the clm50 parameter file for better behavior with prognostic crop, and fix a bug in clm50 urban model + +Purpose of changes +------------------ + +Update a few parameters to tweak prognostic crop harvest yields, adjusting FUN costs, and changing C4 crops and +wheat by Keith Oleson, Dave Lawrence, and Danica Lombardozzi. Danica had this to say: + Overall, the wheat parameters work well (give us correct Fertilized - Unfertilized behavior + and reasonable crop yields), but the C4 crop parameters are less satisfying. The 2A parameter + changes still have trouble with the fertilized - unfertilized behavior in some regions and + lower yields, but seems to be the best combined set of behaviors since there seems to be + a direct tradeoff between the fertilized behavior and crop yields + +Also a fix to urban initialization of rootfr for pervious road. It had used a magic number to assuming nlevsoi +was 10. Now we divide by the actual nlevsoi. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): 2434 + 2434 -- urban assumed to have 10 soil layers + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): clm50 params file + +Changes to the datasets (e.g., parameter, surface or initial files): clm50 parameter file + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self,oleson + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + + unit-tests (components/clm/src): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_17_r264 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES, for CLM50 + + Summarize any changes to answers, i.e., + - what code configurations: all clm50 (except non-urban and non-crop) + - what platforms/compilers: all + - nature of change: crop behavior changes, urban working better + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml -- new params file +M components/clm/src/biogeophys/SoilStateInitTimeConstMod.F90 ----- Divide by nlevsoi + rather than assume nlevsoi is 10 with a magic number. + +=============================================================== +=============================================================== +Tag name: clm4_5_17_r264 +Originator(s): erik (Erik Kluzek) +Date: Thu Nov 16 13:35:59 MST 2017 +One-line Summary: Changes from Dave Lawrenece on resetting soil carbon for spinup + +Purpose of changes +------------------ + +Changes from Dave Lawrence so that total vegetation carbon (totvegc) is used for resetting soil carbon +stocks during the AD spinup exit (to determine if you should reset both carbon and nitrogen). Also read +in totvegc for C13, and C14. These are then passed down into soilbiogechemistry nitrogenstate and carbonstate +restart to determine if the decomposition pools should be reset. The resetting is only done over non-crop +vegetation (ignoring both prognostic and generic crop types) and is only done on the exit_spinup phase +going out of accellerated decomposition mode. + +Fix a couple small issues that in principle could change answers, but we didn't see answer changes in testing. +There was an error in how rootfr was initialized if it wasn't on the restart file. Made sure the crop patch +level restart variables are read after the enter_spinup code. + +Bugs fixed or introduced +------------------------ + 2406 -- Crop patch-level restart variables read after enter_spinup code + 2426 -- Error in rootfr for SoilStateType restart + 2447 -- dayl_factor not just exactly zero, but small + +Bugs fixed (include bugzilla ID): + +Known bugs introduced in this tag (include bugzilla ID): Following found + 2534 -- rootfr_road_perv calculation now incorrect for CLM50 + 2533 -- c13/c14 isotope time-series is awkward for 1850 control (convert to streams file) + 2531 -- FATES doesn't call SoilBiogeochemCompetitionInit + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + SetNCrit in SoilBiogeochemNitrogenStateType.F90, should be SetCCrit, because totvegc is + used rather than totvegn. + SoilBiogeochemPrecisionControlInit was added as a new method that could be extended to + set ncrit and ccrit from namelist, or to set them from the settings for CNPrecisionControl + that are read in by namelist + +Changes to tests or testing: None + +Code reviewed by: self,dlawren + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular (without testing on cheyenne when tag was made) + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- Ran on yellowstone OK + cheyenne_gnu ------ Ran on yellowstone OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_17_r263 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes, but only for spinup! + + Summarize any changes to answers, i.e., + - what code configurations: Only during spinup (at exit_spinup stage) + - what platforms/compilers: All + - nature of change: minor for spinup + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + M components/clm/src/biogeochem/CNVegCarbonStateType.F90 --- Add totvegc_col (and cor c13/c14) to restart + M components/clm/src/biogeochem/CNVegetationFacade.F90 ----- Add get_totvegc_col to get the column level totvegc + M components/clm/src/main/clm_initializeMod.F90 ------------ Remove use of CNDriverInit, not needed + M components/clm/src/main/clm_instMod.F90 ------------------ Add call to SoilBiogeochemCompetitionInit + do vegetation restart before soil bgc restart, pass totvegc down to soilbiogeochem_carbonstate restart (and nitrogenstate) + M components/clm/src/biogeophys/PhotosynthesisMod.F90 ------ Fix bug 2447 checking for small dayl_factor and not just exactly zero + M components/clm/src/biogeophys/SoilStateType.F90 ---------- Fix bug 2446 initialize rootfr only if rootfr not read in + M components/clm/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 ---- Add SetNCrit to set new module variable ncrit + pass totvegc_col into restart, if it is lower than ncrit (and not crop) reset decomposition pools to zero + M components/clm/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 -- Add SoilBiogeochemPrecisionControlInit, to set + ncrit and ccrit now module variables and pass them down to carbonstate and nitrogenstate + M components/clm/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 ------ Add SetCCrit to set new module variable ccrit + pass totvegc_col into restart, if it is lower than ccrit (and not crop) reset decomposition pools to zero + save restart_file_spinup_state and read it in with C12 + +=============================================================== +=============================================================== +Tag name: clm4_5_17_r263 +Originator(s): erik (Erik Kluzek) +Date: Wed Nov 8 15:36:41 MST 2017 +One-line Summary: Drydep vel. for SO2 doubled, influence of organic mater in soil calmed, max daylength not hardwired to present day + +Purpose of changes +------------------ + +Keep the hydraulic conductivity for organic soil higher than it is for mineral soil. This was found to be an issue and fixed by +Sean Swenson, Dave Lawrence, and Keith Oleson. Double dry deposition velocity for SO2 (Jean-Francois Lamaruque) for both clm4_5 +and clm5_0. Fix bug for value of NACTIVE at first time-step. Partial fix so that max daylengh isn't hardwired to present day at least +at initialization (see caveat below). Move the sample files for the mkprocdata_map tool (for mapping between unstructured grids +and regular lat lon grids) out of CLM and into $CSMDATA. Update the c13/c14 timeseries files to the 2.0 version as per Keith Lindsay. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2530 -- organic soil influence varies wildly + 2304 -- NACTIVE at first time step + 1843 -- Max daylength now uses orbital parameters at initialization rather than hardwired to present day (partial) + +Known bugs introduced in this tag: + 2529 -- SSP case that runs on cheyenne fails on hobart + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): c13/c14 time-series files + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + Max daylength will still be wrong in cases where variable_years is used, where the orbit + changes after initializaiton. It'll start out correct and begin to diverge each year. + Since, this feature is untested it's not worth going through the additional changes to + correct it during the run. + + At the time the tag was made, cheyenne was down, so there are six tests that weren't confirmed to pass: + ERS_D_Ld3.f19_f19_mg16.IHistClm40SpCruGs.cheyenne_intel.clm-40default + ERS_Ly5_P60x1.f10_f10_musgs.IHistClm50BgcCrop.cheyenne_intel.clm-cropMonthOutput + SMS_D_Ld5.f10_f10_musgs.I2000Clm50Fates.cheyenne_intel.clm-fates + SMS_D_Ly2.1x1_numaIA.IHistClm50BgcCropGs.cheyenne_intel.clm-ciso_bombspike1963 + SMS_Ld1.f19_f19_mg16.IHistClm40SpCruGs.cheyenne_intel.clm-40default + SMS_Ld1.f19_g17.I2000Clm50Vic.cheyenne_intel.clm-default + +Changes to tests or testing: tools testing modified to point to files in CSMDATA + +Code reviewed by: self,lamar,oleson,sacks,dlawren + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular, tools + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + + unit-tests (components/clm/src): + + cheyenne - PASS + + tools-tests (components/clm/test/tools): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_16_r262 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes! + + Summarize any changes to answers, i.e., + - what code configurations: clm4_5 and clm5_0 + - what platforms/compilers: all + - nature of change: changes answers with bug fixes in a significant way + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: oleson/csm/clm50_r243_1deg_GSWP3V2_cropopt_nsc_hksat_hist + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: + + Remove sample files, move to CSMDATA, remove sample namelist + D components/clm/tools/mkprocdata_map/clm4054_f19g16_I2000.clm2.h0.2000-01_c170430.nc + D components/clm/tools/mkprocdata_map/map_ne30np4_nomask_to_fv1.9x2.5_nomask_aave_da_c121107.nc + D components/clm/tools/mkprocdata_map/clm4054_ne30g16_I2000.clm2.h0.2000-01_c170430.nc + D components/clm/tools/mkprocdata_map/mkprocdata_map_in + +List all files added and what they do: + + A components/clm/tools/mkprocdata_map/README.filedescriptions -- Describe the files in this directory + +List all existing files that have been modified, and describe the changes: + + M components/clm/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000 - Point to files in CSMDATA rather than mkprocdata_map dir. + + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml -- Point to new v2.0 of the c13/c14 timeseries files + + M components/clm/src/biogeophys/SoilStateInitTimeConstMod.F90 -- Fix bug 2530 for organic mater influence in soil + M components/clm/src/biogeochem/DryDepVelocity.F90 ------------- Double SO2 dry deposition rate + M components/clm/src/biogeochem/CNFUNMod.F90 ------------------- Bug, 2304 for NACTIVE on history for first time-step + M components/clm/src/biogeochem/ch4Mod.F90 --------------------- Bug, 2528, floating overflow for methane (doesn't change answers) + M components/clm/src/main/clm_initializeMod.F90 ---------------- Bug, 1843, max daylength no longer hardwired to present day at initialization + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r262 +Originator(s): sacks (Bill Sacks) +Date: Fri Oct 27 10:17:54 MDT 2017 +One-line Summary: Rename atm2lnd history fields for downscaled fields, properly turn on vic for clm45, and other minor fixes + +Purpose of changes +------------------ + +(1) Rename atm2lnd history fields for downscaled fields. The downscaled + version is now the default. Non-downscaled history fields are now + noted explicitly with a "_FROM_ATM" suffix. A detailed list of + changes is given below. + +(2) Properly turn on VIC for CLM45 compsets (fixes bug 2465) + +(3) Use correct PE layouts for CISM1 + +(4) Remove CWDC_HR diagnostic field, which was always 0 (fixes bug 2502) + +(5) Turn on U10_DUST diagnostic field by default (fixes bug 2246) + +(6) Fix documentation of some variables + +Detailed list of changes related to (1): + + Rain and snow: + + Old: + - RAIN: "atmospheric rain" - NOT downscaled + - Rainf: "atmospheric rain" - NOT downscaled + - SNOW: "atmospheric snow" - NOT downscaled + - RAIN_REPARTITIONED: "atmospheric rain, after rain/snow repartitioning based on temperature" - DOWNSCALED + - SNOW_REPARTITIONED: "atmospheric snow, after rain/snow repartitioning based on temperature" - DOWNSCALED + + New: + - RAIN: "atmospheric rain, after rain/snow repartitioning based on temperature" - DOWNSCALED + - Rainf: "atmospheric rain, after rain/snow repartitioning based on temperature" - DOWNSCALED + - SNOW: "atmospheric snow, after rain/snow repartitioning based on temperature" - DOWNSCALED + - RAIN_FROM_ATM: "atmospheric rain received from atmosphere (pre-repartitioning)" - NOT downscaled + - SNOW_FROM_ATM: "atmospheric snow received from atmosphere (pre-repartitioning)" - NOT downscaled + + Air temperature: + + Old: + - TBOT: "atmospheric air temperature" - NOT downscaled + - Tair: "atmospheric air temperature" - NOT downscaled + - Tair_downscaled: "atmospheric air temperature downscaled to columns" - DOWNSCALED + + New: + - TBOT: "atmospheric air temperature (downscaled to columns in glacier regions)" - DOWNSCALED + - Tair: "atmospheric air temperature (downscaled to columns in glacier regions)" - DOWNSCALED + - Tair_from_atm: "atmospheric air temperature received from atmosphere (pre-downscaling)" - NOT downscaled + + Atmospheric pressure: + + Old: + - PBOT: "atmospheric pressure" - NOT downscaled + - Psurf: "surface pressure" - NOT downscaled + + New: + - PBOT: "atmospheric pressure at surface (downscaled to columns in glacier regions)" - DOWNSCALED + - Psurf: "atmospheric pressure at surface (downscaled to columns in glacier regions)" - DOWNSCALED + + Atmospheric longwave radiation: + + Old: + - FLDS: "atmospheric longwave radiation" - NOT downscaled + - LWdown: "atmospheric longwave radiation" - NOT downscaled + + New: + - FLDS: "atmospheric longwave radiation (downscaled to columns in glacier regions)" - DOWNSCALED + - LWdown: "atmospheric longwave radiation (downscaled to columns in glacier regions)" - DOWNSCALED + + Potential temperature: + + Old: + - THBOT: "atmospheric air potential temperature" - NOT downscaled + + New + - THBOT: "atmospheric air potential temperature (downscaled to columns in glacier regions)" - DOWNSCALED + + Specific humidity: + + Old: + - QBOT: "atmospheric specific humidity" - NOT downscaled + - Qair: "atmospheric specific humidity" - NOT downscaled + + New: + - QBOT: "atmospheric specific humidity (downscaled to columns in glacier regions)" - DOWNSCALED + - Qair: "atmospheric specific humidity (downscaled to columns in glacier regions)" - DOWNSCALED + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): +- 2192: wrong units in comment for variables qflx_ev_snow, qflx_ev_soil, + qflx_ev_h2osfc +- 2246: Turn on U10_DUST history field variable by default +- 2363: inline documentation is wrong in SoilTemperatureMod.F90 +- 2401: Need to put in an "override" for PE layouts for CISM1 +- 2465: ICLM45VIC compset doesn't actually turn VIC on +- 2502: CWDC_HR is identically zero +- 2503: Wrong units for FAREA_BURNED + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): +- Changed meaning of some atm2lnd history fields: see above + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: self; Sean Swenson did a conceptual review of the +changes in atm2lnd diagnostic fields + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - not run + + unit-tests (components/clm/src): + + cheyenne - pass + + tools-tests (components/clm/test/tools): + + cheyenne - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - not run + + regular tests (aux_clm): + + yellowstone_intel - ok + yellowstone_pgi --- ok + yellowstone_gnu --- ok + cheyenne_intel ---- ok + cheyenne_gnu ------ ok + hobart_nag -------- ok + hobart_pgi -------- ok + hobart_intel ------ ok + + ok means tests pass, answers change for some atm2lnd diagnostic + fields as noted below + +CLM tag used for the baseline comparisons: clm4_5_16_r261 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: all + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + - For most configurations: Changes diagnostic fields only (see + below for list) + - Changes CLM45 compsets with VIC: actually turns on VIC (there + are no CLM45 tests with VIC in the test suite) + + Changes the following fields: FLDS, PBOT, QBOT, RAIN, SNOW, TBOT, + THBOT: These now give downscaled versions of these fields. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Rename atm2lnd history fields for downscaled fields +M components/clm/src/main/atm2lndType.F90 + +========= Properly turn on VIC for CLM45 compsets +M components/clm/cime_config/config_component.xml + +========= Use correct PE layouts for cism1 +M components/clm/cime_config/config_pes.xml + +========= Remove CWDC_HR diagnostic field +M components/clm/src/biogeochem/CNVegCarbonFluxType.F90 + +========= Turn on U10_DUST by default +M components/clm/src/biogeophys/FrictionVelocityMod.F90 + +========= Fix various documentation +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml +M components/clm/src/biogeophys/BareGroundFluxesMod.F90 +M components/clm/src/biogeophys/WaterfluxType.F90 +M components/clm/src/biogeophys/SoilTemperatureMod.F90 +M components/clm/src/biogeophys/SoilFluxesMod.F90 +M components/clm/src/biogeophys/CanopyFluxesMod.F90 +M components/clm/src/biogeophys/SoilHydrologyMod.F90 +M components/clm/src/biogeochem/CNVegStateType.F90 + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r261 +Originator(s): sacks (Bill Sacks) +Date: Wed Oct 25 07:37:24 MDT 2017 +One-line Summary: Add option to reset snow over glacier columns + +Purpose of changes +------------------ + +We have had an option to reset snow over non-glacier columns, using the +reset_snow namelist variable. This is useful when transitioning from a +spinup with one set of atmospheric forcings to a run with substantially +different atmospheric forcings. We originally did not provide an option +to reset snow over glacier columns, because we couldn't find a +satisfactory way to determine which glacier columns should and should +not be reset. However, members of the LIWG have found that it's hard to +analyze some test runs without this option. + +This tag, therefore, provides an option to reset snow over glacier +columns, using a new namelist flag reset_snow_glc. You can optionally +provide an elevation threshold for this resetting: By setting +reset_snow_glc_ela to some elevation (in meters), only glacier columns +below this elevation get their snow packs reset. Note that you run the +risk of baking in answers with this (how much of the resulting spatial +patterns are due to your choice of where to reset snow?), but this can +still be useful in some cases. In general, this is meant for testing, +and not for "real" scientific production runs. + +Original changes were from Leo van Kampenhout, with some refactoring by +Bill Sacks. + + +Bugs fixed or introduced +------------------------ + +Known bugs introduced in this tag (include bugzilla ID): +- 2525: test_build_namelist.pl fails in clm4_5_16_r260 + (this bug existed prior to this tag, but was first discovered here) + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- New namelist variables: + - reset_snow_glc: logical; if set to .true., resets the snow pack over + glacier columns + - reset_snow_glc_ela: elevation threshold for resetting snow pack over + glacier columns + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: +- reseedresetsnow testmod turns on snow resetting over glacier points, + and so changes answers. It uses the reset_snow_glc_ela threshold that + Leo has been using. + +Code reviewed by: self, Leo van Kampenhout + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - ok (run on yellowstone) + Tests in build-namelist_test.pl pass but change answers as expected + due to new namelist options. + + NOTE: prove test_build_namelist.pl fails (see bug 2525) + + unit-tests (components/clm/src): + + cheyenne - pass + + tools-tests (components/clm/test/tools): + + cheyenne - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - not run + + regular tests (aux_clm): + + yellowstone_intel - ok + yellowstone_pgi --- ok + yellowstone_gnu --- ok + cheyenne_intel ---- ok + cheyenne_gnu ------ ok + hobart_nag -------- ok + hobart_pgi -------- ok + hobart_intel ------ ok + + ok means tests pass, NLCOMP failures as expected. Also, expected + baseline failure: + ERS_D.f19_g17.I1850Clm50BgcCrop.cheyenne_intel.clm-reseedresetsnow + + However, there were also baseline failures in these tests, due to + problems with r260: + + (1) + + SMS_Ld5.f19_g17.IHistClm50Bgc.cheyenne_intel.clm-decStart + SMS_Ld5.f19_g17.IHistClm50Bgc.yellowstone_pgi.clm-decStart + SMS_Ld5.f19_g17.IHistClm50Bgc.yellowstone_intel.clm-decStart + + These are due to problems with the baseline, in terms of which cism + history files are present. Baseline comparisons failed in the same + way when using out-of-the-box r260. The current code seems correct + in this respect, so this is just a problem with the baseline + directories. + + (2) + + SMS_D_Ly2.1x1_brazil.IHistClm50BgcQianGs.cheyenne_intel.clm-ciso_bombspike1963 + + Differences in C14 history fields. Baseline comparisons failed in + the same way when using out-of-the-box r260. I can't tell if the + baselines are correct or the trunk code is correct. I have asked + Erik to look into this. + +CLM tag used for the baseline comparisons: clm4_5_16_r260 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: Only tests with reseedresetsnow testmod + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + new climate for tests with this testmod + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Main changes +M components/clm/src/biogeophys/SnowHydrologyMod.F90 + +========= Unit tests of new changes +M components/clm/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_SnowCappingExcess.pf + +========= Pass down new arguments +M components/clm/src/main/clm_driver.F90 +M components/clm/src/biogeophys/HydrologyNoDrainageMod.F90 +M components/clm/src/biogeophys/LakeHydrologyMod.F90 + +========= New namelist variables +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml +M components/clm/bld/CLMBuildNamelist.pm + +========= Changes to reseedresetsnow testmod to turn on the new option +M components/clm/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/user_nl_clm + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r260 +Originator(s): erik (Erik Kluzek) +Date: Tue Oct 24 15:59:41 MDT 2017 +One-line Summary: Update paramater file for CLM50 as well as fates, fix a few issues + +Purpose of changes +------------------ + +Update the parameter file for CLM5.0, changing: ekc_active,ekn_active,kn_nonmyc,psi50, and stem_leaf. Dave Lawrence, +Keith Oleson, Will Wieder, and Rosie Fischer were involved in changing these parameters to increase survivability of +BDT Tropical and NDT Boreal and to slightly decrease the over-productivity of BDS boreal. + +The version of FATES used was updated to one with the same API, but updated science (science_1.3.0 api_1.0.0). + +There were a couple issues fixed as well. PTCLM was updated to fix a few issues and also allow us to test running +with an updated PTCLM user-mods-directory. So the US-UMB testing was updated to point to a freshly created directory. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2524 -- Run with decStart tests + 2523 -- Run with cnonly + 2522 -- PTCLMmkdata doesn't handle crop on or off well in latest CLM45/CLM50 + 2521 -- Add warning for when PTCLMmkdata sets MPILIB to mpi-serial by default + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + -crop option becomes a toggle for CLM_BLDNML_OPTS (so -no-crop is valid as well) + Same setup for mksurfdata.pl was introduced as well (and for PTCLMmkdata) + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): New parameter file for CLM5.0 + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: USUMB tests updated, tests for PTCLM updated + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular, tools + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS (118 compare tests fail) + + unit-tests (components/clm/src): + + cheyenne - PASS + + tools-tests (components/clm/test/tools): + + cheyenne - PASS + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - OK (one expected fail) + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_16_r259 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes for CLM50 and/or with fates + + Summarize any changes to answers, i.e., + - what code configurations: all configurations with CLM50 or CLM45 with Fates + - what platforms/compilers: All + - nature of change: Improvements in survivability of certain trees + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): PTCLM + + PTCLM to PTCLM2_171024b + +List all files eliminated: None + +List all files added and what they do: Missing file from previous tag + + A components/clm/cime_config/testdefs/testmods_dirs/clm/decStart/user_nl_cism + +List all existing files that have been modified, and describe the changes: + + M components/clm/test/tools/TSMscript_tools.sh --------------------- Update PTCLM version of mapping data being pointed to + M components/clm/test/tools/nl_files/mksrfdt_10x15_1850 ------------ Change -no_crop option to -no-crop + M components/clm/test/tools/nl_files/mksrfdt_1x1_vancouverCAN_2000 - Change -no_crop option to -no-crop + M components/clm/tools/mksurfdata_map/mksurfdata.pl ---------------- Change -no_crop option to -no-crop toggle + M components/clm/bld/CLMBuildNamelist.pm --------------------------- Change -crop option to a toggle (so -no-crop is valid) + Fix bug 2523 by setting bgc_spinup + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml --- Update parameter file for CLM50 + M components/clm/cime_config/testdefs/testmods_dirs/clm/USUMB/user_nl_clm ---- Point to c171024 version of PTCLM data + M components/clm/cime_config/testdefs/testmods_dirs/clm/USUMB/shell_commands - Point to c171024 version of PTCLM data + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r259 +Originator(s): erik (Erik Kluzek) +Date: Tue Oct 17 10:39:36 MDT 2017 +One-line Summary: Update to latest cime from cesm2_0_beta07 and config_components version 3 + +Purpose of changes +------------------ + +Update CLM to use version 3 for config_components.xml which has additional error checking of compset names. Also +update it for mosart, cism and rtm. And cime is updated to the version used in cesm2_0_beta07. There are a few +new features brought in with the latest cime that are described below. CLM now requires one and only one modifier +for what type it is in the compset name (i.e. only one "%" as in CLM45%BGC or CLM50%SP). Will now abort when +CLM build-namelist encounters a warning (after printing information on all warnings). To ignore the warnings +and continue add the new "-ignore_warnings" to CLM_BLDNML_OPTS. "-irrig" is now an option to CLM_BLDNML_OPTS +only for clm4_0, set "irrigate" namelist item in your user_nl_clm file for clm4_5 or clm5_0. By default build-namelist +sets irrigate to true for transient or present-day configurations if crop is on and clm5_0 (unless DV on). Get PTCLMmkdata fully +converted over to cheyenne, and create a new set of files for testing it's ability to create cases. Checking for +.true. or .false. in CLM build-namelist is now more robust and allows for "F" or "T" as newer FORTRAN versions do. + + +Fix several bugs as described below. PTCLM and CLM tools were both verified to work and pass testing. +The PE layout for f10 on hobart was changed to a single-node so that it would compare exactly to previous versions. +Fix a bug for NCK tests in RTM and MOSART. Get mksurfdata_map working correctly for f05. Error message when +you set finidat=' ' is more clear on what to do. You can also now do a cold-start for a hybrid case prints a warning), +but not allowed on a branch case. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2519 -- Trouble setting use_aereoxid_prog=.false./ + 2515 -- Setting finidat=' ' gives cryptic error message + 2510 -- Mapping files from the 1km grid can only be created on geyser + 2509 -- Bad mapping files for f05 resolution + 2504 -- hybrid/branch cases don't allow CLM_FORCE_COLDSTART to be on + 2494 -- MOSART test NLCOMP fails due to duplicate mosart_inparam in user_nl_mosart + 2477 -- Multiinstance mosart with REFCASE does not initialize + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + This includes an update to cime, so some behavior is a little different than before (see section below) + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + CLM now allows one and only one modifier for the type of configuration in the compset name + (i.e. CLM50%BGC or CLM45%SP (only one "%" modifier is allowed) ). "-irrig" is now only allowed as an option + to CLM_BLDNML_OPTS for clm4_0, for clm4_5/clm5_0 the handling of irrigate is handled inside CLM build-namelist. + Remove some no longer needed forcing definitions for compsets (the year range at the beginning of the compset name). + Now abort on build-namelist warnings (but adding "-ignore_warnings" option to CLM_BLDNML_OPTS allow it to run without it). + Remove compset forcings that aren't being used: 5505, C2R6, C2R8, C2R4, C1, GEOS (start of long compset names) + +Changes to CIME user interface: +- Eleminate --user-compset. Clean up caseroot directory upon failed creation. +- Check coupler fields for nan. +- New xml variable, readmode, +- xmlquery --group has been changed go xmlquery --get-group +- New case.qstatus tool. +- Autodeletion of broken case dirs. +- Add --mail-user and --mail-type to case.submit. +- Remove --user-compset from create_newcase, allow compset longname in testname argument to create_test. +- New argument to create_clone (--user-mods-dir to also point to user-mods directory that will be used) + +Changes made to namelist defaults (e.g., changed parameter values): + Correct SCRIP grid file for f05 and add mapping files for them + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: + clm-decStarts cism history is a bit different (shown as changing answers) + Allow longname in tests +- Add --pesfile option to create_test. +- New --timeout flag for wait_for_tests +- CLM now needs to define its own LII and SSP tests (they already were put in place, now it's actually using them) + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular, tools + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + (216 compare tests fail comparing to clm4_5_16_r258 tag) + + unit-tests (components/clm/src): + + cheyenne - PASS + + tools-tests (components/clm/test/tools): + + cheyenne - PASS + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + cheyenne - OK + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_16_r258 + + +Answer changes +-------------- + +Changes answers relative to baseline: No (bit for bit) + + clm/decStart tests were changed though + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): cime, cism, rtm, mosart + cime to cime5.4.0-alpha.03 + cism to cism2_1_40 + rtm to rtm1_0_63 + mosart to mosart1_0_28 + +List all files eliminated: Remove -irrig option for clm4_5/clm5_0 tests + + D components/clm/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/shell_commands + D components/clm/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/shell_commands + D components/clm/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/shell_commands + +List all files added and what they do: + + A components/clm/bld/namelist_files/LogMessages.pm - Log message, warning, exit and abort handling for perl + +List all existing files that have been modified, and describe the changes: + + Update to new PTCLM directory for testing PTCLM cases + M components/clm/test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 -- Change map_gdate + M components/clm/test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 - Change map_gdate + M components/clm/test/tools/nl_files/PTCLM_USUMB_clm4_5 --------- Change map_gdate + M components/clm/test/tools/TSMscript_tools.sh -- Change user_mods directory used for PTCLM case + + M components/clm/tools/mkmapdata/regridbatch.sh -- Get working on cheyenne + + M components/clm/bld/namelist_files/namelist_defaults_clm4_5_tools.xml - Working f05 SCRIP grid file + M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml ----- Remove irrig + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml ------- Change irrig to irrigate + add mapping files for f05 + + Set irrigate for use-cases, .true. for use_crop=T, use_cndv=F and not 1850 + M components/clm/bld/namelist_files/use_cases/2000-2100_rcp8.5_transient.xml + M components/clm/bld/namelist_files/use_cases/stdurbpt_pd.xml + M components/clm/bld/namelist_files/use_cases/2000_glacierMEC_control.xml + M components/clm/bld/namelist_files/use_cases/1850_control.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp6_transient.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp2.6_transient.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp4.5_transient.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp8.5_transient.xml + M components/clm/bld/namelist_files/use_cases/20thC_transient.xml + M components/clm/bld/namelist_files/use_cases/1850_glacierMEC_control.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp2.6_glacierMEC_transient.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp6_glacierMEC_transient.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp4.5_glacierMEC_transient.xml + M components/clm/bld/namelist_files/use_cases/glacierMEC_pd.xml + M components/clm/bld/namelist_files/use_cases/2000_control.xml + M components/clm/bld/namelist_files/use_cases/1850-2100_rcp8.5_glacierMEC_transient.xml + M components/clm/bld/namelist_files/use_cases/20thC_glacierMEC_transient.xml + + M components/clm/bld/CLMBuildNamelist.pm -- moving warnings, logging, exit, and fatal_error to LogMessages + Add -ignore_warnings, -irrig is now only for clm4_0, pass $opts to add_default, not just {test}, + use value_is_true for all logical evalutions (extend it to all T or F), warnings will all be + written out, and abort at the end (unless -ignore_warnings is used) + don't die if clm_usr_name is set and didn't find user datasets, add final_exit on completion + M components/clm/bld/unit_testers/build-namelist_test.pl - Add tests for -ignore_warnings option + handle -irrig for clm4_5 + + M components/clm/cime_config/config_compsets.xml -- Add I2000Clm50BgcCruGs compset + M components/clm/cime_config/config_pes.xml ------- Set PE count for f10 on hobart to single node + M components/clm/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm --------------- turn irrigate on + M components/clm/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm - turn irrigate on + M components/clm/cime_config/testdefs/testmods_dirs/clm/irrigOn_reduceOutput/user_nl_clm ------- turn irrigate on + M components/clm/cime_config/testdefs/testlist_clm.xml - 1x1_camdenNJ test with stub-GLC: I2000Clm50BgcCruGs + M components/clm/cime_config/config_component.xml --- Update to config_component version 3. CLM must have 1 and exactly + one modifier, move setting of -irrig for 2000 and transient compsets to inside of CLM build-namelist + remove some no longer needed forcing definitions for compsets + M components/clm/cime_config/buildnml - Print warning if branch and coldstart, allow colstart with hybrid + Add warning if doing a coldstart + + M components/clm/src/CMakeLists.txt - Add additional subdirectory for unit testing (from Bill Sacks) + + M components/clm/src/main/controlMod.F90 - Allow use_crop=F and irrigate + + M parse_cime.cs.status - Seperate out differences when baselines don't exist + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r258 +Originator(s): erik (Erik Kluzek) +Date: Fri Oct 6 22:25:29 MDT 2017 +One-line Summary: Revert change to fire, set n_melt_glcmec=10, update mosart to version that doesn't accumulate water in short rivers + +Purpose of changes +------------------ + +Revert the changes to fire that came in clm4_5_16_r257. Add some notes that clarify that the code as is, is correct. +Set n_melt_glcmec=10.0 for clm5.0 (This should have happened in the fresh snow grain size change in clm4_5_16_r256). +Update mosart to a version that doesn't accumulate water in short rivers. This is done by explicitly making sure river length +isn't smaller than a minimum value. + +Bugs fixed or introduced +------------------------ + + 2516 -- Mistaken bug for fire mortality calculations for some + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): + Changed n_melt_glcmec to 10.0d00 for clm5_0 (same as clm4_5, but double precision) + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): Some of the + fire mortality code is confusing, we added some notes to clarify that's it's correct + +Changes to tests or testing: None + +Code reviewed by: self, dlawren, oleson, swenson + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS (231 compare tests fail) + + unit-tests (components/clm/src): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_16_r257 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes! + + Summarize any changes to answers, i.e., + - what code configurations: clm45/clm50 and/or with mosart + - what platforms/compilers: all + - nature of change: small + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): mosart + mosart to rlen_min_n01_mosart1_0_26 (will bring trunk version of mosart in an upcoming tag) + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml - set +M components/clm/src/biogeochem/CNFireBaseMod.F90 --- Revert fire changes (bug 2516) add comments + use fm_droot as it's used to represent fraction of transport from livestem/livecroot to litter + or to represent the fraction of plant-tissue mortality for deadstem/deadcroot +M components/clm/src/biogeochem/CNFireLi2014Mod.F90 - Revert fire changes + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r257 +Originator(s): erik (Erik Kluzek) +Date: Fri Sep 29 10:17:36 MDT 2017 +One-line Summary: Fix two bugs found by Hui Tang, one for Carbon isotopes and one in the fire model + +Purpose of changes +------------------ + +This is a fix for two bugs found by Hui Tang. One is for Carbon isotopes where a fix that came in for +clm4_5_11_r188, used leafc for too many of the isotope flux calculation calls. This changes it so the +correct terms are used for the particular flux. + +The other fix is in the fire model where fire emissions were using the wrong fire related +mortality term for dead stem and should have been using a different type. Now it matches the +flux type, as well as the term used in combustion completness for the particular fire emission. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2517 -- Bug in CNFireFluxes for some fire fluxes + 2516 -- Leafc wrongly used in too many CIsoFluxCalc calls. + +Known bugs introduced in this tag (include bugzilla ID): (new one found) + 2518 -- --- warnings from CLM build-namelist don't get sent out of preview_namelist + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self,oleson,dlawren,Hui Tang + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + + unit-tests (components/clm/src): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + +CLM tag used for the baseline comparisons: clm4_5_16_r256 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes! + + Summarize any changes to answers, i.e., + - what code configurations: clm45/clm50 with CN and fire on, and also for carbon isotopes + - what platforms/compilers: all + - nature of change: very small impact + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: /oleson/clm50_r255_fireiso_1deg_GSWP3V1_1850 + + URL for LMWG diagnostics output used to validate new climate: +http://webext.cgd.ucar.edu/I1850/clm50_r255_fireiso_1deg_GSWP3V1_1850/lnd/clm50_r255_fireiso_1deg_GSWP3V1_1850_21_50-clm50_r255_coniso_1deg_GSWP3V1_1850_21_50/setsIndex.html + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/src/biogeochem/CNFireBaseMod.F90 --- Some fire emissions were using + fire related mortality for dead stem and should have been using a different type + it should match the one used in the combustion completeness factor and the main + type + M components/clm/src/biogeochem/CNFireLi2014Mod.F90 - Same change as above + + M components/clm/src/biogeochem/CNCIsoFluxMod.F90 -- In the fix for bug 2116 that came + in with clm4_5_11_r188, leafc was used in too many CNCIsoFluxCalc calls this corrects + it to use the correct term + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r256 +Originator(s): erik (Erik Kluzek) +Date: Wed Sep 20 15:42:17 MDT 2017 +One-line Summary: Fresh snow grain radius is temperature dependent + +Purpose of changes +------------------ + +Changes from Leo VanKampenhout to have fresh snow grain size a function of air temperature for CLM50. +Behavior is the same as before for CLM45 with fresh snow grain size a fixed parameter. For CLM50 +it's that same value (54.526) less than -30C and linear with T up to 204.526 at 0C, and 204.526 for +temperatures greater than 0C. + + +Bugs fixed or introduced +------------------------ + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + Added namelist item: fresh_snw_rds_max + +Changes made to namelist defaults (e.g., changed parameter values): + fresh_snw_rds_max is snw_rds_min for clm4_5 + fresh_snw_rds_max is 204.526 for clm5_0 + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self,L.vanKampenhout@uu.nl + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS (343 compare tests fail since namelists change) + + unit-tests (components/clm/src): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu - OK + cheyenne_intel - OK + cheyenne_gnu - OK + hobart_nag - OK + hobart_pgi - PASS + hobart_intel - PASS + +CLM tag used for the baseline comparisons: clm4_5_16_r255 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes, for clm5_0 + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: clm5_0 + - what platforms/compilers: All + - nature of change: more snow melt at expense of ice melt + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: oleson clm50_r251_SNOWGRAIN_2000 + + URL for LMWG diagnostics output used to validate new climate: + +http://webext.cgd.ucar.edu/B1850/b.e20.B1850.f09_g17.pi_control.all.196/lnd/b.e20.B1850.f09_g17.pi_control.all.196.8_27-b.e20.B1850.f09_g17.pi_control.all.195.8_27/set1/set1.html + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + + M components/clm/src/biogeophys/SnowSnicarMod.F90 -- Pass atm2lnd_inst in, make sure snw_rds isn't less than the min parameter + create a function for setting FreshSnowRadius, dependent on atm2lnd_inst (for air temperature), the function sets to min + parameter if fresh_snw_rds_max is same as min (clm45), or to min at less than -30C linear between fresh_snw_rds_max and min parameter + up to 0C, and then at fresh_snw_rds_max value for clm50. + M components/clm/src/biogeophys/AerosolMod.F90 ----- Add InitReadNML and fresh_snw_rds_max + M components/clm/src/main/clm_driver.F90 ----------- Pass atm2lnd_inst down to SnowAgeGrain + M components/clm/src/main/clm_instMod.F90 ---------- Pass NLFilename to aerosol_inst%Init + + M components/clm/bld/CLMBuildNamelist.pm - Set fresh_snw_rds_max, and add aerosol namelist + + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml --- Set fresh_snw_rds_max for clm45 and clm50 + M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml - Define fresh_snw_rds_max + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r255 +Originator(s): erik (Erik Kluzek) +Date: Mon Sep 18 21:21:29 MDT 2017 +One-line Summary: Changes to crop and enabling Carbon isotopes for crop and some miscellaneous small changes + +Purpose of changes +------------------ + +Changes for crop on as well as enabling carbon isotopes when crop is on. Fix some small answer changing issues. +Also bring in new timeseries datasets for C14 as well as now C13. The C14 dataset has hardwired latitude sectors +it uses (so previous file can NOT be used). Properly handle and update C13/C14 variables when crop is on. +Handle CIsoFluxCalc calls for a list of crop specific fields. Add cropseedc_deficit, to storvegc as well as totveg. +Send livestemc to litter for prognostic crop. Ignore downreg for carbon isotopes in Fractionation subroutine. +For dynamic roots, use rooting values on parameter dataset which is set to values from PFT=1. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2508 -- Incorrect landuse.timeseries datasets for f09 and hcru for rcp=8.5 in r254 + 2489 -- Set c/nnegcrit for clm45/clm50 (10X higher for clm45 than clm50) + 2412 -- Initialize rootfr to PFT==1 value for dynamic roots -- update params files + 2396 -- make subtraction the default behavior for clm4_5. + 2316 -- update carbon isotopes same as C12: CNVegCarbonStateType.F90 + 2211 -- Fix time used for Ciso time series + +Known bugs introduced in this tag (include bugzilla ID): + 2511 -- Overflow with Carbon isotopes + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + Change to restarts when c-isotopes on + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + New namelist items: use_c13_timeseries, atm_c13_filename + New history vars: C13_GRAINC, C13_CROPSEEDC_DEFICIT, C14_GRAINC, C14_CROPSEEDC_DEFICIT + +Changes made to namelist defaults (e.g., changed parameter values): + Set cnegcrit/nnegcrit for CLM45/CLM50 + +Changes to the datasets (e.g., parameter, surface or initial files): + New C13 and C14 timeseries files + New params files, but only answer changing part is for dynamic roots + (setup bare-soil on file to match what's used for PFT=1) + Bring in correct datasets for rcp8.5 for f09 and hcru + 1x1_numaIA 1850 and 1850-2000 transient files + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + The C13/C14 timeseries should be implemented with streams for greater flexibility, robustness, and code + reuse. The new C14 timeseries file is hardcoded for three specific latitude sectors, and thus can't use + the previous file, nor a file of a different configuration. Downreg is passed down from get_downreg_patch + in clm_driver, to CanopyFluxes to Fractionation, but no longer used (it should be removed). + + Note the following from Dave: While debugging crop isotope code, found that cpool_patch and frootc_patch + could occasionally be very small but nonzero numbers after crop harvest, which persists + through to next planting and for reasons that could not 100% isolate, caused C12/C13 ratios to occasionally + go out of bounds. Zeroing out these small pools and putting them into the flux to the atmosphere solved many + of the crop isotope problems + +Changes to tests or testing: Added some tests, two of the new tests fail due to bug 2511 + +Code reviewed by: self, koven, dlawren, dll, oleson + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS (234 comparison tests fail) + + unit-tests (components/clm/src): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu - OK + cheyenne_intel - OK + cheyenne_gnu - OK + hobart_nag - OK + hobart_pgi - OK + hobart_intel - OK + +CLM tag used for the baseline comparisons: clm4_5_16_r254 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes! + + Summarize any changes to answers, i.e., + - what code configurations: Crop, Carbon-isotopes + + - what platforms/compilers: All + - nature of change: + small change to crop with missing updates, crop with carbon-isotopes are now enabled + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: + +D components/clm/src/biogeochem/C14BompbSpikeMod.F90 --- Change name to more general + +List all files added and what they do: + +A components/clm/src/biogeochem/CNCIsoAtmTimeSeriesReadMod.F90 -- Handle time series + for both C13 and C14 + +List all existing files that have been modified, and describe the changes: + +M components/clm/src/biogeochem/CNPhenologyMod.F90 -------- Remove subtract_cropseed always do when crop on, pass c13/c14 + instances down to CNPhenology and CropPhenology. After setting C12-leafc_xfer/totvegc set the c13/c14 + leafc_xfer/totvegc as well +M components/clm/src/biogeochem/CNCStateUpdate1Mod.F90 ---- Change location of xsmrpool update. Dave added this note: + While debugging crop isotope code, found that cpool_patch and frootc_patch + could occasionally be very small but nonzero numbers after crop harvest, which persists + through to next planting and for reasons that could not 100% + isolate, caused C12/C13 ratios to occasionally go out of + bounds. Zeroing out these small pools and putting them into the flux to the + atmosphere solved many of the crop isotope problems +M components/clm/src/biogeochem/CNCIsoFluxMod.F90 --------- Add CIsoFluxCalc calls for: soilc_change, cpool_to_resp, + grainc_xfer_to_|grainc|food|seed, crop_seedc_to_leaf, grain_|curmr|xsmr, cpool_|grain|grain_storage|_gr, cpool_to_|grainc|grainc_storage, + transfer_grain_gr, grainc_storage_to_xfer, livestemc_to_litter, and if use_grainproduct for ciso-grainc_to_cropprodc/grain_mr + pass iso totvegc_path for hrv_xsmrpool_to_atm CIsoFluxCalc, section adding livestemc to litter for crop + add additional check for ciso_state(i) /= 0 for divide by check in CIsoFluxCalc +M components/clm/src/biogeochem/CNPrecisionControlMod.F90 - Handle c13/c14 TruncateCandNStates for grainc/storage/xfer, + cropseedc_deficit_patch and xsmrpool +M components/clm/src/biogeochem/CNVegCarbonStateType.F90 -- Add: C13_GRAINC, C13_CROPSEEDC_DEFICIT, C14_GRAINC, C14_CROPSEEDC_DEFICIT + restartvar calls explicit for c12, c13, c14: grainc, grainc_storage, grainc_xfer (with c13 and c14 for ciso) + add cropseedc_deficit, to storvegc as well as totvegc, fix bug 2316 make cisotopes the same as C12 +M components/clm/src/biogeochem/CNDriverMod.F90 ----------- Pass more c13/c14 instances down to CNPhenology calls +M components/clm/src/main/controlMod.F90 ------------------ Add namelist items: use_c13_timeseries, atm_c13_filename + remove abort when crop and use_c13/use_c14 is on +M components/clm/src/main/clm_initializeMod.F90 ----------- Add call to C13_init_TimeSeries +M components/clm/src/biogeophys/PhotosynthesisMod.F90 ----- Handle C13 timeseries (call C13TimeSeries), put C14 bombspike data in + hard-wired latitude sectors, ignore downreg for carbon isotopes in Fractionation subroutine +M components/clm/src/biogeophys/RootBiophysMod.F90 -------- Use parameters for roots from params file for bare-soil rather than + an explicit if statement for it + +M components/clm/bld/CLMBuildNamelist.pm ------------------- Add cnegcrit/nnegcrit, allow crop and C-isotopes to be + on at the same time, add c13 time-series +M components/clm/bld/unit_testers/build-namelist_test.pl --- Change testing for time-series + +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml ----- New datasets for atm_c14_filename, and + atm_c13_filename, new paramdata files, set cnegcrit/nnegcrit, flanduse_timeseries for f09 and hcru @ rcp=8.5 +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml --- Add: use_c13_timeseries, atm_c13_filename + update similar documenation on c14 bombspike +M components/clm/bld/test_build_namelist/t/input/namelist_definition_clm4_5_test.xml -- Same as changes above + +M components/clm/cime_config/testdefs/testmods_dirs/clm/ciso_bombspike1963/user_nl_clm - Set use_c13_timeseries=T +M components/clm/cime_config/testdefs/testlist_clm.xml - Change two ciso transient tests to include crop, add transient + crop ciso test + +M components/clm/cime_config/testdefs/ExpectedTestFails.xml -- Add expected fails for new ciso overflow bug 2511 + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r254 +Originator(s): erik (Erik Kluzek) +Date: Fri Sep 1 00:09:25 MDT 2017 +One-line Summary: Update surface datasets, and point to new CMIP6 population density dataset + +Purpose of changes +------------------ + +Update all surface datasets to new versions that have updated soil albedo, and use latest PFTCFT files. Also +get mksurdata_map fully working on cheyenne for batch mode. Point to latest CMIP6 population density dataset +for historical case, this is with HYDE3.2 data. New fsurdat files for 16pft are with irrigation on. If ask for +irrig=F and 16pft won't be able to find any files. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2479 --- Irrigation is occurring in non-prognostic-crop runs + +Known bugs introduced in this tag (include bugzilla ID): (found ...) + 2506 --- ntree used before it's set in pftconMod.F90 2017-08-25 + 2505 --- Set stream_year_first_urbantv/last for CLM4.5 just for consistency 2017-08-25 + 2504 --- hybrid/branch cases don't allow CLM_FORCE_COLDSTART to be on 2017-08-18 + 2503 --- Wrong units for FAREA_BURNED 2017-08-16 + 2502 --- CWDC_HR is identically zero 2017-08-16 + 2500 --- ne30 case fails on hobart_nag due to floating overflow + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): -irrig .true. is needed without -crop + fsurdat files without crop are all just with irrigation on. + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): Datasets + +Changes to the datasets (e.g., parameter, surface or initial files): new fsurdat, landuse.timeseries, popdens + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers: none + +Changes to tests or testing: none + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + + unit-tests (components/clm/src): + + cheyenne - PASS + + tools-tests (components/clm/test/tools): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu - OK + cheyenne_intel - OK + cheyenne_gnu - OK + hobart_nag - OK + hobart_pgi - OK + hobart_intel - OK + +CLM tag used for the baseline comparisons: clm4_5_16_r253 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes! + + Summarize any changes to answers, i.e., + - what code configurations: CLM45/CLM50 + - what platforms/compilers: All + - nature of change (roundoff; larger than roundoff/same climate; new climate): + similar climate CLM4.5/CLM5.0 surface datasets change with latest soil albedo and small changes form raw PFTCFT files. + also an updated population-density dataset used for historical + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/tools/mksurfdata_map/mksurfdata.pl -- Add rundir option, if 16pfts add Irrig to filename + M components/clm/tools/mksurfdata_map/Makefile.data -- Get working on cheyenne or yellowstone + + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml ------- Default resolution and sim_year, + set irrig to .true. when crop off, update fsurdat, flanduse_timeseries, stream_fldfilename_popdens + M components/clm/bld/namelist_files/namelist_defaults_clm4_5_tools.xml - Update soil-color and PFTCFT files + + M components/clm/bld/CLMBuildNamelist.pm --- check irrig for fsurdat files, fsurdat with 16pft is with irrig=T + make sure set only set irrigate when use_crop on + M components/clm/bld/unit_testers/build-namelist_test.pl -- More tests w clm5_0, irrigate=T set without crop + M components/clm/bld/unit_testers/NMLTest/CompFiles.pm ---- Add more documentation + + M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm - Update finidat with + updated fsurdat file + + M components/clm/src/biogeophys/PhotosynthesisMod.F90 -- FPSN_W? variables are default off, and instant averaged + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r253 +Originator(s): erik (Erik Kluzek) +Date: Fri Aug 4 20:23:25 MDT 2017 +One-line Summary: Check on reasonable import/export from CLM, check ndep units from input file + +Purpose of changes +------------------ + +Do some reasonable physical checks on the import/export state to/from CLM. Checking for NaN's and +that solar should be greater or equal to zero, LW down, specific humidity greater than zero. +Check the units on the input nitrogen deposition file and if per year divide by seconds per year, +leave alone if per seconds, and die if units aren't recognized. Increase the tolerence for warnings +for Nitrogen, Carbon, and soil energy balance. Add missing MPI broadcasts for two ndep namelist variables. +Fix an LII test that was failing. Change the PE layout for f4x5 grids for yellowstone and cheyenne. +Add -die_on_duplicate option to parse_cime.cs.status and have summary option add notes about expected fails. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): [If none, remove this line] + 2498 -- missing MPI bcast + 2499 -- Update finidat file so LII case will work + 2484 -- Check for units of ndep only divide by seconds in a year if units are per year + +Known bugs introduced in this tag (include bugzilla ID): [If none, remove this line] + NGEET/fates-clm/#16 -- FATES changes answers at a level of at least roundoff when the PE layout changes + NGEET/fates-clm/#15 -- CLM-FATES can't restart when PE layout is change + ESMCI/cime/#1793 ----- Run time error for mpi-serial case on cheyenne_intel when created with aux_clm create_testd + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + units for ndep input files can either be g(N)/m2/yr or g(N)/m2/s, will now abort for anything else + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: Added test with CMIP6 ndep file + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - PASS + + unit-tests (components/clm/src): + + cheyenne - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu - OK + cheyenne_intel - OK + cheyenne_gnu - OK + hobart_nag - OK + hobart_pgi - OK + hobart_intel - OK + +CLM tag used for the baseline comparisons: clm4_5_16_r253 + + +Answer changes +-------------- + +Changes answers relative to baseline: No bit-for-bit (although FATES tests change because of the PE layout change) + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: Add test mods for case with CMIP6 ndep forcing that has different units/variable name + +A + components/clm/cime_config/testdefs/testmods_dirs/clm/clm50CMIP6frc + +List all existing files that have been modified, and describe the changes: + +M components/clm/cime_config/config_pes.xml ------------- Update f45 PE layout for yellowstone/cheyenne +M components/clm/cime_config/testdefs/testlist_clm.xml -- Add clm50CMIP6frc test +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm - Update finidat file so + LII test will pass + +M components/clm/src/biogeochem/CNBalanceCheckMod.F90 - Lower amount of warnings written out for C and N by order of mag. +M components/clm/src/biogeochem/CropType.F90 ---------- Add if-masterproc to write statement +M components/clm/src/biogeophys/BalanceCheckMod.F90 --- Lower amount of warnings written out for soil energy balance +M components/clm/src/cpl/lnd_import_export.F90 -------- Add checking for physically bad import or export data + ensuring no NaN's are exchanged, solar >= 0, LW-dn > 0, q > 0 +M components/clm/src/main/ncdio_pio.F90.in ------------ Remove write to log file from all tasks +M components/clm/src/main/ndepStreamMod.F90 ----------- Do mpi_bast for ndep_varlist/ndep_taxmode, check units + of input ndep variable and divide by seconds in a year if g(N)/m2/yr, but leave alone for g(N)/m2/s otherwise die + +M parse_cime.cs.status - Add -die_on_duplicate option, and have summarize option make notes about expected fails + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r252 +Originator(s): erik (Erik Kluzek) +Date: Mon Jul 24 16:57:42 MDT 2017 +One-line Summary: Update parameter file for some crop albedo issues, and fix a bug in urban albedo for nightime + +Purpose of changes +------------------ + +Bring in a new CLM50 parameter file that updates a few fields for prognostic crop with affect on crop albedo +(rholnir,taulnir,taulvis,xl). Bring in changes to fix urban albedo for nighttime from Keith Oleson. Rather than set +albedo's for the urban canyon all to 1.0, set them to the viewfactors, as that will result in combined albedo of +one, whereas the previous way ended up with albedo's greater than one. + +Here's a description from Keith about the change in urban albedo. " For diffuse radiation, which is +independent of solar zenith angle, the road albedos appear to be exactly equal to the road-sky view +factor. And the wall albedos are equal to the wall-sky view factor. So the albedos are the albedo +of the surface (1.0) times the appropriate view factor. This makes sense. All incident radiation +entering the canyon should be reflected to the sky and the contribution of each surface is according +to the view factor of each surface to the sky as determined by the height to width ratio. The view +factors of the two walls and the road to the sky sums to 1.0. So setting the diffuse albedos to +these values when the sun is below the horizon results in a scaled diffuse albedo of 1.0. For direct +radiation, it's more complicated because the solar zenith angle is involved when running the +radiation model. However, it seems reasonable to assume the same albedos for direct as for diffuse." + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2492 -- Urban scalings can lead to albedo values greater than 1 + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files):New params file for CLM50 + Updates rholnir,taulnir,taulvis,xl for prognostic crop fields + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self,oleson + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne ---- PASS (60 clm50 tests are different as expected) + + unit-tests (components/clm/src): + + cheyenne ---- PASS + + regular tests (aux_clm): (31 Clm45 tests are different than baseline in cpl hist files for: + l2x_Sl_avsdr ("dr" and "df" and "av" and "an") as expected) + + yellowstone_intel - OK + yellowstone_pgi --- OK + yellowstone_gnu --- OK + cheyenne_intel ---- OK + cheyenne_gnu ------ OK + hobart_nag -------- OK + hobart_pgi -------- OK + hobart_intel ------ OK + + Tests: ERS_Ld5_Mmpi-serial.1x1_vancouverCAN.I1PtClm45SpGs.cheyenne_intel.clm-default, + ERS_Ld5_Mmpi-serial.1x1_vancouverCAN.I1PtClm45SpGs.yellowstone_intel.clm-default + show: FSR, FSRND, and FSRVD different + +CLM tag used for the baseline comparisons: clm4_5_16_r251 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes for CLM50, and for CLM45 when coupled to CAM + + Summarize any changes to answers, i.e., + - what code configurations: CLM50 (CLM45 when coupled to CAM and albedos passed to coupler for any case) + - what platforms/compilers: all + - nature of change: similar climate + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: + oleson/b.e20.B1850.f09_g17.pi_control.all.186.alb + + URL for LMWG diagnostics output used to validate new climate: + +http://webext.cgd.ucar.edu/B1850/b.e20.B1850.f09_g17.pi_control.all.186.alb/lnd/b.e20.B1850.f09_g17.pi_control.all.186.alb.17_36-b.e20.B1850.f09_g17.pi_control.all.186.17_36/setsIndex.html + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml - Updated params file for CLM50 + M components/clm/src/biogeophys/UrbanAlbedoMod.F90 --------------- Fix bug 2492. Set albedo's of + urban surfaces to view factors, by default and for solar zenith angles below horizon. + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r251 +Originator(s): erik (Erik Kluzek) +Date: Fri Jul 14 01:38:38 MDT 2017 +One-line Summary: Update mksurfdata_map for soil depth/color, add new mapping files + +Purpose of changes +------------------ + +Bring in new soil color (from Peter Lawrence) dataset for mksurfdata_map. Also bring +in a new soil depth dataset that uses a mask for when soil depth > 0. Bring in a version +of PTCLM that's working with this cime. + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): + New mapping files for soil depth for mksurfdata_map + New soil color data for mksurfdata_map + New soil depth dataset on the map defined by when soil depth > 0 + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers: None + +Changes to tests or testing: None + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: tools + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + tools-tests (components/clm/test/tools): + + yellowstone - PASS + cheyenne - PASS + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - OK + +CLM tag used for the baseline comparisons: none + + +Answer changes +-------------- + +Changes answers relative to baseline: No, bit-for-bit (CLM code wasn't changed) + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): PTCLM + + PTCLM to PTCLM2_170706 + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/tools/mkmapdata/regridbatch.sh -- go back to using 8 processors + M components/clm/tools/mkmapdata/mkmapdata.sh ---- add mapping for 5x5min_ORNL-Soil, + change check for $MPIEXEC, so ignores arguments + M components/clm/tools/mksurfdata_map/mksurfdata.pl -- Remove extra "_" in "__CMIP6_" + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml -- New + 5x5min-ORNL-Soil mapping files + M components/clm/bld/namelist_files/namelist_defaults_clm4_5_tools.xml - SCRIP + grid file for 5x5min-ORNL-Soil, change soildepth mask to ORNL-Soil + update soil color and soil depth datasets + M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml - Add + ORNL-Soil mask + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r250 +Originator(s): erik (Erik Kluzek) +Date: Thu Jul 13 13:54:13 MDT 2017 +One-line Summary: Update finundation dataset, new fsurdat files with updated soil color + and soil depth, update mosart areas, fix cheyenne_gnu + +Purpose of changes +------------------ + +Update all fsurdat datasets with updated soil color and soil depth. Soil color as modified by Peter Lawrence. +Soil depth was modified to use a mask for soil depth>0 which makes the minimum soil depth 3cm (model still has +a minimum of 40cm). Also updated area's for the mosart routing file (the previous areas were off by up to about 1%). +the update to the area's will influence fluxes. Also fix a problem so that cheyenne_gnu will work (remove pure +attribute from two functions). + +Also bring in the updated finundation inversion from Sean Swenson. This will change the methane output +significantly for CLM50BGC cases. The previous inversion file was incorrect and shouldn't be used! The new file is also +at a higher resolution 1-degree rather than 2-degree. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2493 (gnu6.3.0 compiler doesn't like "pure" functions that use outside modules, especially public ones) + +Known bugs introduced in this tag (include bugzilla ID): + 2491 (Error in Banddiagonal in latest CESM simulation) (found in Cecile's coupled simulation) + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): Just datasets see below + +Changes to the datasets (e.g., parameter, surface or initial files): Update all fsurdat and the + stream_fldfilename_ch4finundated file + + fsurdat files have soil color and soil depth updated. The finundated file is now at f09 resolution + rather than f19, and the previous file was incorrect. + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + regular tests (aux_clm): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu - OK + cheyenne_intel - OK + cheyenne_gnu - OK + hobart_nag - OK + hobart_pgi - OK + hobart_intel - OK + +CLM tag used for the baseline comparisons: clm4_5_16_r249 + + +Answer changes +-------------- + +Changes answers relative to baseline: + + Summarize any changes to answers, i.e., + - what code configurations: CLM45/CLM50 or with MOSART + - what platforms/compilers: all + - nature of change: similar climate, methane outputs are substantially changed + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): mosart + mosart update to mosart1_0_26 + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/src/biogeophys/SnowHydrologyMod.F90 -- Remove pure attribute from OverburdenCompactionVionnet2012 + M components/clm/src/biogeophys/IrrigationMod.F90 ----- Remove purse attribute from PointNeedsCheckForIrrig + + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml -- Update all fsurdat files and stream_fldfilename_ch4finundated + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r249 +Originator(s): sacks (Bill Sacks) +Date: Thu Jul 6 14:32:40 MDT 2017 +One-line Summary: All new compsets, reworked test lists, and related fixes + +Purpose of changes +------------------ + +The changes here were a joint effort between Dave Lawrence, Ben Andre, Erik +Kluzek, Mariana Vertenstein and Bill Sacks + +(1) All new compset aliases, with the following changes: + + (a) Most compset aliases are now for CLM5, with fewer CLM45 compsets and + even fewer CLM40 compsets. + + (b) Compset aliases now use capitalization of only the first letter of each + piece, to avoid the alphabet soup problem. For example, + IHistClm50BgcCrop + + (c) Some other tweaks have been made to compset aliases, such as always + listing the time period and Sp (satellite phenology) explicitly + + (d) Compsets use GSWP3 forcing unless the alias specifies otherwise + + (e) Compsets use CISM2%NOEVOLVE - and so use glc_mec in CLM - unless the + alias has Gs (for GLC - stub) + + (f) An evolving ice sheet (CISM2%EVOLVE) is now denoted by having a final + 'G' in the compset alias + +(2) Completely reworked test lists: + + (a) Use new aliases + + (b) Changed most tests to CLM5 + + (c) Merged the aux_clm45 and aux_clm40 test categories into aux_clm + + (d) Removed the 'null' test category, which was used for SBN tests + + (e) Some minor additional tweaks to the aux_clm test list to ensure + appropriate coverage and remove some redundant tests + + (f) For a few testmods directories, removed some settings that had nothing + to do with those testmods (use_dynroot, use_hydrstress) + +(3) Fixed VIC: + + (a) Previously, VIC compsets were not actually turning VIC on; now they are + + (b) Fixed namelist defaults for VIC with CLM50 + +(4) Updated RTM and MOSART externals: changed their test lists and fixed a + MOSART bug + +(5) Updated CISM external; this changes answers for CISM when ice evolution is + turned off, due to changing the lnd -> glc mapping in this case + +(6) Point to a CIME branch that fixes some bugs + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): +- 2473: Change order of tests run with the LII test +- 2474: CLM50 CN compsets seem to be set up wrong +- 2480: vichydro option doesn't work with CLM50 as it needs bedrock off and + lower_boundary_condition=3 (with aquifer layer) + +CIME Issues fixed (include issue #): I think some issues are fixed here, but I'm +not sure which ones + +Known bugs introduced in this tag (include bugzilla ID): +- 2485: CLM's 'ed' testlist still has old-style compsets +- 2486: Failure in camdenNJ test in prebeta test list +- 2488: Floating overflow in SoilBiogeochemNitrifDenitrifMod.F90 + (newly-discovered, but presumably existed in previous tags) +- 2489: Clm45BgcCrop case dies due to negative leafn + (newly-discovered, but presumably existed in previous tags) + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): +- All new compset aliases + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- All new compset aliases + +Changes made to namelist defaults (e.g., changed parameter values): +- Changed some defaults when running with VIC + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): +- All new aliases means baseline comparisons all BFAIL + +Changes to tests or testing: +- Massive overhaul - see notes elsewhere in this ChangeLog entry + +Code reviewed by: This was a joint effort by Dave Lawrence, Ben Andre, Erik +Kluzek, Mariana Vertenstein and Bill Sacks. Various pieces were reviewed by +different people in this list. + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - ok + + pass except for 'compare file.*DNE', presumably due to new tests added + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu - ok + cheyenne_intel - ok + hobart_nag - ok + hobart_pgi - ok + hobart_intel - ok + + Most tests pass; baseline comparisons BFAIL. Bugs opened (and Expected Fails + list updated) for remaining failures. + + Ran most testing on r85975; just ran relevant tests on latest revision with + changed compset (changed IHistClm50BgcGs to IHistClm50BgcQianGs) + +CLM tag used for the baseline comparisons: N/A + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: All tests BFAIL due to new compset + aliases. Because of this, I'm not completely sure of the answer changes, but I + think they are: + - Tests with CISM2%NOEVOLVE change answers in fields on the glc grid due + to new CISM external + - CLM50 tests with Vic change answers because now they're actually using VIC + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + New climate for tests that change answers + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): +- cime +- rtm +- mosart +- cism + +List all files eliminated: + +========= No longer need these testmods +D components/clm/cime_config/testdefs/testmods_dirs/clm/cropf10IC/include_user_mods +D components/clm/cime_config/testdefs/testmods_dirs/clm/cropf10IC/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/cropf10IC +D components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC/README +D components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC/include_user_mods +D components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC +D components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/shell_commands +D components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v5/user_nl_datm +D components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v5 +D components/clm/cime_config/testdefs/testmods_dirs/clm/snowlayers_12/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/snowlayers_12/include_user_mods +D components/clm/cime_config/testdefs/testmods_dirs/clm/snowlayers_12 + +List all files added and what they do: + +========= Replaces af_bias_v5 +A components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/user_nl_clm +A components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/shell_commands +A components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v7/user_nl_datm +A components/clm/cime_config/testdefs/testmods_dirs/clm/af_bias_v7 + +List all existing files that have been modified, and describe the changes: + +========= Reworked set of compsets and aliases +M components/clm/cime_config/config_compsets.xml + +========= Reworked test list as described above +M components/clm/cime_config/testdefs/testlist_clm.xml + +========= Stop setting glc_snow_persistence_max_days in glcMEC testmods. It made + sense to set this for testing when most of our tests used CLM45, + because the default snow persistence was 20 years. But for CLM50 the + default snow persistence is 0, so it no longer makes sense to set this + value specially for testing. +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC/user_nl_clm +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_long/user_nl_clm + +========= Apply CN and VIC for CLM50 +M components/clm/cime_config/config_component.xml + +========= Use compatible settings for VIC +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml +M components/clm/bld/CLMBuildNamelist.pm +M components/clm/bld/unit_testers/build-namelist_test.pl + +========= Fix for new glacier region +M components/clm/cime_config/usermods_dirs/cmip6_glaciers/user_nl_clm + +========= Make SSP work with mosart instead of rtm +M components/clm/cime_config/SystemTests/ssp.py + +========= Change order of LII test to support re-creating initial conditions + files (rather than requiring a separate SMS_Ln1 test) +M components/clm/cime_config/SystemTests/lii.py +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/README + +========= New, compatible initial conditions +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm +M components/clm/cime_config/testdefs/testmods_dirs/clm/interp_f19_noncrop/user_nl_clm + +========= No longer set use_dynroot = .true., use_hydrstress = .false. +M components/clm/cime_config/testdefs/testmods_dirs/clm/cropMonthOutput/user_nl_clm + +========= No longer set use_hydrstress = .false. +M components/clm/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm +M components/clm/cime_config/testdefs/testmods_dirs/clm/clm50KitchenSink/user_nl_clm + +========= Update ExpectedTestFails list for new tests; new failures are: + SMS_Ld5_D_P24x1.f10_f10_musgs.IHistClm50Bgc.hobart_nag.clm-decStart + ERP_D_P24x1.f10_f10_musgs.IHistClm50Bgc.hobart_nag.clm-decStart + ERP_D.f10_f10_musgs.IHistClm50Bgc.yellowstone_gnu.clm-decStart + ERS_Ly5_P72x1.f10_f10_musgs.IHistClm45BgcCrop.cheyenne_intel.clm-cropMonthOutput +M components/clm/cime_config/testdefs/ExpectedTestFails.xml + +========= Update documentation of system testing +M .ChangeLog_template + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r248 +Originator(s): sacks (Bill Sacks) +Date: Wed Jun 28 15:50:13 MDT 2017 +One-line Summary: Melt most ice runoff + +Purpose of changes +------------------ + +Up until now, excess snow in CLM (accumulated beyond the snow capping limit) has +been sent to the ocean as an ice runoff flux. However, this caused problems in +some regions, in that it cooled an already-cold ocean, leading to excessive sea +ice growth. Keith Lindsay, Marika Holland and others suggested changing CLM so +that it sends this flux as liquid rather than ice runoff - having the atmosphere +melt the ice rather than having the ocean do so. These changes are implemented +here. + +This has now been tested in many fully-coupled simulations, and it indeed solves +the problem of excessive sea ice growth, without having any noticeable +detrimental effects on other aspects of the simulation. + +Specifically, this affects ice runoff from (a) glacier_mec columns outside of +Greenland and Antarctica, and (b) all other column types (vegetated, etc.). We +still send ice runoff from Greenland and Antarctica to simulate the ice calving +flux that occurs in those regions. In addition, we still send an ice runoff flux +generated from dynamic landunit adjustments. + +This new behavior is used by default in CLM50, but not in CLM45. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- New namelist variable: melt_non_icesheet_ice_runoff +- New namelist variable: glacier_region_ice_runoff_behavior + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + +Changes to tests or testing: none + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - ok + + tests pass, namelists change as expected + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + cheyenne_intel - ok + hobart_nag --- ok + hobart_pgi --- ok + hobart_intel - ok + + ok means tests pass, answers change as expected + + Ran most testing on melt_ice_runoff_n05_clm4_5_16_r247; ran hobart on latest + (which included a commit to split long lines) + +CLM tag used for the baseline comparisons: clm4_5_16_r247 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: All CLM50 cases + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + new climate + + This changes runoff terms (liquid and ice) and the sensible heat flux sent + to the atmosphere. In addition, there are limited changes in some + methane-related terms; this is presumably due to the dependence of + finundated on TWS, and the fact that TWS changes due to the changes in + these runoff terms. + + There are also diffs in x2r_Flrl_irrig for this test (and the similar + yellowstone test): + ERS_D_Ld10.T31_g37_gl4.IGHISTCLM50.cheyenne_intel.clm-glcMEC_decrease. It + makes sense that there would be x2r irrig diffs due to diffs in volr, but + I was surprised that this test had any irrigation. It turns out this is + due to bug #2479. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: b.e20.B1850.f09_g17.pi_control.all.149 + + URL for LMWG diagnostics output used to validate new climate: ??? + + Note that the climate tests were done on an earlier, kludgey + implementation. I have verified that the latest implementation is bit-for-bit + with that earlier implementation via a 5-year run of compset + 1850_DATM%GSWP3_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2%NOEVOLVE_SWAV at + resolution f09_g16, producing annual-average cpl history files. (For the + original, used + https://svn-ccsm-models.cgd.ucar.edu/clm2/branch_tags/melt_ice_runoff_orig_tags/melt_ice_runoff_orig_n01_clm4_5_16_r246.) + There were differences in a few CLM diagnostic fields, as expected (because I + have tweaked some diagnostic fields in the latest version), but the cpl + avghist files were bit-for-bit. + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Main changes as described above +M components/clm/src/main/lnd2atmMod.F90 +M components/clm/src/main/lnd2atmType.F90 + +========= Changed long name in some runoff terms: removed statements that they + do not include QSNWCPICE, because now they *do* include the *melted* + portion of QSNWCPICE +M components/clm/src/biogeophys/WaterfluxType.F90 + +========= New glacier region-specific behavior +M components/clm/src/main/glcBehaviorMod.F90 +M components/clm/src/main/test/glcBehavior_test/test_glcBehavior.pf +M components/clm/src/main/clm_driver.F90 + +========= New namelist flags controlling the behavior +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml +M components/clm/bld/CLMBuildNamelist.pm +M components/clm/src/main/clm_instMod.F90 + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r247 +Originator(s): sacks (Bill Sacks) +Date: Mon Jun 26 19:52:20 MDT 2017 +One-line Summary: New GLACIER_REGION field with CISM domain split in two + +Purpose of changes +------------------ + +In an upcoming tag, we'll need a separate GLACIER_REGION for the purpose of +determining where ice runoff should be melted: we do not want this melt to +happen over Greenland itself, but we do want it to happen in peripheral parts of +the CISM domain (and in particular, we want it to happen over the Canadian +archipelago, which is within the CISM domain, and thus was within the +"Greenland" GLACIER_REGION). (We still need a GLACIER_REGION that encompasses +areas outside Greenland itself in case ice extent grows a bit beyond the current +boundaries. So we truly need two separate GLACIER_REGIONs for (a) Greenland +itself, and (b) peripheral areas of the CISM domain.) This tag updates the +surface datasets and related fields to have this extra GLACIER_REGION. + +In addition to updating the GLACIER_REGION raw data file, this also introduces a +new regridding method that is applied to GLACIER_REGION: this takes the maximum +value from any source point (NOT the dominant value). This is important for the +new GLACIER_REGION, where we want a destination (CLM) cell to be considered in +region 2 (Greenland itself) if ANY overlapping source points are in region +2. This means that the ordering of regions in the GLACIER_REGION raw data file +is important: preference will be given to higher-numbered regions. + +Note that I just changed surface datasets that had time stamp 170428 or +later. This excluded some older single point datasets, for which the new glacier +region doesn't matter anyway: +- surfdata_0.125x0.125_simyr2000_c150114.nc +- surfdata_0.125x0.125_mp24_simyr2000_c150114.nc +- surfdata_1x1_smallvilleIA_78pfts_simyr2000_c160127.nc +- surfdata_1x1_smallvilleIA_78pfts_simyr1850_c160127.nc +- surfdata_1x1_tropicAtl_16pfts_simyr1850_c160127.nc (used in tropicAtl_subset testmod) + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): +- There are some additional subtleties now for setting up a run with different + glacier domains (e.g., a paleoclimate run) + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): +- New surface datasets - just differ in GLACIER_REGION + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): +- There are some additional subtleties now for setting up a run with different + glacier domains (e.g., a paleoclimate run) + +Changes to tests or testing: none + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - ok + + PASSed except expected failures: + - baseline comparisons failed for mksurfdata_map tests + - PTCLM tests failed as expected + + Also ran mksurfdata_map unit tests: + - new-style (cmake / pfunit-based): pass + - old-style: same failures as on trunk + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - pass + yellowstone_pgi - pass + yellowstone_gnu (clm45 only) - pass + cheyenne_intel - pass + hobart_nag --- pass + hobart_pgi --- pass + hobart_intel - pass + +Ran tests on glacier_region_canada_n03_clm4_5_16_r246 +- After that, modified the default mksurfdata_map namelist used for testing: + pointed to updated file + + + +CLM tag used for the baseline comparisons: clm4_5_16_r246 + + +Answer changes +-------------- + +Changes answers relative to baseline: NO - bit-for-bit + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: + +List all files added and what they do: + +========= Get mkindexmapMod under some pfunit-based unit tests - required + stubbing out a bunch of netcdf stuff +A components/clm/tools/mksurfdata_map/src/unit_test_stubs +A components/clm/tools/mksurfdata_map/src/unit_test_stubs/mkncdio.F90 +A components/clm/tools/mksurfdata_map/src/test/mkindexmap_test +A components/clm/tools/mksurfdata_map/src/test/mkindexmap_test/test_mkindexmap.pf +A components/clm/tools/mksurfdata_map/src/test/mkindexmap_test/CMakeLists.txt + +========= Add get_max_indices and associated unit tests +A components/clm/tools/mksurfdata_map/src/test/mkgridmap_test +A components/clm/tools/mksurfdata_map/src/test/mkgridmap_test/CMakeLists.txt +A components/clm/tools/mksurfdata_map/src/test/mkgridmap_test/test_mkgridmap.pf + +List all existing files that have been modified, and describe the changes: + +========= New raw dataset for glacier region +M components/clm/bld/namelist_files/namelist_defaults_clm4_5_tools.xml +M components/clm/tools/mksurfdata_map/mksurfdata_map.namelist + +========= Get mksurfdata_map pfunit-based unit tests passing with new cime +M components/clm/tools/mksurfdata_map/src/README.unit_testing +M components/clm/tools/mksurfdata_map/src/CMakeLists.txt + +========= Add get_max_indices and associated unit tests; use get_max_indices to + regrid glacier region +M components/clm/tools/mksurfdata_map/src/mkgridmapMod.F90 +M components/clm/tools/mksurfdata_map/src/mkindexmapMod.F90 +M components/clm/tools/mksurfdata_map/src/mkglacierregionMod.F90 +M components/clm/tools/mksurfdata_map/src/test/CMakeLists.txt + +========= Allow building mkindexmapMod for unit tests - required stubbing out a + bunch of netcdf stuff +M components/clm/tools/mksurfdata_map/src/mkncdio.F90 + +========= Point to new surface datasets +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml + +========= Extended namelist array for new region +M components/clm/cime_config/SystemTests/lvg.py + +========= Removed duplicate makefile rules +M components/clm/tools/mksurfdata_map/Makefile.data + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r246 +Originator(s): sacks (Bill Sacks) +Date: Wed Jun 14 12:40:31 MDT 2017 +One-line Summary: Update to latest cime + +Purpose of changes +------------------ + +Main change is to update to the latest version of cime. + +One of the changes in this cime version is that component-specific system tests +(e.g., LII, SSP) can now be defined in the component rather than in cime. So +this tag defines LII and SSP in CLM. In addition, this adds an LVG test (Land +Virtual Glaciers), which verifies that adding virtual glacier columns doesn't +change answers. + +Another significant change in this cime version is that the lnd -> glc +downscaling (i.e., remapping) method has been changed to be bilinear with a +later conservation correction, rather than area-conservative. This leads to +smooth fields on the CISM grid. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- New drv_in namelist variable 'glc_renormalize_smb' - controls whether to apply + global corrections to the downscaled lnd -> glc smb for conservation + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: +- Moves LII and SSP test definitions into CLM +- Adds new test type, LVG +- Adds an LVG test + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - pass + yellowstone_gnu (clm45 only) - pass + cheyenne_intel - ok + hobart_nag --- pass + hobart_pgi --- ok + hobart_intel - pass + + ok means tests pass, some answers change as noted below + +CLM tag used for the baseline comparisons: clm4_5_16_r245 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: see below + - what platforms/compilers: see below + - nature of change (roundoff; larger than roundoff/same climate; new climate): see below + + (1) Changes answers for cases with CISM, due to new downscaling + method. These changes show up only for long tests with CISM, and are + potentially climate-changing: + + FAIL SMS_Lm37.T31_g37_gl4.IG1850CLM50.cheyenne_intel.clm-glcMEC_long BASELINE clm4_5_16_r245 + FAIL SMS_Lm37.T31_g37_gl4.IG1850CLM50.yellowstone_intel.clm-glcMEC_long BASELINE clm4_5_16_r245 + + (2) Changes answers for hobart-pgi tests, due to new version of the pgi + compiler on hobart. Magnitude of the change not investigated. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): +- cime: cime5.3.0-alpha.21 -> cime5.3.0-alpha.27 + +List all files eliminated: none + +List all files added and what they do: + +========= CLM-specific system tests are now defined here rather than in + cime. Also, added an LVG test type: Land Virtual Glacier. +A components/clm/cime_config/config_tests.xml +A components/clm/cime_config/SystemTests +A components/clm/cime_config/SystemTests/lii.py +A components/clm/cime_config/SystemTests/ssp.py +A components/clm/cime_config/SystemTests/lvg.py + +List all existing files that have been modified, and describe the changes: + +========= Ran through -cleanxml, and added an LVG test +M components/clm/cime_config/testdefs/testlist_clm.xml + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r245 +Originator(s): sacks (Bill Sacks) +Date: Wed Jun 14 12:13:54 MDT 2017 +One-line Summary: Only adjust glc_mec topographic heights if glc_do_dynglacier is true + +Purpose of changes +------------------ + +Two changes in this tag: + +(1) Only adjust glc_mec topographic heights if glc_do_dynglacier is true (this + namelist variable is controlled by the GLC_TWO_WAY_COUPLING xml + variable). Previously, CLM updated its glacier topographic heights even if + this variable was false (so we were not updating areas from CISM). Bill + Lipscomb and Jeremy Fyke agreed a while ago that we should change this. None + of us could remember why we initially set it up to always update topographic + heights, but we felt that it's more intuitive to avoid updating topographic + heights if we're not updating glacier areas. + + Note that setting GLC_TWO_WAY_COUPLING=FALSE is *not* a common thing to do, + so this change does not affect most cases. (The typical way of doing one-way + coupling with CISM is to use CISM2%NOEVOLVE, which turns off ice evolution + but keeps GLC_TWO_WAY_COUPLING=TRUE in order to update CLM's glacier areas + and topographic heights at initialization.) + +(2) Adds some user mods and testmods (currently unexercised) for cmip6 + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: New test mods directories, currently not exercised (I'll add tests soon) + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + cheyenne_intel - ok + hobart_nag --- ok + hobart_pgi --- ok + hobart_intel - ok + + ok means tests pass, a few expected baseline comparison failures + +CLM tag used for the baseline comparisons: clm4_5_16_r244 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: Cases with GLC_TWO_WAY_COUPLING=FALSE + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + new climate + + This affects tests with glcMEC_changeFlags and glcMEC_spunup_1way testmods + + Also, NLCOMP failures for a few tests, I think explainable by the process Erik + used to update some testmods to get LII tests passing: + FAIL SMS_D_Ln1.f09_g17.ICLM45BGC.yellowstone_gnu.clm-defaultf09IC NLCOMP + FAIL ERP.f19_g17_gl4.IG1850CLM45.cheyenne_intel.clm-glcMEC_spunup_1way NLCOMP + FAIL SMS_D_Ln1.f19_g17_gl4.IG1850CLM45.cheyenne_intel.clm-glcMEC_spunup_1way NLCOMP + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: + +========= Renamed +D components/clm/cime_config/usermods_dirs/clm/clm5_OutputCrop/user_nl_clm +D components/clm/cime_config/usermods_dirs/clm/clm5_OutputCrop/shell_commands +D components/clm/cime_config/usermods_dirs/clm/clm5_OutputCrop +D components/clm/cime_config/usermods_dirs/clm + +List all files added and what they do: + +========= Top-level cmip6 usermods directory, which will include other usermods + directories needed for the cmip6 runs +A components/clm/cime_config/usermods_dirs/cmip6/include_user_mods +A components/clm/cime_config/usermods_dirs/cmip6 + +========= Renamed from clm5_OutputCrop; also added some glacier output fields + needed for cmip6 runs +A components/clm/cime_config/usermods_dirs/cmip6_output/user_nl_clm +A components/clm/cime_config/usermods_dirs/cmip6_output/shell_commands +A components/clm/cime_config/usermods_dirs/cmip6_output/README +A components/clm/cime_config/usermods_dirs/cmip6_output + +========= Turns on virtual glacier columns over Antarctica. This is desired by + the LIWG for cmip6 runs, so that we can have the Antarctica output + that would be needed to later run an ice sheet model over + Antarctica. However, it comes with a 10% performance cost. +A components/clm/cime_config/usermods_dirs/cmip6_glaciers/user_nl_clm +A components/clm/cime_config/usermods_dirs/cmip6_glaciers + +========= Test mod that allows testing the cmip6 usermods (currently not + exercised with any tests) +A components/clm/cime_config/testdefs/testmods_dirs/clm/cmip6/include_user_mods +A components/clm/cime_config/testdefs/testmods_dirs/clm/cmip6 + +========= Test mod that allows running the new LVG (virtual glaciers) test + (currently unexercised) +A components/clm/cime_config/testdefs/testmods_dirs/clm/no_vector_output/README +A components/clm/cime_config/testdefs/testmods_dirs/clm/no_vector_output/user_nl_clm +A components/clm/cime_config/testdefs/testmods_dirs/clm/no_vector_output/include_user_mods +A components/clm/cime_config/testdefs/testmods_dirs/clm/no_vector_output + +List all existing files that have been modified, and describe the changes: + +========= Only adjust topographic heights if glc_do_dynglacier is true +M components/clm/src/main/TopoMod.F90 +M components/clm/src/main/test/topo_test/test_topo.pf +M components/clm/src/main/glc2lndMod.F90 + +========= Add _musgs to f10_f10 grid +M components/clm/cime_config/testdefs/ExpectedTestFails.xml + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r244 +Originator(s): erik (Erik Kluzek) +Date: Fri Jun 9 14:26:07 MDT 2017 +One-line Summary: Update cime and cism externals, changes answers for IG compsets, test g17 grids, fix a few issues, update mksurfdata_map + +Purpose of changes +------------------ + +Update the cime version which includes some important updates. Remove lt_archive, new script query_config +to query compsets and grids etcetera. Force user to always use case.submit rather than allow them to submit +to batch queue on their own. Some updates to handling of namelist items in user_nl_clm. All grids now contain +a mask variable. Also fixes a couple glitches from the previous version, see bugs fixed below. + +Update cism which changes answers (for cases running with CISM) as 4km grid was changed. + +Fix some small issues with CLM. Fix interpolation issue with GSSUN and GSSHA, use shr_mpi needed for unit-testing, and +fix an issue with a use of MCT routines for clm40. + +Several updates to mksurfdata_map, fixing problems, starting to get it working on cheyenne, and upgrading to latest +CMIP6 PFT datasets from Peter Lawrence. + +-Update cime and cism. +-Unit tests moved to cime/scripts/fortran_unit_testing/. +-Include Jim Edward's configcompsetupdate changes here. +-Convert mosart half-degree file from NetCDF-4 to NetCDF-3. +-Change grids in test lists so that mask is added to grids that need it (i.e. f45_f45 becomes f45_f45_mg37). +-Add note about supported compset IGM1850GSWCLM50BGCCROP for f09_g17, f19_g17. +-Use grids back to g16 as g17 domain files aren't there. +-Get LII tests working. +-Rerun the list of tests that failed, see if works again because of a system issue. +-use old g16 mask for CLM40 tests. +-Add CMIP5/CMIP6 names to surfdata file creation. +-Bring in mksrfunreplu branch. +-New rawdata PFT datasets from Peter. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): [If none, remove this line] + 2468 GSSUN/GSSHA interp issue + 2440 change to orderedPoints for clm40 as well + 2425 mksurfdata_map changes from Sean didn't get incorporated + 2419 Irrigated areas are low in mksurfdata_map + 2399 Problem with urban points with latest mksurfdata_map +CIME Issues fixed (include issue #): [If none, remove this line] + #1215 -- (in this version of cime) TestStatus sometimes needs to have write permission added + #1155 -- manage_case doesn't work (renamed to query_config) + #848 -- ./xmlquery --list-all doesn't work (refactored) + +Known bugs introduced in this tag (include bugzilla ID): + 2471 PTCLM doesn't work + 2470 CLM is getting the mask from the clm namelist_defaults rather than from top level scripts + 2469 Cleanup restartvar_{DIMS}d_{TYPE} to ONLY be valid for a 1d interface + 2467 Case on non-year boundary dies with error about ignoring ic_date for a crop case, even though for a branch or hybrid case + 2465 ICLM45VIC compset doesn't actually turn VIC on + 2464 allowlakeprod are outputing standard variables instead of the "lake" specific versions... + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + + cime update brought in quite a few changes +- Add skip-preview-namelist to case.submit and case_run. + - Renamed manage_case to query_config. + - manage_case -> query_config + --compset -> --compsets + --machine -> --machines + added 'all' option for --compsets + added 'current' and to --machines + - Remove all references to lt_archive which will not be supported in + CESM2.0. + - Add Support for '+=' in Namelists. + - Add --component Option to preview_namelist. + - Add Support of true and false in Namelist. + - Force user to always go through case.submit. + - Adds support for namelist entries of the form foo(3) = 'a' + - esmf_logging (and therefore drv_in) are now optional + - New run time XML variable: ESMF_LOGFILE_KIND + - New --answer flag to create_newcase + -Update so that all relevent grids contain a mask variable. + - Add preview_run to case.run + +Changes made to namelist defaults (e.g., changed parameter values): Added mapping files for 0.25x0.25_MODIS + +Changes to the datasets (e.g., parameter, surface or initial files): Just to datasets to create surface datasets + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + - Use ESMF7 on yellowstone and cheyenne. + - Big cs.status upgrade. + - Add --input-dir argument to create_test + +Changes to tests or testing: + Change most gx1v6 masks to gx1v7 + Keep clm40 tests at gx1v6 + +Code reviewed by: self, jedwards (config), mvertens, sacks (unit-tests) + +Did you follow the steps in .CLMTrunkChecklist: Yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + tools-tests (components/clm/test/tools): + + yellowstone - OK + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - FAIL + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu (clm45 only) - OK + cheyenne_intel - OK + hobart_nag --- OK + hobart_pgi --- PASS + hobart_intel - PASS + +CLM tag used for the baseline comparisons: clm4_5_16_r243 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes for IG compsets with active glacier model + + Summarize any changes to answers, i.e., + - what code configurations: Any with CISM2 + - what platforms/compilers: All + - nature of change: minor +Changes answers for cases with CISM2 at 4km (the default resolution for CISM2 cases) +- Even changes answers for standard one-way coupled cases (CISM2%NOEVOLVE) +- Fields on the CISM grid will have DIMSIZEDIFF +- Fields sent to CLM have roundoff-level differences +- time variable changes for all cases with CISM + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): cime, cism, mosart + cime to cime5.3.0-alpha.21 + cism to cism2_1_33 + mosart to mosart1_0_24 + +List all files eliminated: + + D components/clm/tools/SVN_EXTERNAL_DIRECTORIES + +List all files added and what they do: + + M components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC/README --- Add description of this testmods + and how to update the finidat file for it + A components/clm/test/tools/tests_pretag_cheyenne_nompi ---- Add test list for cheyenne + +List all existing files that have been modified, and describe the changes: + + M components/clm/test/tools/TCBCFGtools.sh - Source $INITMODULES + M components/clm/test/tools/test_driver.sh - Add cheyenne, set INITMODULES + M components/clm/test/tools/TSMCFGtools.sh - Handle CSMDATA + M components/clm/test/tools/nl_files/gen_domain.ne30.runoptions - Use CSMDATA for path to mapping file + M components/clm/test/tools/nl_files/gen_domain.T31.runoptions -- Use CSMDATA for path to mapping file + + M components/clm/tools/mkmapdata/regridbatch.sh ---------------- Set PBS for cheyenne, increase regrid_num_proc to 36 + M components/clm/tools/mkmapdata/mkmapdata.sh ------------------ Increase REGRID_PROC to 36, show defaults in --help, + change so -b means run with mpi, also create 0.25x0.25_MODIS maps, add cheyenne, rm hopper + M components/clm/tools/mksurfdata_map/Makefile.data ------------ Add global-present-T42 + M components/clm/tools/mksurfdata_map/src/mkharvestMod.F90 ----- Change harvest_fieldnames and string_undef + M components/clm/tools/mksurfdata_map/src/mkgridmapMod.F90 ----- Add gridmap_areaave_scs interface which + multiplys weight by ratio of source over destination weight (set to zero if destination weight is zero) + M components/clm/tools/mksurfdata_map/src/mkpftMod.F90 --------- Use gridmap_areaave_scs interface rather than default + one, passing down source weight of pctnatveg_i and desitination weight of pctnatveg_o (both mulitipled by 0.01) + if zeroing out also set pctnatveg_o, pctcrop_o, pct_nat_pft_o, pct_cft_o to zero, and first entry of pct_nat_pft_o + and pct_cft_o to 100 + M components/clm/tools/mksurfdata_map/mksurfdata_map.namelist -- Update with new files + M components/clm/tools/mksurfdata_map/mksurfdata.pl ------------ Add cmip_series to output filenames, use vegtyp to get harvest files, + + M components/clm/tools/mksurfdata_map/landuse_timeseries_hist_78pfts_simyr1850-2015.txt - Update with new datafiles. Note, each + year is repeated once to point to same data (to be used for harvesting). This allows harvest files to be seperate. + + M components/clm/bld/unit_testers/build-namelist_test.pl --------------- Don't test 0.25x0.25 grid + M components/clm/bld/namelist_files/namelist_defaults_clm4_5_tools.xml - Add 0.25x0.25 MODIS mapping file, harvest, PFT, LAI, and soil-color + are 0.25x0.25_MODIS, harvest files are: mksrf_fvegtyp, Update: LAI, soil-color, and PFT files, remove harvest files + M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml ----- Add 0.25x0.25 to hgrid and res, add 2015 to sim_year, and + 1980-2015 to sim_year_range, + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml ------- Add 0.x25x0.25_MODIS mapping files + + M components/clm/cime_config/config_compsets.xml ------- Changes from Jim Edwards to update to version 2.0 which will do xmllint checking + on the file, add for f09, f19 IGM1850GSWCLM50BGCCROP compsets + + M components/clm/cime_config/testdefs/testlist_clm.xml - Add SMS _Ln1 tests to correspond to each LII test (to make updating finidat files + for LII tests easier, update grids to include mask when needed, and update most g16 mask tests to g17 (except clm40 tests which + need to remain at g16) + M components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC/user_nl_clm ------- Update finidat file, set use_init_interp to True + and add notes on how to update it + M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm - Update finidat file, set use_init_interp to True + and add notes on how to update it + M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/README ------ Add notes on how to update the finidat file + + M components/clm/SVN_EXTERNAL_DIRECTORIES - Point to PTCLM here + + M components/clm/src_clm40/main/GetGlobalValuesMod.F90 - Change mct_gsmap_OP to mct_gsmap_orderedPoints (bug 2440) + M components/clm/src_clm40/main/ncdio_pio.F90.in ------- Change mct_gsmap_OP to mct_gsmap_orderedPoints (bug 2440) + M components/clm/src/biogeochem/CNSharedParamsMod.F90 -- Use shr_mpi_bcast rather than straight MPI (important for new unit tests) + M components/clm/src/README.unit_testing --------------- Updated notes on how to do it from Bill Sacks + M components/clm/src/biogeophys/PhotosynthesisMod.F90 -- Set switchdim=T for GSSUN/GSSHA (bug 2468) + M components/clm/src/CMakeLists.txt -------------------- Add include(CIME_initial_setup) + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r243 +Originator(s): andre (Benjamin Andre,UCAR/CSEG,303-497-1391) +Date: Tue May 23 16:27:42 MDT 2017 +One-line Summary: History output cleanup from Dave Lawrence + +Purpose of changes +------------------ + +* Reduce default history output by setting numerous variables to + default=inactive, limiting some 3d vars to active soil layers only. + +* Update default history output for CLM5. + +* Added diagnostic new output for DWT_WOOD_PRODUCTC_GAIN_PATCH, + GS_MOL, lake_icefracsurf_col, h2osoi_liq_tot_col, h2osoi_ice_tot_col + +* Remove double accounting for CNSoy fixation when FUN is on. + +* Bug fixes to allow landunit-level and column-level averaging and + vector output using the hist_type1d_pertape namelist option (LAND + for land-unit, COL for column-level). Note that if a user asks for + a variable at a subgrid level that is not available at that subgrid + level, the model will crash ungracefully. An example would be + asking for TOT_WOODPRODC at the land-unit level when this variable + is only available at the grid cell level, or asking for H2OSOI at + the pft-level when H2OSOI is a column-level variable. Code may be + added in a future tag that will inform the user of the error. + +* Add usermods dir for recommended clm5 crop default output. To use + the usermod when creating a new case: + + ./create_newcase --compset HIST_DATM%GSWP3_CLM50%BGC-CROP_SICE_SOCN_MOSART_CISM2_SWAV \ + --user-mods-dir clm/clm5_OutputCrop \ + ... machine, compiler, grid, case name, etc... + + +Bugs fixed or introduced +------------------------ + +None, but see note below in testing about c14 bombspike test. + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + + The default history output has been reduced. You may need to + explicitly request fields of interest from the namelist. + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: unknown + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: Dave Lawrence, Ben Andre + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - unit tests pass + + unit-tests (components/clm/src): + + yellowstone - all tests pass + + tools-tests (components/clm/test/tools): + + yellowstone - n/a, not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - n/a, not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + cheyenne_intel - ok, see note below + hobart_nag - ok + hobart_pgi - ok + hobart_intel - ok + +CLM tag used for the baseline comparisons: clm4_5_16_r242, no + yellowstone intel baselines were generated for clm4_5_16_r242 + + Baselines comparisons for clm45/clm5 tests show: + 1. changes in fields sizes (expected, restrict vertical fields to nlevsoi) + + 2. different fields on current and baseline files (expected, new default active/inactive) + + 3. no RMS differences, except the following tests: + + These tests failed baseline comparisons with RMS differences in + testing due to the soy nitrogen double accounting fix. + + ERP_P60x2_Lm36.f10_f10.ICRUCLM50BGCCROP.cheyenne_intel.clm-clm50cropIrrigMonth_interp + ERS_Ly3.f10_f10.I1850CRUCLM50BGCCROP.cheyenne_intel.clm-clm50KSinkMOut + ERS_Ly5_P60x1.f10_f10.IHISTCLM50BGCCROP.cheyenne_intel.clm-cropMonthOutput + + ERP_P60x2_Lm36.f10_f10.ICRUCLM50BGCCROP.yellowstone_intel.clm-clm50cropIrrigMonth_interp + ERS_Ly3.f10_f10.I1850CRUCLM50BGCCROP.yellowstone_intel.clm-clm50KSinkMOut + ERS_Ly5_P60x1.f10_f10.IHISTCLM50BGCCROP.yellowstone_intel.clm-cropMonthOutput + + The ciso-c14 bombspike1963 test failed baseline test with RMS + differences in C14_* fields on cheyenne_intel. This did not have + differences when tested against r273 and yellowstone_intel. This + seems to be intermintent, there was at least one test run with + r242 cheyenne_intel where this passed without RMS differences. + + SMS_D_Ly2.1x1_brazil.IHISTCLM50BGC.cheyenne_intel.clm-ciso_bombspike1963 + + + +Answer changes +-------------- + +Changes answers relative to baseline: some clm5 compsets + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + + - what code configurations: removal of double accounting for soy + nitrogen fixation from clm5 crop runs with fun active. See tests + above. + + - what platforms/compilers: all + + - nature of change (roundoff; larger than roundoff/same climate; + new climate): unknown, presumed larger than roundoff same + climate. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? n/a + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: n/a + + URL for LMWG diagnostics output used to validate new climate: n/a + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: + +New usermods with default output for clm5 crop runs + A clm/cime_config/usermods_dirs/clm/clm5_OutputCrop + A clm/cime_config/usermods_dirs/clm/clm5_OutputCrop/user_nl_clm + A clm/cime_config/usermods_dirs/clm/clm5_OutputCrop/shell_commands + +List all existing files that have been modified, and describe the changes: + + M clm/cime_config/config_component.xml - update component description from Erik Kluzek + +Set history fields active/inactive: + M clm/src/biogeochem/CNVegCarbonStateType.F90 + M clm/src/biogeochem/CNVegNitrogenStateType.F90 + M clm/src/biogeochem/CNVegNitrogenFluxType.F90 + M clm/src/biogeochem/CropType.F90 + M clm/src/biogeophys/EnergyFluxType.F90 - don't output btran unless hydrstress active + M clm/src/biogeophys/TemperatureType.F90 + MM clm/src/biogeophys/HumanIndexMod.F90 + M clm/src/biogeophys/SoilHydrologyType.F90 + M clm/src/biogeophys/SolarAbsorbedType.F90 + M clm/src/biogeophys/CanopyStateType.F90 + M clm/src/biogeophys/SurfaceRadiationMod.F90 + M clm/src/biogeophys/WaterfluxType.F90 - variable renaming + M clm/src/biogeophys/SoilStateType.F90 + +New diag output, set default active/inactive fields: + M clm/src/biogeochem/CNVegCarbonFluxType.F90 + M clm/src/biogeochem/CNProductsMod.F90 + M clm/src/biogeophys/PhotosynthesisMod.F90 + M clm/src/biogeophys/LakeStateType.F90 + M clm/src/biogeophys/LakeTemperatureMod.F90 + M clm/src/biogeophys/HydrologyNoDrainageMod.F90 - vertically summed water state calc + M clm/src/biogeophys/WaterStateType.F90 + + +Default active/inactive history fields, restrict output to nlevsoi: + M clm/src/biogeochem/ch4Mod.F90 + M clm/src/soilbiogeochem/SoilBiogeochemStateType.F90 + M clm/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 + M clm/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 + M clm/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 + M clm/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 + + +FUN Soy Nitrogen Fixation double accounting: + M clm/src/biogeochem/CNDriverMod.F90 + +Subgrid mapping: + M clm/src/main/histFileMod.F90 + M clm/src/main/subgridAveMod.F90 + + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r242 +Originator(s): erik (Erik Kluzek) +Date: Sun May 21 21:16:34 MDT 2017 +One-line Summary: Use finundated streams for CLM50, and use ndep if it comes from cpl + +Purpose of changes +------------------ + +For methane, read in inversion for TWS to Prigent Satellite dataset from a streams file for CLM50. For +CLM45 still read in ZWT inversion parameters from the surface dataset. You can read it from the streams +file if you provide it to the namelist. Answers change for CLM50BGC compsets because of this change to +methane. The change does affect results outside of methane after enough time. + +Add option to use nitrogen deposition sent from the coupler rather than from datasets (from mvertens). + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + bug 2462 -- TWS restart + bug 2457 -- remove FIND_HIST + bug 2454 -- species masterlist confusion + bug 2443 -- ndep + bug 2456 -- rm extra settings + bug 2463 -- T42 SP dataset + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): New namelist item + for finundated streams stream_fldfilename_ch4finundated. It can be used for both TWS_inversion + which is now the CLM50 default, or the ZWT_inversion (CLM45 default), but by default CLM45 + is reading ZWT inversion parameters from the surface dataset + +Changes made to namelist defaults (e.g., changed parameter values): ZWT_inversion for CLM45 and TWS_inversion for CLM50 + for inundated fraction + +Changes to the datasets (e.g., parameter, surface or initial files): Add 2000 T42 fsurdata file + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: Add two new tests + Add test for hourly radiation with lightning resolution at half-degree + And test with reseeding and reset of snow + +Code reviewed by: self,mvertens + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - OK (94 compare tests FAIL) + + unit-tests (components/clm/src): + + yellowstone - PASS + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - Didn't run + yellowstone_pgi - OK + yellowstone_gnu (clm45 only) - OK + cheyenne_intel - OK + hobart_nag --- PASS + hobart_pgi --- PASS + hobart_intel - OK + +CLM tag used for the baseline comparisons: clm4_5_16_r241 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes, CLM50 + + Summarize any changes to answers, i.e., + - what code configurations: CLM50 (with finundated streams for TWS_inversion) + - what platforms/compilers: All + - nature of change: similar climate, but methane changes (which does feedback into system) + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: None + +List all files added and what they do: Add new tests + + A components/clm/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/shell_commands + A components/clm/cime_config/testdefs/testmods_dirs/clm/rad_hrly_light_res_half/user_nl_datm + A components/clm/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/user_nl_clm + A components/clm/cime_config/testdefs/testmods_dirs/clm/reseedresetsnow/include_user_mods + +List all existing files that have been modified, and describe the changes: + + M components/clm/bld/CLMBuildNamelist.pm -------------------- Remove fin_use_fsat, set finundation_method + and get finundated streams file if TWS_inversion, add ch4finundated namelist group + M components/clm/bld/unit_testers/build-namelist_test.pl ---- Add test for change to finundated if not methane + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml --- Remove extra settings of use_init_interp, + add T42 present day fsurdat file, remove fin_use_fsat, set finundation_method to TWS_inversion for CLM50 + and ZWT_inversion for CLM45, set finundation_res=1.9x2.5 and set stream_fldfilename_ch4finundated file for it + M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml - Add: stream_fldfilename_ch4finundated, finundation_res + remove fin_use_fsat, correct finundation_method documentation + + M components/clm/cime_config/config_compsets.xml ------- Add IGMCRUCLM50SP, IGMCRUCLM50BGCROP compsets + M components/clm/cime_config/testdefs/testlist_clm.xml - Change prealpha/prebeta yellowstone_intel/gnu tests to cheyenne + add new tests for reseedresetsnow and rad_hrly_light_res_half + + M components/clm/src/main/clm_instMod.F90 -------- Pass NLFilename down to ch4 Init + M components/clm/src/main/clm_varctl.F90 --------- Add ndep_from_cpl variable + M components/clm/src/main/clm_driver.F90 --------- If ndep_from_cpl is true don't do ndep_interp + M components/clm/src/main/clm_initializeMod.F90 -- If ndep_from_cpl is true don't do ndep_init and ndep_interp + M components/clm/src/main/histFileMod.F90 -------- Add error check if field name is too long + M components/clm/src/biogeophys/WaterStateType.F90 - Add TWS to restart file + + M components/clm/src/cpl/clm_cpl_indices.F90 --- Set ndep_from_cpl based on existance of Faxa_nhx and Faxa_noy + M components/clm/src/cpl/lnd_import_export.F90 - Set forc_ndep_grc if ndep_from_cpl is set, convert units + + M components/clm/src/biogeochem/SpeciesNonIsotopeType.F90 --- Add trim's to strings to make sure blanks aren't added + M components/clm/src/biogeochem/ch4Mod.F90 ------------------ Pass NLFilename to Init, add ch4findstream data and Init to it + Remove fws_a/b/hist, remove fin_use_fsat use finundation_mtd Call ch4findstream%CalcFinundated is finundated streams are being + used (stream_fldfilename_ch4finundated is set), or if finundation_mtd_h2osfc, + M components/clm/src/biogeochem/ch4FInundatedStreamType.F90 - Add UseStreams method, get streams working properly and + M components/clm/src/biogeochem/SpeciesIsotopeType.F90 ------ Add trim for strings to make sure blanks don't happen + M components/clm/src/biogeochem/ch4varcon.F90 --------------- Remove fin_use_fsat + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r241 +Originator(s): sacks (Bill Sacks) +Date: Tue May 16 20:43:43 MDT 2017 +One-line Summary: Fix ch4 subtle dependence on processor count + +Purpose of changes +------------------ + +When we moved to using interpolated initial conditions in most cases, long tests +that change processor counts (ERP, PEM) began to fail (bug 2458). I tracked this +problem down to annsum_npp, annsum_counter, and specifically bug 1597. + +I found that, in both the original finidat and finidat_interp_dest, we have: + +- For coltype = 1, counter can be 0, 3600 or 5400 + +- For coltype = 200-something (crop), counter is always 5400 + +- For other coltypes, counter = 0 (but these shouldn't matter) + +My best guess is that there is some interaction between (1) the history of an +initial conditions file, and (2) dynamic landunits, which causes annsum_counter +to differ by column. Specifically, with (1): I think that problems arise when an +initial conditions file has (at some point in its history) arisen from a run +that didn't run for a complete year; e.g., this can happen in the course of +making an interp'ed initial conditions file - for which we typically run for one +or a few time steps. This can lead to a misalignment of the resetting of +annsum_counter relative to when dynamic landunits kick in, and thus the counter +can differ for different columns. + +This tag fixes the problem by making each column dependent on its own count, +rather than using the count from the first column on that MPI task. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): +- 1597: awkward conditionals to determine end of year in CN AnnualUpdate +- 2458: ERP clm5 restart failure in clm4_5_16_r237 + +Known bugs introduced in this tag (include bugzilla ID): [If none, remove this line] +- https://github.com/NCAR/CLM/issues/7 : CN annsum_counter can trigger mid-year, + and at different times for different columns + + Decision in talking with Erik and Keith was that we would not try to resolve + this right now - it seems that it can cause a bit of confusion, but no + scientific problems as far as we can tell. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: Erik; conceptually reviewed by Keith + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + cheyenne_intel - pending; I'll check them post-tag and open an issue if any fail + hobart_nag --- ok + hobart_pgi --- not run + hobart_intel - ok + + ok means tests pass, some baselines fail as expected + +CLM tag used for the baseline comparisons: clm4_5_16_r240 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: Many configurations, when run for at least a year + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + Larger than roundoff; expected to be same climate, but not investigated carefully. + + Answer changes can appear whenever we have an initial conditions file + where different columns have different values of the annsum_counter + restart field. This is the case for present-day restart files, as well as + at least one year-1850 restart file + (clmi.I1850CRUCLM45BGC.0241-01-01.1.9x2.5_g1v6_simyr1850_c170308.nc). + + The impact of this problem is expected to be small, at least if the + differences in annsum_counter values are small (which they are for the two + initial conditions files I have checked, and I expect this is the case for + others, too): In this case, the impact is that some annually-accumulated + fields reach their end-of-year mark a few time steps too early or late. + + However, I have not investigated the impact of this bug fix carefully. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Main changes +M components/clm/src/biogeochem/CNAnnualUpdateMod.F90 + +========= New function to create a sub-filter based on an existing filter and a + column-level logical array +M components/clm/src/main/filterColMod.F90 +M components/clm/src/main/test/filter_test/test_filter_col.pf + +========= Remove no-longer-failing tests +M components/clm/cime_config/testdefs/ExpectedTestFails.xml + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r240 +Originator(s): sacks (Bill Sacks) +Date: Mon May 15 14:48:22 MDT 2017 +One-line Summary: Make glc_dyn_runoff_routing real-valued + +Purpose of changes +------------------ + +The glc_dyn_runoff_routing variable tracks which CLM grid cells overlap +fully-coupled glc (CISM) grid cells, and which do not: In those that do not, CLM +needs to send the snow capping flux directly to runoff. Previously, this value +was a logical. However, we (Bill Lipscomb and Bill Sacks) realized that this +really needs to be real-valued - having a value between 0 and 1 where a CLM cell +partially overlaps the CISM domain. This is needed for complete conservation +when we are running with a fully-coupled (two-way-coupled) glc component. + +This changes answers for cases with two-way-coupled CISM, but does NOT change +answers for the typical one-way-coupled (%NOEVOLVE) case. + +Main changes are from Bill Lipscomb. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): +- There is some duplicate logic between CLM and the coupler in determining the + fraction of the CLM grid cell that overlaps with the active glc + domain. Ideally, we'd move all of the relevant logic into the coupler and + avoid needing it in CLM. See the TODO note in glc2lndMod.F90 + +Changes to tests or testing: none + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + cheyenne_intel - ok + hobart_nag --- ok + hobart_pgi --- not run + hobart_intel - ok + + ok means tests pass, baselines fail as expected + +CLM tag used for the baseline comparisons: clm4_5_16_r239 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: cases with CISM two-way coupled (i.e., without %NOEVOLVE) + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + Larger than roundoff, but only changes answers around the margin of + Greenland, so expected to be same climate + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Main changes, as described above +M components/clm/src/main/test/topo_test/test_topo.pf +M components/clm/src/main/glc2lndMod.F90 +M components/clm/src/biogeophys/GlacierSurfaceMassBalanceMod.F90 + +========= Add a test to the xfail list which fails sporadically due to bug 2461 +M components/clm/cime_config/testdefs/ExpectedTestFails.xml + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r239 +Originator(s): sacks (Bill Sacks) +Date: Sat May 13 20:35:52 MDT 2017 +One-line Summary: Avoid division by zero in snow WindDriftCompaction + +Purpose of changes +------------------ + +Tweak the equations in WindDriftCompaction to avoid division by 0, to fix bug +2460. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): +- 2460: Floating point trap in FWAMIP compset + +Known bugs introduced in this tag (include bugzilla ID): +- 2461: Multi-instance tests failing sporadically + This has actually been an issue for the last few tags, likely related to bug + 2289 - default finidat_interp_dest file name should have instance number + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: Dave Lawrence + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + cheyenne_intel - ok + Did not do baseline comparisons for cheyenne tests + hobart_nag --- ok + hobart_pgi --- not run + hobart_intel - ok + + ok means tests pass, baseline comparisons fail for clm50 tests as expected + +CLM tag used for the baseline comparisons: clm4_5_16_r238 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: All CLM50 + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + roundoff + + If bitwise differences were observed, how did you show they were no worse + than roundoff? + + via analysis of the change: the new equation is algebraically identical to + the old; essentially we now have X*Y/Z rather than X/(Z/Y) + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Main change, as described above +M components/clm/src/biogeophys/SnowHydrologyMod.F90 + +========= Note sporadic multi-instance failure; remove a test from the xfail + list that is now passing +M components/clm/cime_config/testdefs/ExpectedTestFails.xml + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r238 +Originator(s): andre (Benjamin Andre,UCAR/CSEG,303-497-1391) +Date: Sat May 13 11:45:15 MDT 2017 +One-line Summary: ED is now an external library 'fates' + +Purpose of changes +------------------ + +The ongoing evolution of the 'ED' library is being done by +NGEE-Tropics as 'FATES'. This change removes the 'ED' directory and +replace it with link an external release of fates. + +The primary changes are to finish creation of an interface layer to +separate fates from CLM. There are also numerous science improvements +in the linked fates library. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): 2459 - patch from Erik Kluzek + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +Changes made to namelist defaults (e.g., changed parameter values): + + * ED has been completely rebranded as fates. This includes: + * New/renamed compsets - ICLM45ED is now ICLM45FATES, ICLM50FATES. + * Renamed name list variables: + * use_ed --> use_fates + * use_ed_spitfire --> use_fates_spitfire + + * New namelist variable: fates_paramfile, this can point to either + the clm parameter file, or a standalone fates parameter file + depending on user preference. All fates dimensions and variables + are namespaced by 'fates_'. + + * Fates can not restart and interpolate from a CLM-{SP,CN,BGC} + initial conditions file. It must be run in cold start or restart + from a CLM-fates restart file. + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + +Changes to tests or testing: + + * Add tests to aux_clm45 using the fates compsets and renamed the ed + test mods to fates and fatesFire. + + * Added the cheyenne_intel test list to aux_clm45 + + * all namelist tests are expected to fail because of use_ed -> use_fates rename. + +Code reviewed by: + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + build-namelist tests: + + yellowstone - unit tests pass + + unit-tests (components/clm/src): + + yellowstone - all tests pass + + tools-tests (components/clm/test/tools): + + yellowstone - n/a not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - n/a not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - pass + yellowstone_pgi - pass + yellowstone_gnu (clm45 only) - pass + cheyenne_intel - [ experimental, see xfails list ] pass w/ xfails + hobart_nag - pass w/ xfails + hobart_pgi - not run per CLM-CMT discussion, see bugz 2447, 2455 + hobart_intel - pass + +CLM tag used for the baseline comparisons: clm4_5_16_r237 + + +Answer changes +-------------- + +Changes answers relative to baseline: answer changing for ED/fates + compsets, but bit for bit for all other clm45 and clm50 compsets + + Verified not answer changing for CLM50 compsets via test suite, and + 20 year simulation by Dave Lawrence and Keith Olseson. + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: ED/fates compsets only + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): unknown + + If bitwise differences were observed, how did you show they were no worse + than roundoff? n/a + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: n/a + + URL for LMWG diagnostics output used to validate new climate: n/a + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): + +A components/clm/SVN_EXTERNAL_DIRECTORIES - new SVN_EXTERNALS file for fates +A components/clm/src/fates + +List all files eliminated: + +D components/clm/src/ED - removed and replaced by fates external + +List all files reamed: + +rename testmod edTest --> fates + default now with fire off +A testmods_dirs/clm/fates +A testmods_dirs/clm/fates/user_nl_clm +A testmods_dirs/clm/fates/shell_commands +D testmods_dirs/clm/edTest +D testmods_dirs/clm/edTest/user_nl_clm +D testmods_dirs/clm/edTest/shell_commands + +rename testmod edNoFire --> fatesFire +A testmods_dirs/clm/fatesFire +A testmods_dirs/clm/fatesFire/user_nl_clm +A testmods_dirs/clm/fatesFire/include_user_mods +A testmods_dirs/clm/fatesFire/shell_commands +D testmods_dirs/clm/edNoFire +D testmods_dirs/clm/edNoFire/user_nl_clm +D testmods_dirs/clm/edNoFire/include_user_mods +D testmods_dirs/clm/edNoFire/shell_commands + +List all files added and what they do: + +List all existing files that have been modified, and describe the changes: + +M .ChangeLog_template - include cheyenne_intel +M parse_cime.cs.status - patch from Erik Kluzek bugz 2459 + +Point build to new src/fates directory instead of src/ED +M clm/cime_config/buildlib +M clm/bld/configure + +Update namelist with new fates paramfile, rename use_ed to use_fates +in namelist logic, rename functions to be fates instead of ed. Update tests. +M clm/bld/CLMBuildNamelist.pm +M clm/bld/unit_testers/build-namelist_test.pl +M clm/bld/test_build_namelist/t/input/namelist_defaults_clm4_5_test.xml +M clm/bld/test_build_namelist/t/input/namelist_definition_clm4_5_test.xml +M clm/bld/test_build_namelist/t/test_do_transient_pfts.pm +A clm/bld/test_build_namelist/t/test_fates_mode.pm +D clm/bld/test_build_namelist/t/test_ed_mode.pm +M clm/bld/test_build_namelist/t/test_do_harvest.pm +M clm/bld/test_build_namelist/t/test_do_transient_crops.pm +M clm/bld/namelist_files/namelist_definition_clm4_5.xml +M clm/bld/namelist_files/namelist_defaults_clm4_5.xml + +Update test for fates, cheyenne_intel +M clm/cime_config/testdefs/ExpectedTestFails.xml +M clm/cime_config/testdefs/testlist_clm.xml + +Stub fates parameter interface for unit tests: +M components/clm/src/CMakeLists.txt +A + components/clm/src/unit_test_stubs/utils/clmfates_paraminterfaceMod_stub.F90 +M components/clm/src/unit_test_stubs/utils/CMakeLists.txt + +Rename ED compset FATES +M clm/cime_config/config_compsets.xml +M clm/cime_config/config_component.xml + +Fates interface +A clm/src/utils/clmfates_paraminterfaceMod.F90 +M clm/src/utils/clmfates_interfaceMod.F90 + +Rename use_ed to use_fates and other rebranding +M clm/src/biogeochem/CNCStateUpdate1Mod.F90 +M clm/src/biogeochem/CNMRespMod.F90 +M clm/src/biogeochem/CNVegetationFacade.F90 +M clm/src/biogeochem/CNDriverMod.F90 +M clm/src/main/clm_varpar.F90 +M clm/src/main/subgridRestMod.F90 +M clm/src/main/atm2lndType.F90 +M clm/src/main/restFileMod.F90 +M clm/src/main/initSubgridMod.F90 +M clm/src/main/initVerticalMod.F90 +M clm/src/main/surfrdMod.F90 +M clm/src/biogeophys/PhotosynthesisMod.F90 +M clm/src/biogeophys/HydrologyDrainageMod.F90 +M clm/src/biogeophys/SurfaceAlbedoMod.F90 +M clm/src/biogeophys/SurfaceRadiationMod.F90 +M clm/src/biogeophys/SoilMoistStressMod.F90 +M clm/src/biogeophys/CanopyStateType.F90 +M clm/src/dyn_subgrid/dynSubgridDriverMod.F90 +M clm/src/dyn_subgrid/dynEDMod.F90 +M clm/src/dyn_subgrid/dynSubgridControlMod.F90 +M clm/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 +M clm/src/soilbiogeochem/SoilBiogeochemDecompCascadeCNMod.F90 +M clm/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 +M clm/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 +M clm/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 +M clm/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 +M clm/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 + + +Update logic for fates compatibility and to use clm_fates interface +M clm/src/biogeochem/EDBGCDynMod.F90 +M clm/src/main/subgridWeightsMod.F90 +M clm/src/main/decompInitMod.F90 +M clm/src/main/clm_initializeMod.F90 +M clm/src/main/subgridMod.F90 +M clm/src/main/histFileMod.F90 +M clm/src/main/controlMod.F90 +M clm/src/main/clm_varctl.F90 +M clm/src/main/clm_driver.F90 +M clm/src/main/pftconMod.F90 +M clm/src/main/initGridCellsMod.F90 +M clm/src/main/decompMod.F90 +M clm/src/main/clm_instMod.F90 +M clm/src/main/readParamsMod.F90 +M clm/src/biogeophys/CanopyTemperatureMod.F90 +M clm/src/biogeophys/HydrologyNoDrainageMod.F90 +M clm/src/biogeophys/BalanceCheckMod.F90 +M clm/src/biogeophys/WaterStateType.F90 +M clm/src/biogeophys/TotalWaterAndHeatMod.F90 +M clm/src/biogeophys/CanopyFluxesMod.F90 +M clm/src/biogeophys/SoilStateInitTimeConstMod.F90 +M clm/src/biogeophys/RootBiophysMod.F90 +M clm/src/biogeophys/OzoneMod.F90 + +M clm/src/main/paramUtilMod.F90 - new generic routines used by fates interface +M clm/src/main/PatchType.F90 - new patch array to distinguish between fates patch and clm pft + +A clm/src/biogeophys/SoilWaterPlantSinkMod.F90 - from SoilWaterMovement +M clm/src/biogeophys/SoilWaterMovementMod.F90 - moved to SoilWaterPlantSink +M clm/src/biogeophys/WaterfluxType.F90 - new variable for fates +M clm/src/biogeophys/SoilStateType.F90 - remove tsink + +=============================================================== +=============================================================== +Tag name: clm4_5_16_r237 +Originator(s): erik (Erik Kluzek) +Date: Tue May 9 15:05:51 MDT 2017 +One-line Summary: Latest parameter file and some changes for CLM50, CLM45-transient changes answers also + +Purpose of changes +------------------ + +Adjustments to CLM50 climate from Keith Oleson, Peter Lawrence, Fang Li, Rosie Fisher, Danica Lombardozzi, Will Weider, +Yaqiong Lu, Ben Sanderson, and David Lawrence. Some tweaks to the code and to parameters and the parameter file for CLM50. +Use Medlyn 2011 stomotal conductance rather than Ball-Berry. Modify photosynthesis and leaf maintence respiration for crop. +Limit irrigation if river flow is on and the storage drops below a threshold. Modify a long list of parameter values including +41 items on the parameter file. Only harvest up to 98% to allow for regrowth and divide by several terms rather than just deadstem. +Add slash harvesting fields (debris left from harvesting). Add in a hack to read in FWS_TWS_A/B if they are on the surface +dataset and use them to calculate finundation based on TWS rather than exponential function based on ZWT. For fires change an +if statement from checking if atmosphere is non-freezing to a specific soil layer. If crops have hit peak LAI set leaf allocation +to a small value. Make sure some retranslocation terms are positive. Let lnc in Photosynthesis max out at 10. Only vary baset +for crops for spring wheat and sugarcane (irrigated and non) rather than all crops. + +Coupled crop cases will change since we now use the radiation time-step for fertilization rather than the model time-step. +CLM45 cases remain the same with the exception for transient cases which change answers due to the change in how +harvest is handled. Fix a few minor bugs that came in with clm4_5_15_r236 with specific datasets and finidat file handling in scripts +(bugs 2448-2451). + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + + 2452 --- Change to divisor for harvest and also allow for regrowth + 2451 --- Bad comment marker in cropf10IC testmods + 2450 --- Make sure finidat is reset after setting to coldstart + 2449 --- Add no fail to init_interp_attributes and use_init_interp, needed for DV cases where interpolated IC files aren't there + 2448 --- Misnamed dataset in CLM xml database + +Known bugs introduced in this tag (include bugzilla ID): + 2457 --- Remove FINUN_HIST from history + 2456 --- Remove extra settings of use_init_interp + 2455 --- PGI specific error at initialization + 2454 --- masterlist_addfld getting confused with names for species... + 2453 --- Memory error with restart variable vcmx25t + 2447 --- Floating overflow for CLM50CROP case on hobart_nag in Photosynthesis + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): New slash harvest fields + SLASH_HARVESTC, DWT_SLASH_CFLUX, C13_DWT_SLASH_CFLUX, C14_DWT_SLASH_CFLUX + +Changes made to namelist defaults (e.g., changed parameter values): Many adjustments for CLM50 + modifyphoto_and_lmr_forcrop TRUE for CLM50 + stomatalcond_method Medlyn2011 for CLM50 with PHS + limit_irrigation_if_rof_enabled TRUE for CLM50 + Following values modified for CLM50 cases + modify baseflow_scalar, rh_low, bt_min, bt_max, cli_scale, boreal_peatfire_c, pot_hmn_ign_counts_alpha + non_boreal_peatfire_c, cropfire_a1, lfuel, cmb_cmplt_fact, irrig_threshold_fraction, + n_melt_glcmec, br_root, initial_Cstocks_depth + +Changes to the datasets (e.g., parameter, surface or initial files): CLM50 parameter file clm5_params.c170413.nc + Update CLM50 paramsfile, fsurdat-f09-2000-crop, flanduse_timeseries-f45-hist/f10-hist + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): finundation changes are messy + +Changes to tests or testing: Fixed testmods for one tests + +Code reviewed by: self,dlawren,lawrence,oleson,rosiefisher,wweider,lifang + +Did you follow the steps in .CLMTrunkChecklist: Yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS (93 comparison tests fail to clm4_5_15_r236) + + unit-tests (components/clm/src): + + yellowstone - PASS + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - PASS + yellowstone_pgi - PASS + yellowstone_gnu (clm45 only) - PASS + hobart_nag --- OK + hobart_pgi --- OK + hobart_intel - PASS + +CLM tag used for the baseline comparisons: clm4_5_15_r236 + + +Answer changes +-------------- + +Changes answers relative to baseline: All CLM50 and CLM45-transient + + Summarize any changes to answers, i.e., + - what code configurations: All CLM50 compsets and any transient cases with CLM45 + Also coupled crop cases + - what platforms/compilers: All + - nature of change: + Adjusted climate for CLM50 and changes to harvesting for CLM45 + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml - + modifyphoto_and_lmr_forcrop TRUE for CLM50 + stomatalcond_method Medlyn2011 for CLM50 with PHS + limit_irrigation_if_rof_enabled TRUE for CLM50 + Following values modified for CLM50 cases + modify baseflow_scalar, rh_low, bt_min, bt_max, cli_scale, boreal_peatfire_c, pot_hmn_ign_counts_alpha + non_boreal_peatfire_c, cropfire_a1, lfuel, cmb_cmplt_fact, irrig_threshold_fraction, + n_melt_glcmec, br_root, initial_Cstocks_depth + Update CLM50 paramsfile, fsurdat-f09-2000-crop, flanduse_timeseries-f45-hist/f10-hist + M components/clm/bld/CLMBuildNamelist.pm ------------------------- Make sure local finidat defined for cold start + allow nofail for use_init_interp and init_interp_attributes + + M components/clm/cime_config/testdefs/testmods_dirs/clm/cropf10IC/user_nl_clm - Use \! for comment + + M components/clm/src/biogeochem/CNPhenologyMod.F90 ----------- Use radiation time-step rather than dt for Fertilization + M components/clm/src/biogeochem/CNFireBaseMod.F90 ------------ Change ufuel default + M components/clm/src/biogeochem/dynHarvestMod.F90 ------------ Only harvest up to 98% and divide by sum of several + terms rather than just deadstem (Peter Lawrence) + M components/clm/src/biogeochem/ch4FInundatedStreamType.F90 -- Modify endrun call + M components/clm/src/biogeochem/dynConsBiogeochemMod.F90 ----- Slash flux to litter and CWD + M components/clm/src/biogeochem/CNFireLi2016Mod.F90 ---------- Change if statement from check on forcing temp non-freezing + to tsoi17 non-freezing (From Fang Li) + M components/clm/src/biogeochem/ch4Mod.F90 ------------------- Add ability to read in FWS_TWS_A/B terms from surface + dataset and use for calculation of finundated based on TWS rather than use exponential inversion on ZWT + M components/clm/src/biogeochem/CNVegCarbonFluxType.F90 ------ Add slash harvest flux fields (Peter Lawrence) + M components/clm/src/biogeochem/CropType.F90 ----------------- Only do baset_map_latvary for spring wheat and sugarcane + both irrigated and non. + M components/clm/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 - If crops have hit peaklai, then set leaf allocation to small value + make sure leafn_to_retransn, frootn_to_retransn and livestemn_to_retransn is positive + M components/clm/src/biogeophys/PhotosynthesisMod.F90 -------- Let lnc max out at 10 + +=============================================================== +=============================================================== +Tag name: clm4_5_15_r236 +Originator(s): erik (Erik Kluzek) +Date: Mon May 1 01:42:23 MDT 2017 +One-line Summary: New surface datasets, and landuse.timeseries files, as well as interpolating initial conditions for almost all cases + +Purpose of changes +------------------ + +New fsurdat and landuse.timeseries datasets for almost all resolutions. +New initial conditions datasets pointed to as much as possible for all resolutions (have ability to turn off to COLDSTART for some tests). +Normally model will now die, if it can't find initial conditions to interpolate from. +Reasonable f09 and f19 PE layout for cheyenne. Fix another issue on Cheyenne. Add new pgi/intel tests for hobart. + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2445 -- ED not working with new datasets + 2444 -- dimensional change in URBAN_AC/URBAN_HEAT for interpolation of restart files + 2441 -- fire emissions on cheyenne + 2291 -- fire emissions with gnu compiler sometimes NaN, sometimes change answers for trivial changes + 2239 -- need new initial conditions files with extra metadata on them + +Known bugs introduced in this tag (include bugzilla ID): + 2447 -- Floating overflow for CLM50CROP case on hobart_nag in Photosynthesis + #1215 -- (in this version of cime) TestStatus sometimes needs to have write permission added + #? -- manage_case doesn't work + #? -- ./xmlquery --list-all doesn't work + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + + All initial conditions have to be interpolated now, but there are ones that can be interpolated from for standard cases + NOTE NOW IF YOU WANT TO DO A COLD START USING ARBITRARY INITIAL CONDITIONS SET CLM_FORCE_COLDSTART=on + Also the model will normally fail if it can't find initial conditions close enough to interpolate from + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): A close finidat file will almost always be set + +Changes made to namelist defaults (e.g., changed parameter values): + +Changes to the datasets (e.g., parameter, surface or initial files): New fsurdat/finidat/landuse.timeseris + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + +Changes to tests or testing: New pgi/intel tests for hobart + + Expected fails removed: bug 2239, 2291, and added SMS_Ld5_D_P24x1.f10_f10.IHISTCLM50BGC.hobart_nag.clm-monthl for bug 2447 + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + tools-tests (components/clm/test/tools): + + yellowstone - PASS + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - PASS + yellowstone_pgi - PASS + yellowstone_gnu (clm45 only) - PASS + hobart_nag --- OK + hobart_pgi --- OK + hobart_intel - OK + +CLM tag used for the baseline comparisons: clm4_5_15_r235 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: Almost all CLM45 and CLM50 configurations because of new datasets + - what platforms/compilers: All + - nature of change (roundoff; larger than roundoff/same climate; new climate): similar climate + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: + +------ No longer need vrtlay_interp testmods, nor user_nl_clm for some +D components/clm/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/include_user_mods +D components/clm/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp/README +D components/clm/cime_config/testdefs/testmods_dirs/clm/vrtlay_interp +D components/clm/cime_config/testdefs/testmods_dirs/clm/cropColdStart/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/user_nl_clm +D components/clm/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/user_nl_clm +------- Reduce size of files +D components/clm/tools/mkprocdata_map/clm4054_ne30g16_I2000.clm2.h0.2000-01_c121107.nc +D components/clm/tools/mkprocdata_map/clm4054_f19g16_I2000.clm2.h0.2000-01_c121107.nc + +List all files added and what they do: + +------------ New test-mods with specific initial conditions +A components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC/user_nl_clm +A components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC/include_user_mods +A components/clm/cime_config/testdefs/testmods_dirs/clm/defaultf09IC +A components/clm/cime_config/testdefs/testmods_dirs/clm/cropf10IC/user_nl_clm +A components/clm/cime_config/testdefs/testmods_dirs/clm/cropf10IC/include_user_mods +A components/clm/cime_config/testdefs/testmods_dirs/clm/cropf10IC +A components/clm/tools/mkprocdata_map/clm4054_ne30g16_I2000.clm2.h0.2000-01_c170430.nc +A components/clm/tools/mkprocdata_map/clm4054_f19g16_I2000.clm2.h0.2000-01_c170430.nc + +A components/clm/cime_config/testdefs/testmods_dirs/clm/allActive/shell_commands - CLM_FORCE_COLDSTART=on +A components/clm/cime_config/testdefs/testmods_dirs/clm/cropColdStart/shell_commands - CLM_FORCE_COLDSTART=on +A components/clm/cime_config/testdefs/testmods_dirs/clm/monthly_noinitial/shell_commands - CLM_FORCE_COLDSTART=on + +------------ New unit test for surfrdUtilsMod subroutines +A components/clm/src/main/test/surfrdUtils_test/test_surfrdUtils.pf +A components/clm/src/main/test/surfrdUtils_test/CMakeLists.txt + +List all existing files that have been modified, and describe the changes: + +M components/clm/bld/CLMBuildNamelist.pm ---------------------------- Add better handling of finding finidat files + either with an exact match or interpolated from +M components/clm/bld/unit_testers/build-namelist_test.pl ------------ Add new failure tests, fix ed-test +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml -- Add init_interp_how_close and init_interp_sim_years +M components/clm/bld/namelist_files/namelist_defaults_overall.xml --- Start type is startup (requires finidat) for CLM45/CLM50 + unless use_cndv is on +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml ---- init_interp_how_close=75 and init_interp_sim_years=1850,2000 + new 2-deg IC files IGM1850GSWCLM50BGCCROP, I1850CRUCLM45BGC, IGM2000GSWP3CLM50BGCCROPIRR, ICRUCLM45SP + redone 2-deg ICLM45BGCCROP + create_crop_landunit on unless ED is on + updated: fsurdat, flanduse.timeseries for all but 1x1_smallville_IA and 0.125x0.125 + +M components/clm/cime_config/testdefs/ExpectedTestFails.xml -- ICLM45VIC.yellowstone now PASS + SMS_Lm25.f19_g16.ICLM45BGCCROP.yellowstone_gnu now PASS, new fail SMS_Ld5_D_P24x1.f10_f10.IHISTCLM50BGC.hobart_nag.clm-monthly + +M components/clm/cime_config/testdefs/testmods_dirs/clm/irrig_spunup/user_nl_clm - remove finidat and init_interp_fill_missing_with_natveg +M components/clm/cime_config/testdefs/testmods_dirs/clm/tropicAtl_subset/user_nl_clm - set fsurdat, create_crop_landunit +M components/clm/cime_config/testdefs/testmods_dirs/clm/USUMB/user_nl_clm ------ create_crop_landunit = .false. +M components/clm/cime_config/testdefs/testmods_dirs/clm/40ptsROA/shell_commands - CLM_FORCE_COLDSTART=on +M components/clm/cime_config/testdefs/testmods_dirs/clm/edTest/user_nl_clm ------ remove finidat='' +M components/clm/cime_config/testdefs/testmods_dirs/clm/allActive/user_nl_clm +M components/clm/cime_config/testdefs/testmods_dirs/clm/ptsROA/shell_commands - CLM_FORCE_COLDSTART=on +M components/clm/cime_config/testdefs/testmods_dirs/clm/40ptsRLA/shell_commands - CLM_FORCE_COLDSTART=on +M components/clm/cime_config/testdefs/testmods_dirs/clm/40ptsRLB/shell_commands - CLM_FORCE_COLDSTART=on +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/user_nl_clm - new finidat +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_inc_dec_bgc/README +M components/clm/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/user_nl_clm - remove finidat +M components/clm/cime_config/testdefs/testmods_dirs/clm/interp_f19_crop/README +M components/clm/cime_config/testdefs/testmods_dirs/clm/ptsRLA/shell_commands - CLM_FORCE_COLDSTART=on +M components/clm/cime_config/testdefs/testmods_dirs/clm/ptsRLB/shell_commands - CLM_FORCE_COLDSTART=on +M components/clm/cime_config/testdefs/testmods_dirs/clm/clm50cropIrrigMonth_interp/user_nl_clm - remove finidat, + init_interp_fill_missing_with_natveg +M components/clm/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/shell_commands- CLM_FORCE_COLDSTART=on +M components/clm/cime_config/testdefs/testmods_dirs/clm/decStart1851_noinitial/README +M components/clm/cime_config/testdefs/testmods_dirs/clm/glcMEC_spunup_1way/user_nl_clm - new finidat +M components/clm/cime_config/testdefs/testmods_dirs/clm/clm50KitchenSink/user_nl_clm - remove finidat +M components/clm/cime_config/testdefs/testlist_clm.xml -- new pgi/intel hobart tests, vrtlay_interp->vrtlay, + use defaultf09IC cropf10IC for two LII tests +M components/clm/cime_config/user_nl_clm ----------- Fix documentation of irrigate, add note to use CLM_FORCE_COLDSTART + rather than finidat=' ' +M components/clm/cime_config/config_component.xml - HIST and 2000 compsets for BGCCROP turn irrigation on +M components/clm/cime_config/config_pes.xml -- Add f09 and f19 PE layouts for cheyenne + +M components/clm/src/biogeochem/FireEmisFactorsMod.F90 - Copy crop factors from generic crop CFT's + +M components/clm/src/main/test/CMakeLists.txt ---------- Add new unit test +M components/clm/src/main/surfrdUtilsMod.F90 ----------- Add renormalize and convert_cft_to_pft functions + lighten tolerence for sums to equal 1 from 1.e-14 to 1.e-13 +M components/clm/src/main/surfrdMod.F90 ---------------- Add surfrd_pftformat, surfrd_cftformat to read in old/new formats + for CFT or PFT, also handle conversion of new CFT format to PFT format for ED +M components/clm/src/biogeophys/EnergyFluxType.F90 ----- For CLM50 urban add _L to URBAN_AC/HEAT to restart files, + so CLM45 won't be confused with CLM50 + +=============================================================== +=============================================================== +Tag name: clm4_5_15_r235 +Originator(s): sacks (Bill Sacks) +Date: Thu Apr 27 07:47:50 MDT 2017 +One-line Summary: Zero dynbal fluxes if namelist variable is set + +Purpose of changes +------------------ + +Some fully-active system tests were dying due to too-large sensible heat fluxes +(thousands or 10s of thousands of W m-2) generated from the dynbal +adjustments. These large fluxes arose because these tests trigger daily dynamics +of CISM (via the test_coupling namelist option), rather than the typical annual +coupling. The annual dribblers see these mid-year adjustments and apply them all +in a single time step, rather than spreading them throughout the year. + +The changes in this tag allow you to set a namelist variable +(for_testing_zero_dynbal_fluxes) to force the dynbal fluxes to zero. Typically, +this namelist variable should only be used for testing: setting it to +.true. breaks water and energy conservation. We will set this to true in the +fully-active tests that use daily CISM dynamics. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- new namelist variable, for_testing_zero_dynbal_fluxes; should only be used for + testing + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - pass + yellowstone_pgi - pass + yellowstone_gnu (clm45 only) - pass + hobart_nag - pass + +CLM tag used for the baseline comparisons: clm4_5_15_r234 + + +Answer changes +-------------- + +Changes answers relative to baseline: NO - bit-for-bit + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Changes as described above +M components/clm/src/dyn_subgrid/dynConsBiogeophysMod.F90 +M components/clm/src/dyn_subgrid/dynSubgridControlMod.F90 +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml + +=============================================================== +=============================================================== +Tag name: clm4_5_15_r234 +Originator(s): andre (Benjamin Andre,UCAR/CSEG,303-497-1391) +Date: Fri Apr 14 08:34:22 MDT 2017 +One-line Summary: Update rtm and mosart externals + +Purpose of changes +------------------ + +Update externals to rtm1_0_61 and mosart1_0_23. + +Includes change to python build-namelist (rtm, mosart), histfile +bugfix (rtm, mosart), and science bugfix / changes (mosart). + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): 2434 + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + + python build namelist for rtm will no longer automatically point rtm + to a clm restart file. rtm should be configured to generate and read + it's own restart files. + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) : none + + +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: + +rtm was not outputing a restart file for the ref run in SSP tests, but +was attempting to read one during the second run because of +build-namelist changes in rtm1_0_60. All SSP tests in aux_clm45 and +prebeta were changed to use a new test mod, rtmColdSSP, that forces +rtm to do a cold start when coming out of spinup. + +Old RCP/clm40 tests that were not compatible with new rtm +build-namelist behavior were removed. + +Code reviewed by: self, discussion with Erik Kluzek. + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - n/a, not run + + unit-tests (components/clm/src): + + yellowstone - n/a, not run + + tools-tests (components/clm/test/tools): + + yellowstone - n/a, not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - n/a, not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + hobart_nag - ok + + All tests passed bit for bit except: + + * expected failures + + * Tests with mosart passed functionality, answer changing as expected. + + * SSP tests passed functionality, but don't have baselines + because of test-mod change. Manually ran cprc to compare with + clm4_5_15_r233, files were reported as identical. + + e.g. cprnc clm4_5_15_r233/SSP_D_Ld10.f19_g16.I1850CLM45BGC.yellowstone_intel.clm-default/clm2.h0.0001-01-06-00000.nc clm4_5_15_r234-prelim/SSP_D_Ld10.f19_g16.I1850CLM45BGC.yellowstone_intel.clm-rtmColdSSP/clm2.h0.0001-01-06-00000.nc + + +CLM tag used for the baseline comparisons: clm4_5_15_r233 + + +Answer changes +-------------- + +Changes answers relative to baseline: yes + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: all runs with mosart + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): unknown, assumed same climate. + + If bitwise differences were observed, how did you show they were no worse + than roundoff? + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: + + mosart1_0_23 was reviewed by Sean Swenson and Dave Lawrence in + a long coupled run and approved. + + URL for LMWG diagnostics output used to validate new climate: none + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): + +rtm1_0_61, mosart1_0_23 + +List all files eliminated: none + +List all files added and what they do: + +New test mod so rtm will do a cold start during SSP tests. + +A clm/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP +A clm/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/include_user_mods +A clm/cime_config/testdefs/testmods_dirs/clm/rtmColdSSP/user_nl_rtm + +List all existing files that have been modified, and describe the changes: + +Remove old RCP/clm40 tests that were not compatible with new rtm +behavior. Update SSP tests in aux_clm45 and prebeta to use new +rtmColdSSP testmod. + +M clm/cime_config/testdefs/testlist_clm.xml + + +=============================================================== +=============================================================== +Tag name: clm4_5_15_r233 +Originator(s): erik (Erik Kluzek) +Date: Tue Apr 11 23:30:45 MDT 2017 +One-line Summary: Pull out some constants and options to namelist + +Purpose of changes +------------------ + +Pull out a list of constants and options to namelist control. Decrease a few error tolderances. +Add in reseed_dead_plants namelist option, so can reseed dead plants for BGC on a restart. +Reenable LND_TUNING_MODE, although currently set the same for all options. Add some new +compsets in. Fix a few bugs, including Jim Edward's fix for vector output. +Start adding in the stream option for finundated. Add option to turn Medlyn photosynthesis on. +Replace & with & in namelist_definition_clm4_5.xml + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2440 Remove use of mct_gsmap_op and replace with mct_gsMap_orderedPoints + 2430 Problem with units on new landuse.timeseries datasets + 2184 vector (1d) history output crashes for some fields + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): Added new parameters to namelist + New namelists: cnvegcarbonstate and cn_general + New namelist items: + modifyphoto_and_lmr_forcrop, stomatalcond_method, lfuel, ufuel, cmb_complt_fact, + initial_Cstocks_depth, ndep_taxmode, ndep_varlist, init_interp_attributes, reseed_dead_plants, + initial_vegC, finundation_method + New output history variables: Remove RSCANOPY unless use_ed add: VCMX25T, JMX25T, TPU25T + New compsets I1850GSWCLM50BGCCROP, IM1850GSWCLM50BGCCROP, IGM1850GSWCLM50BGCCROP, IGMHISTGSWCLM50BGCCROP + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): params files + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - OK (183 test fail comparison to previous namelists) + + unit-tests (components/clm/src): + + yellowstone - PASS + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu (clm45 only) - OK + hobart_nag - OK + +CLM tag used for the baseline comparisons: clm4_5_15_r232 + + +Answer changes +-------------- + +Changes answers relative to baseline: None bit-for-bit + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: + +-------- Start adding ability to read finundated streams data (currently disabled) + A components/clm/src/biogeochem/ch4FInundatedStreamType.F90 + +List all existing files that have been modified, and describe the changes: + + M components/clm/bld/CLMBuildNamelist.pm --- Add setup_logic_cnvegcarbonstate, + new namelists: cnvegcarbonstate and cn_general, refactor how finidat files + were being found to a better more general methodology that allows a second + go to find finidat file to interpolate from (currently disabled) + M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml ---- New settings: + modifyphoto_and_lmr_forcrop, stomatalcond_method, use_init_interp, init_interp_attributes + initial_Cstocks_depth, initial_vegC, and new params file with medlynslope/intercept + M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml -- New namelist items: + modifyphoto_and_lmr_forcrop, stomatalcond_method, lfuel, ufuel, cmb_complt_fact, + initial_Cstocks_depth, ndep_taxmode, ndep_varlist, init_interp_attributes, reseed_dead_plants, + initial_vegC, finundation_method + M components/clm/bld/unit_testers/build-namelist_test.pl -- Test that use_init_interp=.true. with + finidat blank is fails + + M components/clm/cime_config/config_component.xml - Set LND_TUNING_MODE by compset + M components/clm/cime_config/config_compsets.xml -- Add: I1850GSWCLM50BGCCROP, IM1850GSWCLM50BGCCROP, + IGM1850GSWCLM50BGCCROP, IGMHISTGSWCLM50BGCCROP compsets + + M components/clm/src/biogeochem/CNBalanceCheckMod.F90 --- Decrease carbon error tolerance from 1xe-8 to 1xe-7 + and nitrogen error tolerance from 1xe-4 to 1xe-3 + M components/clm/src/biogeochem/CNFireBaseMod.F90 ---------- Add lfuel, ufuel, cmb_cmplt_fact to namelist + M components/clm/src/biogeochem/CNVegCarbonStateType.F90 --- Add InitReadNML and read in initial_vegC in + new cnvegcarbonstate namelist, handle reseeding with reseed_patch filter + M components/clm/src/biogeochem/CNVegNitrogenStateType.F90 - Handle reseeding with reseed_patch filter for + restart read + M components/clm/src/biogeochem/CNVegStateType.F90 --------- Handle reseeding with reseed_patch filter for + M components/clm/src/biogeochem/CNVegetationFacade.F90 ----- Add namelist read CNReadNML for cn_general + and reseed_dead_plants option, pass it and/or reseed filter down as appropriate + M components/clm/src/biogeochem/CropType.F90 ------ Check validity of baset_mapping, set latbaset_patch to nan + if not used, switch logic of how activated + M components/clm/src/biogeochem/ch4varcon.F90 ----- Make default private, explicitly make items public as needed + add finundation_mtd and valid settings, read finundation_method in namelist and check it + M components/clm/src/biogeochem/dynHarvestMod.F90 - Validate units of harvest fields abort if not right + + M components/clm/src/biogeophys/CanopyStateType.F90 --- Only send RSCANOPY to history if use_ed is on + M components/clm/src/biogeophys/PhotosynthesisMod.F90 - Add: stomatalcond_mtd, modifyphoto_and_lmr_forcrop namelist + items, add extra history output: VCMX25T, JMX25T, TPU25T + + M components/clm/src/main/GetGlobalValuesMod.F90 - Replace mct_gsMap_orderedPoints for mct_gsMap_OP + M components/clm/src/main/histFileMod.F90 -------- Fix for bug 2184 from Jim Edwards + M components/clm/src/main/init_hydrology.F90 ----- Call init_root_moist_stress + M components/clm/src/main/ncdio_pio.F90.in ------- Replace mct_gsMap_orderedPoints for mct_gsMap_OP + M components/clm/src/main/ndepStreamMod.F90 ------ Add: ndep_taxmode, ndep_varlist to namelist + M components/clm/src/main/pftconMod.F90 ---------- Add: medlynslope/intercept to data/alloc/read/clean + + M components/clm/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 ------ Use decomp_cascade_con%initial_stock_soildepth + in place of hardcoded 0.3 + M components/clm/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 ------- Increase error tolerence allowed + for endrun for too much NH4 uptake predicted by FUN + M components/clm/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 -- Add initial_Cstocks_depth to namelist + M components/clm/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 - Add initial_stock_soildepth set to 0.3 + + M components/clm/src/unit_test_stubs/csm_share/mct_mod_stub.F90 - Replace mct_gsMap_OP with mct_gsMap_orderedPoints + + M components/clm/src/utils/quadraticMod.F90 - Allow for situations where a sqrt of a slightly negative number + would crash the code. + +=============================================================== +=============================================================== +Tag name: clm4_5_15_r232 +Originator(s): erik (Erik Kluzek) +Date: Wed Apr 5 23:04:37 MDT 2017 +One-line Summary: Some small changes that affect both clm4_5 and clm5_0 answers (can be considered bug fixes to clm4_5) + +Purpose of changes +------------------ + +A set of some small changes that affect answers for both CLM45 and CLM50. A fix to a rare problem where soil albedo +could go negative from Keith Oleson and Sean Swenson, by making sure a calculated value could not go below a small value. +A change from Will Weider to lower leaf maintence respiration (LMR) for low LAI. Always calculate btran2 even for low +temperatures and/or low liquid water this lowers fires in boreal forests. For crop at peak LAI set hui to max of hui and +huigrain. Change the handling of GDDPLANT accumulator field from Keith Oleson. Get rid of the use_voc logic that just +prevented MEGAN from activating for crop, since now MEGAN handles the crop case (since clm4_5_13_r204). + +Bugs fixed or introduced +------------------------ + 2437 -- lower leaf maintence respiration for low LAI + 2436 -- some adjustments to crop + 2435 -- always calculate btran to lower fires in boreal forests + 2431 -- Rare condition under which soil albedo goes negative + 2368 -- Remove use_voc as MEGAN can now work with crop + +Bugs fixed (include bugzilla ID): + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): None + +Changes to tests or testing: None + +Code reviewed by: self, oleson, dll, dlawren, wweider, fangli + +Did you follow the steps in .CLMTrunkChecklist: Yes + +CLM testing: regular + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu (clm45 only) - OK + hobart_nag - OK + +CLM tag used for the baseline comparisons: clm4_5_14_r231 + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes! + + Summarize any changes to answers, i.e., + - what code configurations: + - what platforms/compilers: + - nature of change (roundoff; larger than roundoff/same climate; new climate): + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + + M components/clm/src/biogeophys/SurfaceAlbedoMod.F90 --- Fix bug 2431 where soil albedo can got negative + make sure a calculated value doesn't go too small + M components/clm/src/biogeophys/PhotosynthesisMod.F90 -- Add check for divide by zero fo lnc, reduce + lmr for low LAI + M components/clm/src/biogeophys/SoilMoistStressMod.F90 - Always calculate btran2 even for low temperature + and/or low liquid water this lowers fires in boreal forests + M components/clm/src/biogeochem/CNPhenologyMod.F90 ----- For crop at peak lai set hui to max of hui and huigrain + M components/clm/src/biogeochem/CropType.F90 ----------- Change handling of GDDPLANT + +----------- Remove use_voc logic + M components/clm/src/cpl/clm_cpl_indices.F90 ----------- Remove use_voc + M components/clm/src/main/clm_instMod.F90 -------------- Remove use_voc + M components/clm/src/main/controlMod.F90 --------------- Remove use_voc + M components/clm/src/main/clm_varctl.F90 --------------- Remove use_voc + M components/clm/src/main/clm_driver.F90 --------------- Remove use_voc + M components/clm/src/main/lnd2atmMod.F90 --------------- Remove use_voc + +=============================================================== +=============================================================== +Tag name: clm4_5_14_r231 +Originator(s): sacks (Bill Sacks) +Date: Sun Apr 2 19:36:02 MDT 2017 +One-line Summary: Add option to reset snow pack over non-glacier columns + +Purpose of changes +------------------ + +When going from a CLM spinup under one set of atmospheric forcings to a +different set of atmospheric forcings, there is the possibility that columns +that reached large snow depths in the spinup should really have only seasonal +snow cover under the new atmosphere. This is a particular concern for the LIWG +in some areas of Greenland that have only seasonal snow cover: there is a +concern that the offline spinup can bake in too-high snow cover in some +regions. This can especially be a problem because of feedbacks: starting out +with a too-high snow cover can cool the overlying atmosphere, leading to +persistence of the snow pack. This is also a problem because, once the snow pack +becomes very deep, it seems that its refreezing can make it less likely that the +snow pack will ever melt. + +To deal with these issues, this tag introduces a new namelist item, +reset_snow. This is typically .false. If you set it to .true., then all snow in +non-glacier columns is reset to 35 mm SWE over the first few time steps of the +run. + +This resetting is accomplished via the snow capping mechanism. This +implementation was chosen because it is challenging to reset the snow pack +directly, since there are so many snow-related variables that must be kept in +sync. The snow capping mechanism already handles this properly, so it's easiest +to reuse this mechanism. However, unlike standard snow capping, the flux of snow +lost through this resetting is sent into a new flux that simply disappears into +nothingness - rather than being sent to glc and/or rof. Thus, note that - by +design! - the flux from this snow resetting breaks conservation: We do not want +this lost snow to affect ocean circulation, since this is essentially just a +mechanism for adjusting an initial conditions file. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): +- Specifying reset_snow = .true. will lead to a loss of conservation for the + first few time steps of the run + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- New namelist variable: reset_snow + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: none + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: Leo van Kampenhout reviewed an initial prototype + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - ok + tests pass; namelists differ from baseline, as expected + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + hobart_nag - ok + + ok means tests pass, NLCOMP failures as expected + +CLM tag used for the baseline comparisons: clm4_5_14_r230 + + +Answer changes +-------------- + +Changes answers relative to baseline: no - bit-for-bit + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: + +List all files added and what they do: + +========= Unit test of new logic +A components/clm/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_SnowCappingExcess.pf + +List all existing files that have been modified, and describe the changes: + +========= Changes as described above +M components/clm/bld/CLMBuildNamelist.pm +M components/clm/bld/namelist_files/namelist_defaults_clm4_5.xml +M components/clm/bld/namelist_files/namelist_definition_clm4_5.xml +M components/clm/src/biogeophys/LakeHydrologyMod.F90 +M components/clm/src/biogeophys/BalanceCheckMod.F90 +M components/clm/src/biogeophys/WaterfluxType.F90 +M components/clm/src/biogeophys/SnowHydrologyMod.F90 +M components/clm/src/biogeophys/HydrologyDrainageMod.F90 +M components/clm/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt + +=============================================================== +=============================================================== +Tag name: clm4_5_14_r230 +Originator(s): sacks (Bill Sacks) +Date: Fri Mar 31 16:25:49 MDT 2017 +One-line Summary: Fix dynamic landunits water and energy conservation + +Purpose of changes +------------------ + +Fixes water and energy conservation with dynamic landunits. This conservation +works by summing the water and energy contents of each grid cell before and +after the dynamic landunits transitions, then dealing with the difference +through runoff and sensible heat fluxes. However, the code for counting the +water and energy contents was wrong - slightly wrong for water, and +substantially wrong for energy. The energy counts were 6 orders of magnitude too +small, and also were missing some terms. + +This tag fixes these counts, and reconciles the dynamic landunits water and +energy accounting with the accounting done for the balance checks. It also +refactors some of the code used in the balance checks to facilitate code sharing +between various places. + +Also: adds wa_col (water in the unconfined aquifer) to the list of fields copied +to newly-initializing columns, to avoid spurious dynlu adjustment fluxes due to +changes in wa_col. + + +Bugs fixed or introduced +------------------------ + +Known bugs introduced in this tag (include bugzilla ID): [If none, remove this line] +- https://github.com/NCAR/CLM/issues/2 - Count energy of water in lakes in total + gridcell heat content +- https://github.com/NCAR/CLM/issues/3 - Perform gridcell-level water balance + checks bracketing the entire run loop + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): +- Some renamed history variables: see below + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: not investigated, but no major changes expected + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: Dave Lawrence and Keith Oleson reviewed the new code +conceptually for scientifc correctness; Ryan Knox reviewed a slightly older +version of the new code for counting water and energy contents + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - ok + yellowstone_pgi - ok + yellowstone_gnu (clm45 only) - ok + hobart_nag - ok + + ok means tests pass, answers change as expected + +CLM tag used for the baseline comparisons: clm4_5_14_r229 + + +Answer changes +-------------- + +Changes answers relative to baseline: YES + + If a tag changes answers relative to baseline comparison the + following should be filled in (otherwise remove this section): + + Summarize any changes to answers, i.e., + - what code configurations: ALL + - what platforms/compilers: ALL + - nature of change (roundoff; larger than roundoff/same climate; new climate): + + (1) Roundoff-level changes for all cases + + (2) Large changes in diagnostics of total gridcell water and total gridcell + heat, due to various fixes + + (3) Dynamic landunit water adjustments change substantially for glacier + transitions, and somewhat for transient crops + + (4) Dynamic landunit heat adjustments change substantially for all runs with + dynamic landunits (transient glacier, transient crop): change by about + 6 orders of magnitude + + (5) Changes in transient crop cases due to copying wa_col to + newly-initiating columns (though answer changes may be minor for clm5 + cases?) + + (6) Possibly other changes that I'm forgetting? + + If bitwise differences were observed, how did you show they were no worse + than roundoff? N/A + + If this tag changes climate describe the run(s) done to evaluate the new + climate (put details of the simulations in the experiment database) + - casename: N/A + + URL for LMWG diagnostics output used to validate new climate: N/A + + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: + +========= Moved code that sums water and energy contents to here, to facilitate + code sharing; added unit tests for *some* of it +A components/clm/src/biogeophys/TotalWaterAndHeatMod.F90 +A components/clm/src/biogeophys/test/TotalWaterAndHeat_test/test_total_water_and_heat.pf +A components/clm/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt +A components/clm/src/biogeophys/test/TotalWaterAndHeat_test + +List all existing files that have been modified, and describe the changes: + +========= Major rework: Use new shared routines for calculating heat and water + contents; adjust dynlu adjustment heat flux based on heat content of + dynlu adjustment runoff flux +M components/clm/src/dyn_subgrid/dynConsBiogeophysMod.F90 +M components/clm/src/biogeophys/BalanceCheckMod.F90 + +========= Copy wa_col (water in the unconfined aquifer), to avoid large adjustments +M components/clm/src/dyn_subgrid/dynInitColumnsMod.F90 +M components/clm/src/dyn_subgrid/test/dynInitColumns_test/test_init_columns.pf + +========= Use new routines for water content +M components/clm/src/biogeophys/HydrologyDrainageMod.F90 +M components/clm/src/biogeophys/LakeHydrologyMod.F90 + +========= New constant for baseline wa_col (water in the unconfined aquifer), + replacing hard-coded constants +M components/clm/src/main/clm_varcon.F90 +M components/clm/src/biogeophys/SoilHydrologyMod.F90 +M components/clm/src/biogeophys/SoilHydrologyInitTimeConstMod.F90 + +========= For performance: introduce col%hydrologically_active, used in place of + is_hydrologically_active function call +M components/clm/src/main/ColumnType.F90 +M components/clm/src/main/filterMod.F90 +M components/clm/src/main/initSubgridMod.F90 +M components/clm/src/main/glcBehaviorMod.F90 + +========= Changes to diagnostic fields: Remove incorrect HCSOI, HC; rename + GC_HEAT1 and GC_HEAT2 to HEAT_CONTENT1 and HEAT_CONTENT2; add + HEAT_CONTENT1_VEG; add LIQUID_WATER_TEMP1 +M components/clm/src/biogeophys/TemperatureType.F90 +M components/clm/src/biogeophys/SoilTemperatureMod.F90 +M components/clm/src/biogeophys/LakeTemperatureMod.F90 + +========= Changes to diagnostic fields: Rename GC_LIQ1/2 to LIQUID_CONTENT1/2, + and similar for ICE; also remove some now-unused fields +M components/clm/src/biogeophys/WaterStateType.F90 + +========= Minor changes to some calls +M components/clm/src/dyn_subgrid/dynSubgridDriverMod.F90 +M components/clm/src/main/clm_driver.F90 + +========= New stub routines +M components/clm/src/unit_test_stubs/main/ncdio_pio_fake.F90.in + +========= New unit tests +M components/clm/src/biogeophys/CMakeLists.txt +M components/clm/src/biogeophys/test/CMakeLists.txt + +========= Add some comments +M components/clm/src/main/subgridAveMod.F90 +M components/clm/src/main/column_varcon.F90 + +========= Remove unneeded use statements and associates +M components/clm/src/biogeophys/UrbanParamsType.F90 +M components/clm/src/biogeophys/HydrologyNoDrainageMod.F90 +M components/clm/src/main/initVerticalMod.F90 + +=============================================================== +=============================================================== +Tag name: clm4_5_14_r229 +Originator(s): erik (Erik Kluzek) +Date: Fri Mar 10 11:32:20 MST 2017 +One-line Summary: Update cime and make some changes to drv_flds_in namelist, fix some minor bugs + +Purpose of changes +------------------ + +Update cime to a version with an updated top level directory structure. It also fixes a problem +with a CLM test. + +The new cime version has a new directory structure, and updates the XML schema for namelist files +from verison 1 to version 2. Currently the perl namelist code can NOT read version 2. Hence, a local +copy of the version 1 files for the drv_flds_in fields was added to CLM. Also the use of the datm +namelist files for some tools was dropped -- I think that's OK though. + +Fix two minor bugs. + +The new cime has a few improvements. It now adjusts the PIO namelist when the PE layout changes. +There's a new option to case.setup "--no-adjust-pio" to not do that. --mpilib option was added +to create_test. You can remove your bld directory area without having to rerun case.setup. + + +Bugs fixed or introduced +------------------------ + +Bugs fixed (include bugzilla ID): + 2433 -- format error in HumanIndexMod.F90 + 2432 -- intent mixing in dynVarMod.F90 +CIME Issues fixed (include issue #): + 1074 -- ERP_D_Ld5.hcru_hcru.ICRUCLM45BGC.yellowstone_pgi fails with PIO error + +Known bugs introduced in this tag (include bugzilla ID): (recently found, but predate this tag) + 1217 -- Driver allows a contradiction in drv_flds_in between CAM and CLM + 1220 -- missing mpi-serial mpirun case on hobart + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): + + case.setup has a new option --no-adjust-pio + + The user now can rm -rf their build area and rebuild without having + to re-run case.setup. + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + + CIME now normally adjusts PIO layout if you change the PE layout. + + Also puts a copy of namelist definition and defaults for drv_flds_in in CLM. + This copy needs to be doubly maintained with the versions in the driver and in CAM. + The advantage of having a copy is because each copy is using a different version of + the xml schema, and potentially the driver might have additional fields that interact + with other components besides CLM. Currently the only drv_flds_in fields are all shared + between only CAM and CLM. But, the fact that there are duplicated copies does mean + changes in any one of those components will need to go into the other two. + + Also removes the datm namelist files read in tools such as queryDefaultNamelist.pl. + I think this is OK, as this connection may no longer be needed. It does make the + listDefaultNamelist.pl less useful, but I think that's OK as well. + +Changes to tests or testing: + + add --mpilib option to create_test + +Code reviewed by: self,mvertens + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: regular, tools + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - PASS + + unit-tests (components/clm/src): + + yellowstone - PASS + + tools-tests (components/clm/test/tools): + + yellowstone - OK + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - OK + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - OK + yellowstone_pgi - OK + yellowstone_gnu (clm45 only) - OK + hobart_nag - OK + +CLM tag used for the baseline comparisons: clm4_5_14_r226 + + +Answer changes No bit-for-bit +-------------- + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): cime, cime_config + Update cime to cime5.3.0-alpha.02 + Add new cime_config at cime_config0.0.1.alpha.03 + +List all files eliminated: None + +List all files added and what they do: These are version 1 of the files, the ones in the driver + are now version 2. + +A components/clm/bld/namelist_files/namelist_definition_drv.xml ------- Copy from driver +A components/clm/bld/namelist_files/namelist_definition_drv_flds.xml -- Copy from driver +A components/clm/bld/namelist_files/namelist_defaults_drv.xml --------- Copy from driver + +List all existing files that have been modified, and describe the changes: + +------------ Point to new local copy of drv_flds namelist files, and bunch of whitespace changes +------------ Remove pointing to datm namelist files as they are now version 2, and the perl code +------------ currently can't read them +M components/clm/bld/queryDefaultNamelist.pl ------ Point to local location of namelist drv files + and remove pointing to datm namelist files +M components/clm/bld/CLMBuildNamelist.pm ---------- Point to local location of namelist drv files +M components/clm/bld/listDefaultNamelist.pl ------- Point to local location of namelist drv files + and remove pointing to datm namelist files + +M components/clm/cime_config/testdefs/ExpectedTestFails.xml Remove hcr_hcru test that is now passing + +------------ Get unit tests working with the new cime directory structure +M components/clm/src/CMakeLists.txt ----------------------------- New cime directory structure +M components/clm/src/unit_test_stubs/csm_share/seq_comm_mct.F90 - Just change comment as to where + the "real" file exists + +------------ Fix a couple of bugs +M components/clm/src/biogeophys/HumanIndexMod.F90 --- Fix bug 2433 format error +M components/clm/src/dyn_subgrid/dynVarMod.F90.in --- Fix bug 2432 intent issue + +=============================================================== +=============================================================== +Tag name: clm4_5_14_r228 +Originator(s): erik (Erik Kluzek) +Date: Tue Mar 7 14:17:07 MST 2017 +One-line Summary: Bring in changes that were accidentally dropped as part of the clm4_5_14_r226 tag + +Purpose of changes +------------------ + +Bring in changes that were included for the testing of clm4_5_14_r226, but accidentally dropped +when moved to the trunk tag. Only a limited amount of testing was done, since the testing was +done in the clm4_5_14_r226 tag. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): None + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): None + +Changes made to namelist defaults (e.g., changed parameter values): None + +Changes to the datasets (e.g., parameter, surface or initial files): None + +Substantial timing or memory changes: None + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers: None + +Changes to tests or testing: None + +Code reviewed by: self + +Did you follow the steps in .CLMTrunkChecklist: yes + +CLM testing: short, since full testing was done in clm4_5_14_r226 + +CLM tag used for the baseline comparisons: clm4_5_14_r227 + + +Answer changes +-------------- + +Changes answers relative to baseline: No bit-for-bit + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): None + +List all files eliminated: None + +List all files added and what they do: None + +List all existing files that have been modified, and describe the changes: + +---------- Remove --phys option to PTCLM testing +M components/clm/test/tools/nl_files/PTCLM_USUMB_clm4_5 +M components/clm/test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 +M components/clm/test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 + +M components/clm/cime_config/config_component.xml ------------ Remove unnneeded "" +M components/clm/cime_config/testdefs/ExpectedTestFails.xml -- Add note about hcru_hcru failing test +M components/clm/cime_config/testdefs/testlist_clm.xml ------- Add a test with MOSART on hobart_nag +M components/clm/src/biogeophys/SnowSnicarMod.F90 ------------ Fix bug 2479 workaround for Intel 16/17 compiler +M components/clm/src/main/initGridCellsMod.F90 --------------- Fix bug 2417 for create_crop_landunit + +=============================================================== +=============================================================== +Tag name: clm4_5_14_r227 +Originator(s): sacks (Bill Sacks) +Date: Mon Mar 6 09:42:41 MST 2017 +One-line Summary: Improve performance of dynamic landunits code + +Purpose of changes +------------------ + +Main change is to improve the performance of the column state updates portion of +the dynamic landunits code. In optimized, global runs, this piece of the code +(dyn_cnbal_col) was taking 3 - 5% of total CLM runtime. Its cost was greater in +global debug runs (~ 10 - 15%), and even greater in single-point debug runs (30 +- 40%). + +Here I have introduced a variable that tracks whether there are any changes in +area in this time step for each clump; if not, then it avoids doing most of the +work in dyn_cnbal_col. + +This tag also fixes the fortran unit tests with the new cime version: the +necessary changes were accidentally dropped from the last tag. + + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): none + +Changes to CLM's user interface (e.g., new/renamed XML or namelist variables): none + +Changes made to namelist defaults (e.g., changed parameter values): none + +Changes to the datasets (e.g., parameter, surface or initial files): none + +Substantial timing or memory changes: 3-4% performance improvement for global, +optimized runs; greater performance improvement for debug and single-point runs + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): none + +Changes to tests or testing: none + +Code reviewed by: self + +CLM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + yellowstone - not run + + unit-tests (components/clm/src): + + yellowstone - pass + + tools-tests (components/clm/test/tools): + + yellowstone - not run + + PTCLM testing (components/clm/tools/shared/PTCLM/test): + + yellowstone - not run + + regular tests (aux_clm40, aux_clm45): + + yellowstone_intel - pass + yellowstone_pgi - pass + yellowstone_gnu (clm45 only) - pass + hobart_nag - pass + +CLM tag used for the baseline comparisons: clm4_5_14_r226 + + +Answer changes +-------------- + +Changes answers relative to baseline: NO - bit-for-bit + +Detailed list of changes +------------------------ + +List any svn externals directories updated (cime, rtm, mosart, cism, etc.): none + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +========= Main changes, as noted above. Primary changes are in + dynColumnStateUpdater, but other modules needed to be changed in order + to pass the clump index down. Eventually, we should be able to get rid + of this clump index tracking, instead having a separate object for + each clump - but that is waiting on a major refactor of how we handle + threading in CLM. +M components/clm/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 +M components/clm/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 +M components/clm/src/dyn_subgrid/test/dynColumnStateUpdater_test/test_column_state_updater.pf +M components/clm/src/dyn_subgrid/dynSubgridDriverMod.F90 +M components/clm/src/dyn_subgrid/dynColumnStateUpdaterMod.F90 +M components/clm/src/biogeochem/dynConsBiogeochemMod.F90 +M components/clm/src/biogeochem/CNVegetationFacade.F90 +M components/clm/src/biogeochem/ch4Mod.F90 + +========= Fix unit tests +M components/clm/src/CMakeLists.txt +M components/clm/src/README.unit_testing + +========= Note expected failure that started failing in r226 +M components/clm/cime_config/testdefs/ExpectedTestFails.xml + +=============================================================== +=============================================================== Tag name: clm4_5_14_r226 Originator(s): erik (Erik Kluzek) Date: Thu Mar 2 15:12:50 MST 2017 diff --git a/doc/ChangeSum b/doc/ChangeSum index eac0f0accd..d7ca3328f2 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,52 @@ Tag Who Date Summary ============================================================================================================================ + clm4_5_18_r270 sacks 12/20/2017 Always use multiple elevation classes for glacier, even with stub glc + clm4_5_18_r269 erik 12/16/2017 Move externals to version in github + clm4_5_18_r268 erik 12/11/2017 Fix calculation of stomatal resistence used in dry-deposition, increase threshold of totvegc for soil decomposition to 0.1 + clm4_5_18_r267 sacks 12/07/2017 Fixes to accumulator fields + clm4_5_17_r266 sacks 11/27/2017 Avoid negative snow densities + clm4_5_17_r265 erik 11/18/2017 Update the clm50 parameter file for better behavior with prognostic crop, and fix a bug in clm50 urban model + clm4_5_17_r264 erik 11/16/2017 Changes from Dave Lawrenece on resetting soil carbon for spinup + clm4_5_17_r263 erik 11/08/2017 Drydep vel. for SO2 doubled, influence of organic mater in soil calmed, max daylength not hardwired to present day + clm4_5_16_r262 sacks 10/27/2017 Rename atm2lnd history fields for downscaled fields, properly turn on vic for clm45, and other minor fixes + clm4_5_16_r261 sacks 10/25/2017 Add option to reset snow over glacier columns + clm4_5_16_r260 erik 10/24/2017 Update paramater file for CLM50 as well as fates, fix a few issues + clm4_5_16_r259 erik 10/17/2017 Update to latest cime from cesm2_0_beta07 and config_components version 3 + clm4_5_16_r258 erik 10/06/2017 Revert change to fire, set n_melt_glcmec=10, update mosart to version that doesn't accumulate water in short rivers + clm4_5_16_r257 erik 09/29/2017 Fix two bugs found by Hui Tang, one for Carbon isotopes and one in the fire model + clm4_5_16_r256 erik 09/20/2017 Fresh snow grain radius is temperature dependent + clm4_5_16_r255 erik 09/18/2017 Changes to crop and enabling Carbon isotopes for crop and some miscellaneous small changes + clm4_5_16_r254 erik 09/01/2017 Update surface datasets, and point to new CMIP6 population density dataset + clm4_5_16_r253 erik 08/04/2017 Check on reasonable import/export from CLM, check ndep units from input file + clm4_5_16_r252 erik 07/24/2017 Update parameter file for some crop albedo issues, and fix a bug in urban albedo for nightime + clm4_5_16_r251 erik 07/14/2017 Update mksurfdata_map for soil depth/color, add new mapping files + clm4_5_16_r250 erik 07/13/2017 Update finundation dataset, new fsurdat files with updated soil color and soil depth, + update mosart areas, fix cheyenne_gnu + clm4_5_16_r249 sacks 07/06/2017 All new compsets, reworked test lists, and related fixes + clm4_5_16_r248 sacks 06/28/2017 Melt most ice runoff + clm4_5_16_r247 sacks 06/26/2017 New GLACIER_REGION field with CISM domain split in two + clm4_5_16_r246 sacks 06/14/2017 Update to latest cime + clm4_5_16_r245 sacks 06/14/2017 Only adjust glc_mec topographic heights if glc_do_dynglacier is true + clm4_5_16_r244 erik 06/09/2017 Update cime and cism externals, changes answers for IG compsets, test g17 grids, fix a few + issues, update mksurfdata_map + clm4_5_16_r243 andre 05/23/2017 History output cleanup from Dave Lawrence + clm4_5_16_r242 erik 05/21/2017 Use finundated streams for CLM50, and use ndep if it comes from cpl + clm4_5_16_r241 sacks 05/16/2017 Fix ch4 subtle dependence on processor count + clm4_5_16_r240 sacks 05/15/2017 Make glc_dyn_runoff_routing real-valued + clm4_5_16_r239 sacks 05/13/2017 Avoid division by zero in snow WindDriftCompaction + clm4_5_16_r238 andre 05/13/2017 ED is now an external library 'fates' + clm4_5_16_r237 erik 05/09/2017 Latest parameter file and some changes for CLM50, CLM45-transient changes answers also + clm4_5_15_r236 erik 05/01/2017 New surface datasets, and landuse.timeseries files, as well as interpolating initial conditions for + almost all cases + clm4_5_15_r235 sacks 04/27/2017 Zero dynbal fluxes if namelist variable is set + clm4_5_15_r234 andre 04/14/2017 Update rtm and mosart externals + clm4_5_15_r233 erik 04/11/2017 Pull out some constants and options to namelist + clm4_5_15_r232 erik 04/05/2017 Some small changes that affect both clm4_5 and clm5_0 answers (can be considered bug fixes to clm4_5) + clm4_5_14_r231 sacks 04/02/2017 Add option to reset snow pack over non-glacier columns + clm4_5_14_r230 sacks 03/31/2017 Fix dynamic landunits water and energy conservation + clm4_5_14_r229 erik 03/10/2017 Update cime and make some changes to drv_flds_in namelist, fix some minor bugs + clm4_5_14_r228 erik 03/07/2017 Bring in changes that were accidentally dropped as part of the clm4_5_14_r226 tag + clm4_5_14_r227 sacks 03/06/2017 Improve performance of dynamic landunits code clm4_5_14_r226 erik 03/02/2017 Update cime, mosart and ccism to a version that is cesm2_0_beta05 or part of beta06 clm4_5_14_r225 sacks 02/19/2017 Fix GDD accumulation in new crop columns clm4_5_14_r224 sacks 02/10/2017 Tweaks for glaciers and snow @@ -11,7 +58,8 @@ Tag Who Date Summary clm4_5_14_r218 sacks 01/13/2017 For newly initiating columns: do not copy snow state clm4_5_14_r217 sacks 01/13/2017 Bug fix for snow radiation absorption clm4_5_14_r216 erik 01/12/2017 Fix previous broken tag - clm4_5_14_r215 erik 01/12/2017 Update mksurfdata_map to work with new updated datasets from Peter, and use hand-edited surfdata/landuse.timeseries datasets for f09/f19 + clm4_5_14_r215 erik 01/12/2017 Update mksurfdata_map to work with new updated datasets from Peter, and use hand-edited + surfdata/landuse.timeseries datasets for f09/f19 clm4_5_14_r214 sacks 01/03/2017 Update column states based on dwt terms between dyn_cnbal_patch and dyn_cnbal_col, and minor fixes clm4_5_14_r213 sacks 12/30/2016 Convert buildnml to python clm4_5_14_r212 sacks 12/22/2016 Bump science version number due to changes in clm4_5_13_r211 diff --git a/doc/UsersGuide/adding_files.xml b/doc/UsersGuide/adding_files.xml index e166522b9a..18c034cbbb 100644 --- a/doc/UsersGuide/adding_files.xml +++ b/doc/UsersGuide/adding_files.xml @@ -128,7 +128,7 @@ Here's what the entry for resolutions looks like in the file: group="default_settings" valid_values= "128x256,64x128,48x96,32x64,8x16,94x192,0.23x0.31,0.47x0.63, -0.9x1.25,1.9x2.5,2.65x3.33,4x5,10x15,5x5_amazon,1x1_tropicAtl, +0.9x1.25,1.9x2.5,2.65x3.33,4x5,10x15,5x5_amazon, 1x1_camdenNJ,1x1_vancouverCAN,1x1_mexicocityMEX,1x1_asphaltjungleNJ, 1x1_brazil,1x1_urbanc_alpha,0.5x0.5"> Horizontal resolutions @@ -144,7 +144,7 @@ add these resolutions to the the sitespf_pt name. The entry in that file looks like: <entry id="sitespf_pt" -valid_values="none,1x1_brazil,1x1_tropicAtl,5x5_amazon, +valid_values="none,1x1_brazil,5x5_amazon, 1x1_camdenNJ,1x1_vancouverCAN,1x1_mexicocityMEX,1x1_asphaltjungleNJ, 1x1_urbanc_alpha,1x1_numaIA,1x1_smallvilleIA" value="none" category="physics"> diff --git a/parse_cime.cs.status b/parse_cime.cs.status index a4bde25005..7a7e285907 100755 --- a/parse_cime.cs.status +++ b/parse_cime.cs.status @@ -37,7 +37,7 @@ sub GetNameNDir { } else { $scrdir = $cwd; } - return( $ProgName ); + return( $ProgName, $scrdir ); } @@ -53,6 +53,7 @@ REQUIRED OPTIONS At least one file needs to be given, but you can also give a list of space seperated files. OPTIONS + -die_on_duplicate Die if find a duplicate testname -summarize [or -s] Summarize results into lists of tests in categories (pend, pass, fail etc.) -sum_results_perline Summarize results categories of each test into one line -help [or -h] Print usage to STDOUT. @@ -73,6 +74,7 @@ sub process_cmdline { csstatusfiles_ref => undef, sumintocats => 0, sumperline => 0, + dieondup => 0, help => 0, verbose => 0, ); @@ -80,6 +82,7 @@ sub process_cmdline { GetOptions( "h|help" => \$opts{'help'}, "s|summarize" => \$opts{'sumintocats'}, + "die_on_duplicate" => \$opts{'dieondup'}, "sum_results_perline" => \$opts{'sumperline'}, "v|verbose" => \$opts{'verbose'}, ) or usage($ProgName); @@ -178,7 +181,7 @@ sub absolute_path { sub run_csstatus { # run a cs.status file and parse it's output - my ( $csstatusfilename, $verbose, $csstatus_ref ) = @_; + my ( $csstatusfilename, $verbose, $csstatus_ref, $dieondup ) = @_; if ( ! -x $csstatusfilename ) { die "ERROR: cs.status file does NOT exist or can not execute: $csstatusfilename\n"; @@ -196,12 +199,18 @@ sub run_csstatus { my $over = $2; my $fails = ""; my $passes = ""; my $pendings = ""; my $newline; + my $bfail = 0; if ( $verbose ) { print "$test\n"; } do { $newline = shift(@lines); if ( $newline =~ /FAIL[ ]+$test ([^ ]+)/ ) { $fails .= " $1"; chomp( $fails ); + if ( $1 eq "BASELINE" ) { + if ( $newline =~ /ERROR BFAIL baseline directory/ ) { + $bfail = 1; + } + } } elsif ( $newline =~ /PASS[ ]+$test ([^ ]+)/ ) { $passes .= " $1"; chomp( $passes ); @@ -222,27 +231,30 @@ sub run_csstatus { if ( $over eq "NLCOMP" ) { $over = "PASS"; } - if ( $over eq "FAIL" && $fails =~ /MEMLEAK/ ) { - $over = "PASS"; - } - if ( $over eq "FAIL" && $fails =~ /MEMCOMP/ ) { - $over = "PASS"; + if ( $over eq "FAIL" && ($fails =~ /MEMLEAK/ || $fails =~ /TPUTCOMP/ || $fails =~ /MEMCOMP/) ) { + my $status = $fails; + $status =~ s/MEMLEAK//; + $status =~ s/TPUTCOMP//; + $status =~ s/MEMCOMP//; + $status =~ s/NLCOMP//; + $status =~ s/BASELINE//; + if ( $status =~ /^\s*$/ ) { + $over = "PASS"; + } } if ( $over eq "DIFF" ) { - my $file = glob( "${test}.*$csdate/TestStatus" ); - my $result = " "; - if ( -f $file ) { - $result = `grep "ERROR baseline directory" $file`; - } else { - if ( $verbose ) { print( "Bad file: $file\n" ); } - } - if ( $result =~ /ERROR/ ) { + if ( $bfail ) { $over = "FAIL_BDNE"; } else { $over = "DIFF"; } } - if ( exists($$csstatus_ref{$test}) ) { next; } + if ( exists($$csstatus_ref{$test}) ) { + if ( $dieondup ) { + die "ERROR: Already had a test that matches this one: $test\n"; + } + next; + } $$csstatus_ref{$test}{'over'} = $over; $$csstatus_ref{$test}{'FAIL'} = $fails; $$csstatus_ref{$test}{'PASS'} = $passes; @@ -294,12 +306,15 @@ sub print_sumperline { sub print_categories { # Seperate tests into categories + my $scrdir = shift(@_); my %csstatus = @_; + my $expectedfailfile = "$scrdir/components/clm/cime_config/testdefs/ExpectedTestFails.xml"; my @passes; my @fails; my @pendings; my @compares_diff; + my @compares_diff_nobase; my @keys = sort( keys(%csstatus) ); foreach my $key ( @keys ) { if ( $csstatus{$key}{'over'} eq "PASS" ) { @@ -309,7 +324,7 @@ sub print_categories { push( @compares_diff, $key ); } elsif ( $csstatus{$key}{'over'} eq "FAIL_BDNE" ) { push( @passes, $key ); - push( @compares_diff, $key ); + push( @compares_diff_nobase, $key ); } elsif ( $csstatus{$key}{'over'} eq "FAIL" ) { push( @fails, $key ); } elsif ( $csstatus{$key}{'over'} eq "PEND" ) { @@ -324,6 +339,7 @@ sub print_categories { printf( "%d Tests pending\n", $#pendings+1 ); printf( "%d Tests passed\n", $#passes+1 ); printf( "%d Tests compare different to baseline\n", $#compares_diff+1 ); + printf( "%d Tests are new where there is no baseline\n", $#compares_diff_nobase+1 ); printf( "%d Tests failed\n", $#fails+1 ); print( "================================================================================\n" ); @@ -340,7 +356,10 @@ sub print_categories { print( "These tests passed\n" ); print( "================================================================================\n" ); foreach my $key ( @passes ) { - print( "$key\n" ); + my $expect = ""; + `grep $key $expectedfailfile > /dev/null`; + if ( $? == 0 ) { $expect = "FAILED PREVIOUSLY"; } + print( "$key\t\t\t$expect\n" ); } } if ( $#compares_diff >= 0 ) { @@ -351,12 +370,23 @@ sub print_categories { print( "$key\n" ); } } + if ( $#compares_diff_nobase >= 0 ) { + print( "================================================================================\n" ); + print( "These tests don't have a baseline to compare to\n" ); + print( "================================================================================\n" ); + foreach my $key ( @compares_diff_nobase ) { + print( "$key\n" ); + } + } if ( $#fails >= 0 ) { print( "================================================================================\n" ); print( "These tests failed\n" ); print( "================================================================================\n" ); foreach my $key ( @fails ) { - print( "$key\n" ); + my $expect = ""; + `grep $key $expectedfailfile > /dev/null`; + if ( $? == 0 ) { $expect = "EXPECTED"; } + print( "$key\t\t$expect\n" ); } } } @@ -365,20 +395,20 @@ sub print_categories { sub main { # main subroutine - my ($ProgName ) = &GetNameNDir( ); + my ($ProgName, $scrdir) = &GetNameNDir( ); my $pwd = `pwd`; chomp( $pwd ); my %opts = &process_cmdline( $ProgName ); my %csstatus; my $files_ref = $opts{'csstatusfiles_ref'}; foreach my $file ( @$files_ref ) { - &run_csstatus( "$pwd/$file", $opts{'verbose'}, \%csstatus ); + &run_csstatus( "$pwd/$file", $opts{'verbose'}, \%csstatus, $opts{'dieondup'} ); } if ( $opts{'verbose'} ) { print "Print summary of testing:\n"; } if ( $opts{'sumintocats'} ) { - &print_categories( %csstatus ); + &print_categories( $scrdir, %csstatus ); } elsif ( $opts{'sumperline'} ) { &print_sumperline( %csstatus ); } else { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 66892499ac..4d392b1fb1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,11 @@ cmake_minimum_required(VERSION 2.8) + +list(APPEND CMAKE_MODULE_PATH ${CIME_CMAKE_MODULE_DIRECTORY}) +include(CIME_initial_setup) + project(clm45_tests Fortran C) -list(APPEND CMAKE_MODULE_PATH ${CESM_CMAKE_MODULE_DIRECTORY}) -include(CESM_utils) +include(CIME_utils) set(CLM_ROOT "..") set(CESM_ROOT "${CLM_ROOT}/../../") @@ -14,9 +17,10 @@ add_definitions(-DHIDE_MPI) # done first, so that in case of name collisions, the CLM versions take # precedence (when there are two files with the same name, the one added later # wins). -add_subdirectory(${CESM_ROOT}/cime/share/csm_share/shr csm_share) -add_subdirectory(${CESM_ROOT}/cime/share/esmf_wrf_timemgr esmf_wrf_timemgr) -add_subdirectory(${CESM_ROOT}/cime/driver_cpl/shr drv_share) +add_subdirectory(${CESM_ROOT}/cime/src/share/util csm_share) +add_subdirectory(${CESM_ROOT}/cime/src/share/unit_test_stubs/util csm_share_stubs) +add_subdirectory(${CESM_ROOT}/cime/src/share/esmf_wrf_timemgr esmf_wrf_timemgr) +add_subdirectory(${CESM_ROOT}/cime/src/drivers/mct/shr drv_share) # Extract just the files we need from drv_share set (drv_sources_needed_base @@ -32,7 +36,6 @@ add_subdirectory(${CLM_ROOT}/src/biogeophys clm_biogeophys) add_subdirectory(${CLM_ROOT}/src/dyn_subgrid clm_dyn_subgrid) add_subdirectory(${CLM_ROOT}/src/main clm_main) add_subdirectory(${CLM_ROOT}/src/init_interp clm_init_interp) -add_subdirectory(${CLM_ROOT}/src/ED/main ed_main) # Add general unit test directories (stubbed out files, etc.) add_subdirectory(unit_test_stubs) @@ -51,7 +54,7 @@ foreach (sourcefile ${share_sources}) endif() endforeach() -# Build libraries containing stuff needed for the unit tests. +# Build libraries containing stuff needed for the unit tests. # Eventually, these add_library calls should probably be distributed into the correct location, rather than being in this top-level CMakeLists.txt file. add_library(csm_share ${share_sources} ${drv_sources_needed}) declare_generated_dependencies(csm_share "${share_genf90_sources}") @@ -62,11 +65,11 @@ add_dependencies(esmf_wrf_timemgr csm_share) add_dependencies(clm csm_share esmf_wrf_timemgr) # We need to look for header files here, in order to pick up shr_assert.h -include_directories(${CESM_ROOT}/cime/share/csm_share/include) +include_directories(${CESM_ROOT}/cime/src/share/include) # And we need to look for header files here, for some include files needed by # the esmf_wrf_timemgr code -include_directories(${CESM_ROOT}/cime/share/esmf_wrf_timemgr) +include_directories(${CESM_ROOT}/cime/src/share/esmf_wrf_timemgr) # Tell cmake to look for libraries & mod files here, because this is where we built libraries include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/src/ED/biogeochem/EDCanopyStructureMod.F90 b/src/ED/biogeochem/EDCanopyStructureMod.F90 deleted file mode 100755 index 34bff850e1..0000000000 --- a/src/ED/biogeochem/EDCanopyStructureMod.F90 +++ /dev/null @@ -1,710 +0,0 @@ -module EDCanopyStructureMod - - ! ============================================================================ - ! Code to determine whether the canopy is closed, and which plants are either in the understorey or overstorey - ! This is obviosuly far too complicated for it's own good and needs re-writing. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8; - use clm_varctl , only : iulog - use pftconMod , only : pftcon - use EDGrowthFunctionsMod , only : c_area - use EDCohortDynamicsMod , only : copy_cohort, terminate_cohorts, fuse_cohorts - use EDtypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type, ncwd - use EDtypesMod , only : cp_nclmax - use EDtypesMod , only : numpft_ed - use shr_log_mod , only : errMsg => shr_log_errMsg - use abortutils , only : endrun - - implicit none - private - - public :: canopy_structure - public :: canopy_spread - public :: calc_areaindex - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - - ! 10/30/09: Created by Rosie Fisher - ! ============================================================================ - -contains - - ! ============================================================================ - subroutine canopy_structure( currentSite ) - ! - ! !DESCRIPTION: - ! create cohort instance - ! - ! This routine allocates the 'canopy_layer' attribute to each cohort - ! All top leaves in the same canopy layer get the same light resources. - ! The first canopy layer is the 'canopy' or 'overstorey'. The second is the 'understorey'. - ! More than two layers is not permitted at the moment - ! Seeds germinating into the 3rd or higher layers are automatically removed. - ! - ! ------Perfect Plasticity----- - ! The idea of these canopy layers derives originally from Purves et al. 2009 - ! Their concept is that, given enoughplasticity in canopy position, size, shape and depth - ! all of the gound area will be filled perfectly by leaves, and additional leaves will have - ! to exist in the understorey. - ! Purves et al. use the concept of 'Z*' to assume that the height required to attain a place in the - ! canopy is spatially uniform. In this implementation, described in Fisher et al. (2010, New Phyt) we - ! extent that concept to assume that position in the canopy has some random element, and that BOTH height - ! and chance combine to determine whether trees get into the canopy. - ! Thus, when the canopy is closed and there is excess area, some of it must be demoted - ! If we demote -all- the trees less than a given height, there is a massive advantage in being the cohort that is - ! the biggest when the canopy is closed. - ! In this implementation, the amount demoted, ('weight') is a function of the height weighted by the competitive exclusion - ! parameter (ED_val_comp_excln). - - ! Complexity in this routine results from a few things. - ! Firstly, the complication of the demotion amount sometimes being larger than the cohort area (for a very small, short cohort) - ! Second, occasionaly, disturbance (specifically fire) can cause the canopy layer to become less than closed, - ! without changing the area of the patch. If this happens, then some of the plants in the lower layer need to be 'promoted' so - ! all of the routine has to happen in both the downwards and upwards directions. - ! - ! The order of events here is therefore: - ! (The entire subroutine has a single outer 'patch' loop. - ! Section 1: figure out the total area, and whether there are >1 canopy layers at all. - ! - ! Sorts out cohorts into canopy and understorey layers... - ! - ! !USES: - - use EDParamsMod, only : ED_val_comp_excln, ED_val_ag_biomass - use SFParamsMod, only : SF_val_cwd_frac - use EDtypesMod , only : ncwd, min_patch_area, cp_nlevcan - ! - ! !ARGUMENTS - type(ed_site_type) , intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort,copyc - integer :: i,j - integer :: z ! Current number of canopy layers. (1= canopy, 2 = understorey) - real(r8) :: checkarea - real(r8) :: cc_loss - real(r8) :: lossarea - real(r8) :: newarea - real(r8) :: arealayer(cp_nlevcan) ! Amount of plant area currently in each canopy layer - real(r8) :: sumdiff(cp_nlevcan) ! The total of the exclusion weights for all cohorts in layer z - real(r8) :: weight ! The amount of the total lost area that comes from this cohort - real(r8) :: sum_weights(cp_nlevcan) - real(r8) :: new_total_area_check - real(r8) :: missing_area, promarea,cc_gain,sumgain - integer :: promswitch,lower_cohort_switch - integer :: c - real(r8) :: sumloss,excess_area - integer :: count_mi - !---------------------------------------------------------------------- - - currentPatch => currentSite%oldest_patch - - ! Section 1: Check total canopy area. - - new_total_area_check = 0._r8 - do while (associated(currentPatch)) ! Patch loop - - if (currentPatch%area .gt. min_patch_area) then ! avoid numerical weirdness that shouldn't be happening anyway - - excess_area = 1.0_r8 - - ! Does any layer have excess area in it? Keep going until it does not... - - do while(excess_area > 0.000001_r8) - - ! Calculate the area currently in each canopy layer. - z = 1 - arealayer = 0.0_r8 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - currentCohort%c_area = c_area(currentCohort) ! Reassess cohort area. - arealayer(currentCohort%canopy_layer) = arealayer(currentCohort%canopy_layer) + currentCohort%c_area - z = max(z,currentCohort%canopy_layer) ! What is the current number of canopy layers? - currentCohort => currentCohort%shorter - enddo - - ! Does the bottom layer have more than a full canopy? If so we need to make another layer. - - if(arealayer(z) > currentPatch%area)then ! Do we have too much area in either layer? - !write(iulog,*) 'CANOPY CLOSURE', z - z = z + 1 - endif - - currentPatch%NCL_p = min(cp_nclmax,z) ! Set current canopy layer occupancy indicator. - - do i = 1,z ! Loop around the currently occupied canopy layers. - - do while((arealayer(i)-currentPatch%area) > 0.000001_r8) - ! Is this layer currently over-occupied? - ! In that case, we need to work out which cohorts to demote. - - sumloss = 0.0_r8 - new_total_area_check = 0.0_r8 - sumdiff(i) = 0.0_r8 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - currentCohort%c_area = c_area(currentCohort) - if(arealayer(i) > currentPatch%area.and.currentCohort%canopy_layer == i)then - currentCohort%excl_weight = 1.0_r8/(currentCohort%dbh**ED_val_comp_excln) - sumdiff(i) = sumdiff(i) + currentCohort%excl_weight - endif - currentCohort => currentCohort%shorter - enddo !currentCohort - - lossarea = arealayer(i) - currentPatch%area !how much do we have to lose? - sum_weights(i) = 0.0_r8 - currentCohort => currentPatch%tallest !start from the tallest cohort - - ! Correct the demoted cohorts for - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i) then - weight = currentCohort%excl_weight/sumdiff(i) - currentCohort%excl_weight = min(currentCohort%c_area/lossarea, weight) - sum_weights(i) = sum_weights(i) + currentCohort%excl_weight - endif - currentCohort => currentCohort%shorter - enddo - - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i)then !All the trees in this layer need to lose some area... - weight = currentCohort%excl_weight/sum_weights(i) - cc_loss = lossarea*weight !what this cohort has to lose. - !-----------Split and copy boundary cohort-----------------! - if(cc_loss < currentCohort%c_area)then - allocate(copyc) - - call copy_cohort(currentCohort, copyc) !makes an identical copy... - ! n.b this needs to happen BEFORE the cohort goes into the new layer, - ! otherwise currentPatch%spread(i+1) will be higher and the area will change...!!! - sumloss = sumloss + cc_loss - - newarea = currentCohort%c_area - cc_loss - copyc%n = currentCohort%n*newarea/currentCohort%c_area ! - currentCohort%n = currentCohort%n - (currentCohort%n*newarea/currentCohort%c_area) ! - - copyc%canopy_layer = i !the taller cohort is the copy - currentCohort%canopy_layer = i + 1 !demote the current cohort to the understory. - ! seperate cohorts. - ! - 0.000000000001_r8 !needs to be a very small number to avoid - ! causing non-linearity issues with c_area. is this really required? - currentCohort%dbh = currentCohort%dbh - copyc%dbh = copyc%dbh !+ 0.000000000001_r8 - !kill the ones which go into canopy layers that are not allowed... (default nclmax=2) - if(i+1 > cp_nclmax)then - !put the litter from the terminated cohorts into the fragmenting pools - ! write(iulog,*) '3rd canopy layer' - do c=1,ncwd - - currentPatch%CWD_AG(c) = currentPatch%CWD_AG(c) + (currentCohort%bdead+currentCohort%bsw) * & - ED_val_ag_biomass * & - SF_val_CWD_frac(c)*currentCohort%n/currentPatch%area - - currentPatch%CWD_BG(c) = currentPatch%CWD_BG(c) + (currentCohort%bdead+currentCohort%bsw) * & - (1.0_r8-ED_val_ag_biomass) * & - SF_val_CWD_frac(c)*currentCohort%n/currentPatch%area !litter flux per m2. - - enddo - - currentPatch%leaf_litter(currentCohort%pft) = & - currentPatch%leaf_litter(currentCohort%pft) + (currentCohort%bl)* & - currentCohort%n/currentPatch%area ! leaf litter flux per m2. - - currentPatch%root_litter(currentCohort%pft) = & - currentPatch%root_litter(currentCohort%pft) + & - (currentCohort%br+currentCohort%bstore)*currentCohort%n/currentPatch%area - - currentCohort%n = 0.0_r8 - currentCohort%c_area = 0._r8 - else - currentCohort%c_area = c_area(currentCohort) - endif - copyc%c_area = c_area(copyc) - new_total_area_check = new_total_area_check+copyc%c_area - - !----------- Insert copy into linked list ------------------------! - copyc%shorter => currentCohort - if(associated(currentCohort%taller))then - copyc%taller => currentCohort%taller - currentCohort%taller%shorter => copyc - else - currentPatch%tallest => copyc - copyc%taller => null() - endif - currentCohort%taller => copyc - else - currentCohort%canopy_layer = i + 1 !the whole cohort becomes demoted - sumloss = sumloss + currentCohort%c_area - - !kill the ones which go into canopy layers that are not allowed... (default cp_nclmax=2) - if(i+1 > cp_nclmax)then - !put the litter from the terminated cohorts into the fragmenting pools - do c=1,ncwd - - currentPatch%CWD_AG(c) = currentPatch%CWD_AG(c) + (currentCohort%bdead+currentCohort%bsw) * & - ED_val_ag_biomass * & - SF_val_CWD_frac(c)*currentCohort%n/currentPatch%area - currentPatch%CWD_BG(c) = currentPatch%CWD_BG(c) + (currentCohort%bdead+currentCohort%bsw) * & - (1.0_r8-ED_val_ag_biomass) * & - SF_val_CWD_frac(c)*currentCohort%n/currentPatch%area !litter flux per m2. - - enddo - - currentPatch%leaf_litter(currentCohort%pft) = & - currentPatch%leaf_litter(currentCohort%pft) + currentCohort%bl* & - currentCohort%n/currentPatch%area ! leaf litter flux per m2. - - currentPatch%root_litter(currentCohort%pft) = & - currentPatch%root_litter(currentCohort%pft) + & - (currentCohort%br+currentCohort%bstore)*currentCohort%n/currentPatch%area - currentCohort%n = 0.0_r8 - currentCohort%c_area = 0._r8 - - else - currentCohort%c_area = c_area(currentCohort) - endif - - !write(iulog,*) 'demoting whole cohort', currentCohort%c_area,cc_loss, & - !currentCohort%canopy_layer,currentCohort%dbh - - endif - ! call terminate_cohorts(currentPatch) - - !----------- End of cohort splitting ------------------------------! - endif !canopy layer = i - - currentCohort => currentCohort%shorter - - enddo !currentCohort - - call terminate_cohorts(currentPatch) - arealayer(i) = arealayer(i) - sumloss - !Update arealayer for diff calculations of layer below. - arealayer(i + 1) = arealayer(i + 1) + sumloss - - enddo !arealayer loop - if(arealayer(i)-currentPatch%area > 0.00001_r8)then - write(iulog,*) 'lossarea problem', lossarea,sumloss,z,currentPatch%patchno,currentPatch%clm_pno - endif - - enddo !z - - z = 1 - arealayer = 0.0_r8 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - currentCohort%c_area = c_area(currentCohort) - arealayer(currentCohort%canopy_layer) = arealayer(currentCohort%canopy_layer) + currentCohort%c_area - z = max(z,currentCohort%canopy_layer) - currentCohort => currentCohort%shorter - enddo - - !does the bottom layer have more than a full canopy? If so we need to make another layer. - if(arealayer(z) > currentPatch%area)then - z = z + 1 - endif - excess_area = 0.0_r8 - do j=1,z - if(arealayer(j) > currentPatch%area)then - excess_area = arealayer(j)-currentPatch%area - endif - enddo - currentPatch%ncl_p = min(z,cp_nclmax) - - enddo !is there still excess area in any layer? - - call terminate_cohorts(currentPatch) - call fuse_cohorts(currentPatch) - call terminate_cohorts(currentPatch) - - ! ----------- Check cohort area ------------------------------! - do i = 1,z - checkarea = 0.0_r8 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i)then - checkarea = checkarea + c_area(currentCohort) - endif - - currentCohort=>currentCohort%shorter - - enddo - - enddo ! - - - ! ----------- Check whether the intended 'full' layers are actually filling all the space. - ! If not, promote some fraction of cohorts upwards ------------------------------! - ! THIS SECTION MIGHT BE TRIGGERED BY A FIRE OR MORTALITY EVENT, FOLLOWED BY A PATCH FUSION, - ! SO THE TOP LAYER IS NO LONGER FULL... - - promswitch = 0 - - missing_area=1.0_r8 - count_mi = 0 - !does any layer have excess area in it? keep going until it does not... - do while(missing_area > 0.000001_r8.and.z > 1) - count_mi = count_mi +1 - do i = 1,z-1 ! if z is greater than one, there is a possibility of too many plants in the understorey. - lower_cohort_switch = 1 - ! is the area of the layer less than the area of the patch, if it is supposed to be closed (z>1) - do while((arealayer(i)-currentPatch%area) < -0.000001_r8.and.lower_cohort_switch == 1) - - if(arealayer(i+1) <= 0.000001_r8)then - currentCohort => currentPatch%tallest - arealayer = 0._r8 - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i+1)then !look at the cohorts in the canopy layer below... - currentCohort%canopy_layer = i - currentCohort%c_area = c_area(currentCohort) - - ! write(iulog,*) 'promoting very small cohort', currentCohort%c_area,currentCohort%canopy_layer - endif - arealayer(currentCohort%canopy_layer) = arealayer(currentCohort%canopy_layer)+currentCohort%c_area - currentCohort => currentCohort%shorter - enddo - - endif !promoting all of the small amount of area in the lower layers. - - - lower_cohort_switch = 0 - sumgain = 0.0_r8 - sumdiff(i) = 0.0_r8 - ! figure out with what weighting we need to promote cohorts. - ! This is the opposite of the demotion weighting... - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - currentCohort%c_area = c_area(currentCohort) - if(currentCohort%canopy_layer == i+1)then !look at the cohorts in the canopy layer below... - currentCohort%prom_weight = currentCohort%dbh**ED_val_comp_excln !as opposed to 1/(dbh^C_e) - sumdiff(i) = sumdiff(i) + currentCohort%prom_weight - endif - currentCohort => currentCohort%shorter - enddo !currentCohort - - promarea = currentPatch%area -arealayer(i) !how much do we need to gain? - sum_weights(i) = 0.0_r8 - currentCohort => currentPatch%tallest !start from the tallest cohort - - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i+1) then !still looking at the layer beneath. - weight = currentCohort%prom_weight/sumdiff(i) - if(promarea > 0._r8)then - currentCohort%prom_weight = min(currentCohort%c_area/promarea, weight) - else - currentCohort%prom_weight = 0._r8 - endif - sum_weights(i) = sum_weights(i) + currentCohort%prom_weight - endif - currentCohort => currentCohort%shorter - enddo - - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i+1)then !All the trees in this layer need to promote some area upwards... - lower_cohort_switch = 1 - weight = currentCohort%prom_weight/sum_weights(i) - cc_gain = promarea*weight !what this cohort has to promote. - !-----------Split and copy boundary cohort-----------------! - if(cc_gain < currentCohort%c_area)then - allocate(copyc) - - call copy_cohort(currentCohort, copyc) !makes an identical copy... - ! n.b this needs to happen BEFORE the cohort goes into the new layer, otherwise currentPatch - ! %spread(+1) will be higher and the area will change...!!! - sumgain = sumgain + cc_gain - - - newarea = currentCohort%c_area - cc_gain !new area of existing cohort - copyc%n = currentCohort%n*cc_gain/currentCohort%c_area !number of individuals in promoted cohort. - ! number of individuals in cohort remianing in understorey - currentCohort%n = currentCohort%n - (currentCohort%n*cc_gain/currentCohort%c_area) - - currentCohort%canopy_layer = i+1 !keep current cohort in the understory. - copyc%canopy_layer = i ! promote copy to the higher canopy layer. - - ! seperate cohorts. - ! needs to be a very small number to avoid causing non-linearity issues with c_area. - ! is this really required? - currentCohort%dbh = currentCohort%dbh - 0.000000000001_r8 - copyc%dbh = copyc%dbh + 0.000000000001_r8 - - currentCohort%c_area = c_area(currentCohort) - copyc%c_area = c_area(copyc) - - !----------- Insert copy into linked list ------------------------! - copyc%shorter => currentCohort - if(associated(currentCohort%taller))then - copyc%taller => currentCohort%taller - currentCohort%taller%shorter => copyc - else - currentPatch%tallest => copyc - copyc%taller => null() - endif - currentCohort%taller => copyc - else - currentCohort%canopy_layer = i !the whole cohort becomes promoted - sumgain = sumgain + currentCohort%c_area !inserting deliberate mistake to see how far we make it... - ! update area AFTER we sum up the losses. the cohort may shrink at this point, - ! if the upper canopy spread is smaller. this shold be dealt with by the 'excess area' loop. - currentCohort%c_area = c_area(currentCohort) - - promswitch = 1 - - ! write(iulog,*) 'promoting whole cohort', currentCohort%c_area,cc_gain,currentCohort%canopy_layer, & - !currentCohort%pft,currentPatch%patchno - - endif - !call terminate_cohorts(currentPatch) - if(promswitch == 1)then - ! write(iulog,*) 'cohort loop',currentCohort%pft,currentCohort%indexnumber,currentPatch%patchno - endif - !----------- End of cohort splitting ------------------------------! - else - if(promswitch == 1)then - ! write(iulog,*) 'cohort list',currentCohort%pft,currentCohort%indexnumber, & - ! currentCohort%canopy_layer,currentCohort%c_area - endif - endif - - currentCohort => currentCohort%shorter - enddo !currentCohort - arealayer(i) = arealayer(i) + sumgain - arealayer(i + 1) = arealayer(i + 1) - sumgain !Update arealayer for diff calculations of layer below. - - if(promswitch == 1)then - ! write(iulog,*) 'arealayer loop',arealayer(1:3),currentPatch%area,promarea,sumgain, & - !currentPatch%patchno,z,i,lower_cohort_switch - endif - if(promswitch == 1.and.associated(currentPatch%tallest))then - ! write(iulog,*) 'cohorts',currentCohort%pft,currentCohort%indexnumber,currentPatch%patchno, & - !currentCohort%c_area - endif - enddo !arealayer loop - - if(currentPatch%area-arealayer(i) < 0.000001_r8)then - !write(iulog,*) 'gainarea problem',sumgain,arealayer(i),currentPatch%area,z, & - !currentPatch%patchno,currentPatch%clm_pno,currentPatch%area - arealayer(i),i,missing_area,count_mi - endif - if(promswitch == 1)then - ! write(iulog,*) 'z loop',arealayer(1:3),currentPatch%patchno,z - endif - enddo !z - - z = 1 - arealayer = 0.0_r8 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - currentCohort%c_area = c_area(currentCohort) - arealayer(currentCohort%canopy_layer) = arealayer(currentCohort%canopy_layer) + currentCohort%c_area - z = max(z,currentCohort%canopy_layer) - currentCohort => currentCohort%shorter - enddo - - missing_area = 0.0_r8 - do j=1,z-1 - if(arealayer(j) < currentPatch%area)then !this is the amount of area that we still have spare in this layer. - missing_area = currentPatch%area - arealayer(j) - if(missing_area <= 0.000001_r8.and.missing_area > 0._r8)then - missing_area = 0.0_r8 - ! write(iulog,*) 'correcting MI',j,currentPatch%area - arealayer(j) - endif - endif - enddo - currentPatch%ncl_p = min(z,cp_nclmax) - if(promswitch == 1)then - ! write(iulog,*) 'missingarea loop',arealayer(1:3),currentPatch%patchno,missing_area,z - endif - enddo !is there still not enough canopy area in any layer? - - call terminate_cohorts(currentPatch) - call fuse_cohorts(currentPatch) - call terminate_cohorts(currentPatch) - - if(promswitch == 1)then - !write(iulog,*) 'going into cohort check',currentPatch%clm_pno - endif - ! ----------- Check cohort area ------------------------------! - do i = 1,z - checkarea = 0.0_r8 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i)then - checkarea = checkarea + c_area(currentCohort) - endif - - currentCohort => currentCohort%shorter - - enddo - - if(((checkarea-currentPatch%area)) > 0.0001)then - write(iulog,*) 'problem with canopy area', checkarea,currentPatch%area,checkarea-currentPatch%area,i,z,missing_area - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - if(currentCohort%canopy_layer == i)then - write(iulog,*) 'c_areas in top layer', c_area(currentCohort) - endif - currentCohort => currentCohort%shorter - - enddo - - endif - - if ( i > 1) then - if ( (arealayer(i) - arealayer(i-1) )>1e-11 ) then - write(iulog,*) 'smaller top layer than bottom layer ',arealayer(i),arealayer(i-1), & - currentPatch%area,currentPatch%spread(i-1:i) - endif - endif - enddo ! - - if(promswitch == 1)then - ! write(iulog,*) 'end patch loop',currentSite%clmgcell - endif - - else !terminate logic to only do if patch_area_sufficiently large - write(iulog,*) 'canopy_structure: patch area too small.', currentPatch%area - end if - - - currentPatch => currentPatch%younger - enddo !patch - - if(promswitch == 1)then - ! write(iulog,*) 'end canopy structure',currentSite%clmgcell - endif - - end subroutine canopy_structure - - ! ============================================================================ - subroutine canopy_spread( currentSite ) - ! - ! !DESCRIPTION: - ! Calculates the spatial spread of tree canopies based on canopy closure. - ! - ! !USES: - use EDTypesMod , only : cp_nlevcan - use EDParamsMod , only : ED_val_maxspread, ED_val_minspread - ! - ! !ARGUMENTS - type (ed_site_type), intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type), pointer :: currentCohort - type (ed_patch_type) , pointer :: currentPatch - real(r8) :: arealayer(cp_nlevcan) ! Amount of canopy in each layer. - real(r8) :: inc ! Arbitrary daily incremental change in canopy area - integer :: z - !---------------------------------------------------------------------- - - inc = 0.005_r8 - - currentPatch => currentSite%oldest_patch - - do while (associated(currentPatch)) - - !calculate canopy area in each canopy storey... - arealayer = 0.0_r8 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - currentCohort%c_area = c_area(currentCohort) - if(pftcon%woody(currentCohort%pft) == 1)then - arealayer(currentCohort%canopy_layer) = arealayer(currentCohort%canopy_layer) + currentCohort%c_area - endif - currentCohort => currentCohort%shorter - enddo - - !If the canopy area is approaching closure, squash the tree canopies and make them taller and thinner - do z = 1,cp_nclmax - - if(arealayer(z)/currentPatch%area > 0.9_r8)then - currentPatch%spread(z) = currentPatch%spread(z) - inc - else - currentPatch%spread(z) = currentPatch%spread(z) + inc - endif - if(currentPatch%spread(z) >= ED_val_maxspread)then - currentPatch%spread(z) = ED_val_maxspread - endif - if(currentPatch%spread(z) <= ED_val_minspread)then - currentPatch%spread(z) = ED_val_minspread - endif - enddo !z - !write(iulog,*) 'spread',currentPatch%spread(1:2) - !currentPatch%spread(:) = ED_val_maxspread - !FIX(RF,033114) spread is off - !write(iulog,*) 'canopy_spread',currentPatch%area,currentPatch%spread(1:2) - currentPatch => currentPatch%younger - - enddo !currentPatch - - end subroutine canopy_spread - - ! ===================================================================================== - - function calc_areaindex(cpatch,ai_type) result(ai) - - ! ---------------------------------------------------------------------------------- - ! This subroutine calculates the exposed leaf area index of a patch - ! this is the square meters of leaf per square meter of ground area - ! It does so by integrating over the depth and functional type profile of leaf area - ! which are per area of crown. This value has to be scaled by crown area to convert - ! to ground area. - ! ---------------------------------------------------------------------------------- - - ! Arguments - type(ed_patch_type),intent(in), target :: cpatch - character(len=*),intent(in) :: ai_type - - integer :: cl,ft - real(r8) :: ai - ! TODO: THIS MIN LAI IS AN ARTIFACT FROM TESTING LONG-AGO AND SHOULD BE REMOVED - ! THIS HAS BEEN KEPT THUS FAR TO MAINTAIN B4B IN TESTING OTHER COMMITS - real(r8),parameter :: ai_min = 0.1_r8 - real(r8),pointer :: ai_profile - - ai = 0._r8 - if (trim(ai_type) == 'elai') then - do cl = 1,cpatch%NCL_p - do ft = 1,numpft_ed - ai = ai + sum(cpatch%canopy_area_profile(cl,ft,1:cpatch%nrad(cl,ft)) * & - cpatch%elai_profile(cl,ft,1:cpatch%nrad(cl,ft))) - enddo - enddo - elseif (trim(ai_type) == 'tlai') then - do cl = 1,cpatch%NCL_p - do ft = 1,numpft_ed - ai = ai + sum(cpatch%canopy_area_profile(cl,ft,1:cpatch%nrad(cl,ft)) * & - cpatch%tlai_profile(cl,ft,1:cpatch%nrad(cl,ft))) - enddo - enddo - elseif (trim(ai_type) == 'esai') then - do cl = 1,cpatch%NCL_p - do ft = 1,numpft_ed - ai = ai + sum(cpatch%canopy_area_profile(cl,ft,1:cpatch%nrad(cl,ft)) * & - cpatch%esai_profile(cl,ft,1:cpatch%nrad(cl,ft))) - enddo - enddo - elseif (trim(ai_type) == 'tsai') then - do cl = 1,cpatch%NCL_p - do ft = 1,numpft_ed - ai = ai + sum(cpatch%canopy_area_profile(cl,ft,1:cpatch%nrad(cl,ft)) * & - cpatch%tsai_profile(cl,ft,1:cpatch%nrad(cl,ft))) - enddo - enddo - else - write(iulog,*) 'Unsupported area index sent to calc_areaindex' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - ai = max(ai_min,ai) - - return - - end function calc_areaindex - - - -end module EDCanopyStructureMod diff --git a/src/ED/biogeochem/EDCohortDynamicsMod.F90 b/src/ED/biogeochem/EDCohortDynamicsMod.F90 deleted file mode 100755 index fca32709d3..0000000000 --- a/src/ED/biogeochem/EDCohortDynamicsMod.F90 +++ /dev/null @@ -1,1183 +0,0 @@ -module EDCohortDynamicsMod - ! - ! !DESCRIPTION: - ! Cohort stuctures in ED. - ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8; - use clm_varctl , only : iulog - use pftconMod , only : pftcon - use EDEcophysContype , only : EDecophyscon - use EDGrowthFunctionsMod , only : c_area, tree_lai - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type - use EDTypesMod , only : fusetol, cp_nclmax - use EDtypesMod , only : ncwd, numcohortsperpatch, udata - use EDtypesMod , only : sclass_ed,nlevsclass_ed,AREA - use EDtypesMod , only : min_npm2, min_nppatch, min_n_safemath - ! - implicit none - private - ! - public :: create_cohort - public :: zero_cohort - public :: nan_cohort - public :: terminate_cohorts - public :: fuse_cohorts - public :: insert_cohort - public :: sort_cohorts - public :: copy_cohort - public :: count_cohorts -! public :: countCohorts - public :: allocate_live_biomass - - logical, parameter :: DEBUG = .false. ! local debug flag - - ! 10/30/09: Created by Rosie Fisher - !-------------------------------------------------------------------------------------! - -contains - - !-------------------------------------------------------------------------------------! - subroutine create_cohort(patchptr, pft, nn, hite, dbh, & - balive, bdead, bstore, laimemory, status, ctrim, clayer) - ! - ! !DESCRIPTION: - ! create new cohort - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type), intent(inout), pointer :: patchptr - integer, intent(in) :: pft ! Cohort Plant Functional Type - integer, intent(in) :: clayer ! canopy status of cohort (1 = canopy, 2 = understorey, etc.) - integer, intent(in) :: status ! growth status of plant (2 = leaves on , 1 = leaves off) - real(r8), intent(in) :: nn ! number of individuals in cohort per 'area' (10000m2 default) - real(r8), intent(in) :: hite ! height: meters - real(r8), intent(in) :: dbh ! dbh: cm - real(r8), intent(in) :: balive ! total living biomass: kGC per indiv - real(r8), intent(in) :: bdead ! total dead biomass: kGC per indiv - real(r8), intent(in) :: bstore ! stored carbon: kGC per indiv - real(r8), intent(in) :: laimemory ! target leaf biomass- set from previous year: kGC per indiv - real(r8), intent(in) :: ctrim ! What is the fraction of the maximum leaf biomass that we are targeting? :- - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: new_cohort ! Pointer to New Cohort structure. - type(ed_cohort_type), pointer :: storesmallcohort - type(ed_cohort_type), pointer :: storebigcohort - integer :: tnull,snull ! are the tallest and shortest cohorts allocate - !---------------------------------------------------------------------- - - allocate(new_cohort) - udata%cohort_number = udata%cohort_number + 1 !give each cohort a unique number for checking cohort fusing routine. - - call nan_cohort(new_cohort) ! Make everything in the cohort not-a-number - call zero_cohort(new_cohort) ! Zero things that need to be zeroed. - - !**********************/ - ! Define cohort state variable - !**********************/ - - new_cohort%indexnumber = udata%cohort_number - new_cohort%siteptr => patchptr%siteptr - new_cohort%patchptr => patchptr - new_cohort%pft = pft - new_cohort%status_coh = status - new_cohort%n = nn - new_cohort%hite = hite - new_cohort%dbh = dbh - new_cohort%canopy_trim = ctrim - new_cohort%canopy_layer = clayer - new_cohort%laimemory = laimemory - new_cohort%bdead = bdead - new_cohort%balive = balive - new_cohort%bstore = bstore - - if ( DEBUG ) write(iulog,*) 'EDCohortDyn I ',bstore - - if (new_cohort%dbh <= 0.0_r8 .or. new_cohort%n == 0._r8 .or. new_cohort%pft == 0 & - .or. new_cohort%canopy_trim <= 0.0_r8 .or. new_cohort%balive <= 0._r8) then - write(iulog,*) 'ED: something is zero in create_cohort', & - new_cohort%indexnumber,new_cohort%dbh,new_cohort%n, & - new_cohort%pft,new_cohort%canopy_trim,new_cohort%balive - endif - - if (new_cohort%siteptr%status==2 .and. pftcon%season_decid(pft) == 1) then - new_cohort%laimemory = 0.0_r8 - endif - - if (new_cohort%siteptr%dstatus==2 .and. pftcon%stress_decid(pft) == 1) then - new_cohort%laimemory = 0.0_r8 - endif - - ! Calculate live biomass allocation - call allocate_live_biomass(new_cohort,0) - - ! Assign canopy extent and depth - new_cohort%c_area = c_area(new_cohort) - new_cohort%treelai = tree_lai(new_cohort) - new_cohort%lai = new_cohort%treelai * new_cohort%c_area/patchptr%area - new_cohort%treesai = 0.0_r8 !FIX(RF,032414) - - ! Put cohort at the right place in the linked list - storebigcohort => patchptr%tallest - storesmallcohort => patchptr%shortest - - if (associated(patchptr%tallest)) then - tnull = 0 - else - tnull = 1 - patchptr%tallest => new_cohort - endif - - if (associated(patchptr%shortest)) then - snull = 0 - else - snull = 1 - patchptr%shortest => new_cohort - endif - - ! Recuits do not have mortality rates, nor have they moved any - ! carbon when they are created. They will bias our statistics - ! until they have experienced a full day. We need a newly recruited flag. - ! This flag will be set to false after it has experienced - ! growth, disturbance and mortality. - new_cohort%isnew = .true. - - call insert_cohort(new_cohort, patchptr%tallest, patchptr%shortest, tnull, snull, & - storebigcohort, storesmallcohort) - - patchptr%tallest => storebigcohort - patchptr%shortest => storesmallcohort - - end subroutine create_cohort - - !-------------------------------------------------------------------------------------! - subroutine allocate_live_biomass(cc_p,mode) - ! - ! !DESCRIPTION: - ! Divide alive biomass between leaf, root and sapwood parts. - ! Needs to be called whenver balive changes. - ! - ! !USES: - ! - ! !ARGUMENTS - type (ed_cohort_type), intent(inout), target :: cc_p ! current cohort pointer - integer , intent(in) :: mode - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type), pointer :: currentCohort - real(r8) :: leaf_frac ! fraction of live biomass in leaves - real(r8) :: ideal_balive ! theoretical ideal (root and stem) biomass for deciduous trees with leaves off. - ! accounts for the fact that live biomass may decline in the off-season, - ! making leaf_memory unrealistic. - real(r8) :: ratio_balive ! ratio between root+shoot biomass now and root+shoot biomass when leaves fell off. - - integer :: ft ! functional type - integer :: leaves_off_switch - !---------------------------------------------------------------------- - - currentCohort => cc_p - ft = currentcohort%pft - leaf_frac = 1.0_r8/(1.0_r8 + EDecophyscon%sapwood_ratio(ft) * currentcohort%hite + pftcon%froot_leaf(ft)) - - !currentcohort%bl = currentcohort%balive*leaf_frac - !for deciduous trees, there are no leaves - - if (pftcon%evergreen(ft) == 1) then - currentcohort%laimemory = 0._r8 - currentcohort%status_coh = 2 - endif - - ! iagnore the root and stem biomass from the functional balance hypothesis. This is used when the leaves are - !fully on. - !currentcohort%br = pftcon%froot_leaf(ft) * (currentcohort%balive + currentcohort%laimemory) * leaf_frac - !currentcohort%bsw = EDecophyscon%sapwood_ratio(ft) * currentcohort%hite *(currentcohort%balive + & - ! currentcohort%laimemory)*leaf_frac - - leaves_off_switch = 0 - if (currentcohort%status_coh == 1.and.pftcon%stress_decid(ft) == 1.and.currentcohort%siteptr%dstatus==1) then !no leaves - leaves_off_switch = 1 !drought decid - endif - if (currentcohort%status_coh == 1.and.pftcon%season_decid(ft) == 1.and.currentcohort%siteptr%status==1) then !no leaves - leaves_off_switch = 1 !cold decid - endif - - ! Use different proportions if the leaves are on vs off - if(leaves_off_switch==0)then - - ! Tracking npp/gpp diagnostics only occur after growth derivatives is called - if(mode==1)then - ! it will not be able to put out as many leaves as it had previous timestep - currentcohort%npp_leaf = currentcohort%npp_leaf + & - max(0.0_r8,currentcohort%balive*leaf_frac - currentcohort%bl)/udata%deltat - end if - - currentcohort%bl = currentcohort%balive*leaf_frac - - !diagnose the root and stem biomass from the functional balance hypothesis. This is used when the leaves are - !fully on. - if(mode==1)then - - currentcohort%npp_froot = currentcohort%npp_froot + & - max(0._r8,pftcon%froot_leaf(ft)*(currentcohort%balive+currentcohort%laimemory)*leaf_frac - currentcohort%br) / & - udata%deltat - - currentcohort%npp_bsw = max(0._r8,EDecophyscon%sapwood_ratio(ft) * currentcohort%hite *(currentcohort%balive + & - currentcohort%laimemory)*leaf_frac - currentcohort%bsw)/udata%deltat - - currentcohort%npp_bdead = currentCohort%dbdeaddt - - end if - - currentcohort%br = pftcon%froot_leaf(ft) * (currentcohort%balive + currentcohort%laimemory) * leaf_frac - currentcohort%bsw = EDecophyscon%sapwood_ratio(ft) * currentcohort%hite *(currentcohort%balive + & - currentcohort%laimemory)*leaf_frac - - - else ! Leaves are on (leaves_off_switch==1) - - !the purpose of this section is to figure out the root and stem biomass when the leaves are off - !at this point, we know the former leaf mass (laimemory) and the current alive mass - !because balive may decline in the off-season, we need to adjust the root and stem biomass that are predicted - !from the laimemory, for the fact that we now might not have enough live biomass to support the hypothesized root mass - !thus, we use 'ratio_balive' to adjust br and bsw. Apologies that this is so complicated! RF - - - currentcohort%bl = 0.0_r8 - ideal_balive = currentcohort%laimemory * pftcon%froot_leaf(ft) + & - currentcohort%laimemory* EDecophyscon%sapwood_ratio(ft) * currentcohort%hite - currentcohort%br = pftcon%froot_leaf(ft) * (ideal_balive + currentcohort%laimemory) * leaf_frac - currentcohort%bsw = EDecophyscon%sapwood_ratio(ft) * currentcohort%hite *(ideal_balive + & - currentcohort%laimemory)*leaf_frac - - ratio_balive = currentcohort%balive / ideal_balive - currentcohort%br = currentcohort%br * ratio_balive - currentcohort%bsw = currentcohort%bsw * ratio_balive - - ! Diagnostics - if(mode==1)then - - currentcohort%npp_froot = currentcohort%npp_froot + & - max(0.0_r8,pftcon%froot_leaf(ft)*(ideal_balive + & - currentcohort%laimemory)*leaf_frac*ratio_balive-currentcohort%br)/udata%deltat - - currentcohort%npp_bsw = max(0.0_r8,EDecophyscon%sapwood_ratio(ft) * currentcohort%hite *(ideal_balive + & - currentcohort%laimemory)*leaf_frac*ratio_balive - currentcohort%bsw)/udata%deltat - - currentcohort%npp_bdead = currentCohort%dbdeaddt - - end if - - endif - - if (abs(currentcohort%balive -currentcohort%bl- currentcohort%br - currentcohort%bsw)>1e-12) then - write(iulog,*) 'issue with carbon allocation in create_cohort,allocate_live_biomass',& - currentcohort%balive -currentcohort%bl- currentcohort%br - currentcohort%bsw, & - currentcohort%status_coh,currentcohort%balive - write(iulog,*) 'actual vs predicted balive',ideal_balive,currentcohort%balive ,ratio_balive,leaf_frac - write(iulog,*) 'leaf,root,stem',currentcohort%bl,currentcohort%br,currentcohort%bsw - write(iulog,*) 'pft',ft,pftcon%evergreen(ft),pftcon%season_decid(ft),leaves_off_switch - endif - currentCohort%b = currentCohort%bdead + currentCohort%balive - - end subroutine allocate_live_biomass - - !-------------------------------------------------------------------------------------! - subroutine nan_cohort(cc_p) - ! - ! !DESCRIPTION: - ! Make all the cohort variables NaN so they aren't used before defined. - ! - ! !USES: - use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) - ! - ! !ARGUMENTS - type (ed_cohort_type), intent(inout), target :: cc_p - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - !---------------------------------------------------------------------- - - currentCohort => cc_p - - currentCohort%taller => null() ! pointer to next tallest cohort - currentCohort%shorter => null() ! pointer to next shorter cohort - currentCohort%patchptr => null() ! pointer to patch that cohort is in - currentCohort%siteptr => null() ! pointer to site that cohort is in - - nullify(currentCohort%taller) - nullify(currentCohort%shorter) - nullify(currentCohort%patchptr) - nullify(currentCohort%siteptr) - - ! VEGETATION STRUCTURE - currentCohort%pft = 999 ! pft number - currentCohort%indexnumber = 999 ! unique number for each cohort. (within clump?) - currentCohort%canopy_layer = 999 ! canopy status of cohort (1 = canopy, 2 = understorey, etc.) - currentCohort%NV = 999 ! Number of leaf layers: - - currentCohort%status_coh = 999 ! growth status of plant (2 = leaves on , 1 = leaves off) - - currentCohort%n = nan ! number of individuals in cohort per 'area' (10000m2 default) - currentCohort%dbh = nan ! 'diameter at breast height' in cm - currentCohort%hite = nan ! height: meters - currentCohort%balive = nan ! total living biomass: kGC per indiv - currentCohort%bdead = nan ! dead biomass: kGC per indiv - currentCohort%bstore = nan ! stored carbon: kGC per indiv - currentCohort%laimemory = nan ! target leaf biomass- set from previous year: kGC per indiv - currentCohort%b = nan ! total biomass: kGC per indiv - currentCohort%bsw = nan ! sapwood in stem and roots: kGC per indiv - currentCohort%bl = nan ! leaf biomass: kGC per indiv - currentCohort%br = nan ! fine root biomass: kGC per indiv - currentCohort%lai = nan ! leaf area index of cohort m2/m2 - currentCohort%sai = nan ! stem area index of cohort m2/m2 - currentCohort%gscan = nan ! Stomatal resistance of cohort. - currentCohort%canopy_trim = nan ! What is the fraction of the maximum leaf biomass that we are targeting? :- - currentCohort%leaf_cost = nan ! How much does it cost to maintain leaves: kgC/m2/year-1 - currentCohort%excl_weight = nan ! How much of this cohort is demoted each year, as a proportion of all cohorts:- - currentCohort%prom_weight = nan ! How much of this cohort is promoted each year, as a proportion of all cohorts:- - currentCohort%c_area = nan ! areal extent of canopy (m2) - currentCohort%treelai = nan ! lai of tree (total leaf area (m2) / canopy area (m2) - currentCohort%treesai = nan ! stem area index of tree (total stem area (m2) / canopy area (m2) - - ! CARBON FLUXES - currentCohort%gpp = nan ! GPP: kgC/indiv/year - currentCohort%gpp_tstep = nan ! GPP: kgC/indiv/timestep - currentCohort%gpp_acc = nan ! GPP: kgC/indiv/day - currentCohort%npp = nan ! NPP: kgC/indiv/year - currentCohort%npp_tstep = nan ! NPP: kGC/indiv/timestep - currentCohort%npp_acc = nan ! NPP: kgC/indiv/day - currentCohort%year_net_uptake(:) = nan ! Net uptake of individual leaf layers kgC/m2/year - currentCohort%ts_net_uptake(:) = nan ! Net uptake of individual leaf layers kgC/m2/s - currentCohort%resp = nan ! RESP: kgC/indiv/year - currentCohort%resp_tstep = nan ! RESP: kgC/indiv/timestep - currentCohort%resp_acc = nan ! RESP: kGC/cohort/day - - currentCohort%npp_leaf = nan - currentCohort%npp_froot = nan - currentCohort%npp_bsw = nan - currentCohort%npp_bdead = nan - currentCohort%npp_bseed = nan - currentCohort%npp_store = nan - - - !RESPIRATION - currentCohort%rd = nan - currentCohort%resp_m = nan ! Maintenance respiration. kGC/cohort/year - currentCohort%resp_g = nan ! Growth respiration. kGC/cohort/year - currentCohort%livestem_mr = nan ! Live stem maintenance respiration. kgC/indiv/s-1 - currentCohort%livecroot_mr = nan ! Coarse root maintenance respiration. kgC/indiv/s-1 - currentCohort%froot_mr = nan ! Fine root maintenance respiration. kgC/indiv/s-1 - - ! ALLOCATION - currentCohort%md = nan ! plant maintenance demand: kgC/indiv/year - currentCohort%leaf_md = nan ! leaf maintenance demand: kgC/indiv/year - currentCohort%root_md = nan ! root maintenance demand: kgC/indiv/year - currentCohort%carbon_balance = nan ! carbon remaining for growth and storage: kg/indiv/year - currentCohort%dmort = nan ! proportional mortality rate. (year-1) - currentCohort%seed_prod = nan ! reproduction seed and clonal: KgC/indiv/year - currentCohort%c_area = nan ! areal extent of canopy (m2) - currentCohort%treelai = nan ! lai of tree (total leaf area (m2) / canopy area (m2) - currentCohort%treesai = nan ! stem area index of tree (total stem area (m2) / canopy area (m2) - currentCohort%leaf_litter = nan ! leaf litter from phenology: KgC/m2 - currentCohort%woody_turnover = nan ! amount of wood lost each day: kgC/indiv/year. Currently set to zero. - - ! NITROGEN POOLS - currentCohort%livestemn = nan ! live stem nitrogen : KgN/invid - currentCohort%livecrootn = nan ! live coarse root nitrogen: KgN/invid - currentCohort%frootn = nan ! fine root nitrogen : KgN/invid - - ! VARIABLES NEEDED FOR INTEGRATION - currentCohort%dndt = nan ! time derivative of cohort size - currentCohort%dhdt = nan ! time derivative of height - currentCohort%ddbhdt = nan ! time derivative of dbh - currentCohort%dbalivedt = nan ! time derivative of total living biomass - currentCohort%dbdeaddt = nan ! time derivative of dead biomass - currentCohort%dbstoredt = nan ! time derivative of stored biomass - currentCohort%storage_flux = nan ! flux from npp into bstore - - ! FIRE - currentCohort%cfa = nan ! proportion of crown affected by fire - currentCohort%cambial_mort = nan ! probability that trees dies due to cambial char P&R (1986) - currentCohort%crownfire_mort = nan ! probability of tree post-fire mortality due to crown scorch - currentCohort%fire_mort = nan ! post-fire mortality from cambial and crown damage assuming two are independent - - end subroutine nan_cohort - - !-------------------------------------------------------------------------------------! - subroutine zero_cohort(cc_p) - ! - ! !DESCRIPTION: - ! Zero variables that need to be accounted for if - ! this cohort is altered before they are defined. - ! - ! !USES: - ! - ! !ARGUMENTS - type (ed_cohort_type), intent(inout), target :: cc_p - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - !---------------------------------------------------------------------- - - currentCohort => cc_p - - currentCohort%NV = 0 - currentCohort%status_coh = 0 - currentCohort%rd = 0._r8 - currentCohort%resp_m = 0._r8 - currentCohort%resp_g = 0._r8 - currentCohort%livestem_mr = 0._r8 - currentCohort%livecroot_mr = 0._r8 - currentCohort%froot_mr = 0._r8 - currentCohort%fire_mort = 0._r8 - currentcohort%npp_acc = 0._r8 - currentcohort%gpp_acc = 0._r8 - currentcohort%resp_acc = 0._r8 - currentcohort%npp_tstep = 0._r8 - currentcohort%gpp_tstep = 0._r8 - currentcohort%resp_tstep = 0._r8 - currentcohort%resp = 0._r8 - currentcohort%carbon_balance = 0._r8 - currentcohort%leaf_litter = 0._r8 - currentcohort%year_net_uptake(:) = 999 ! this needs to be 999, or trimming of new cohorts will break. - currentcohort%ts_net_uptake(:) = 0._r8 - currentcohort%seed_prod = 0._r8 - currentcohort%cfa = 0._r8 - currentcohort%md = 0._r8 - currentcohort%root_md = 0._r8 - currentcohort%leaf_md = 0._r8 - currentcohort%npp = 0._r8 - currentcohort%gpp = 0._r8 - currentcohort%storage_flux = 0._r8 - currentcohort%dmort = 0._r8 - currentcohort%gscan = 0._r8 - currentcohort%treesai = 0._r8 - - ! currentCohort%npp_leaf = 0._r8 - ! currentCohort%npp_froot = 0._r8 - ! currentCohort%npp_bsw = 0._r8 - ! currentCohort%npp_bdead = 0._r8 - ! currentCohort%npp_bseed = 0._r8 - ! currentCohort%npp_store = 0._r8 - - end subroutine zero_cohort - - !-------------------------------------------------------------------------------------! - subroutine terminate_cohorts( patchptr ) - ! - ! !DESCRIPTION: - ! terminates cohorts when they get too small - ! - ! !USES: - use EDParamsMod, only : ED_val_ag_biomass - use SFParamsMod, only : SF_val_CWD_frac - ! - ! !ARGUMENTS - type (ed_patch_type), intent(inout), target :: patchptr - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort - type (ed_cohort_type) , pointer :: nextc - integer :: terminate ! do we terminate (1) or not (0) - integer :: c ! counter for litter size class. - !---------------------------------------------------------------------- - - currentPatch => patchptr - currentCohort => currentPatch%tallest - - do while (associated(currentCohort)) - nextc => currentCohort%shorter - terminate = 0 - - ! Check if number density is so low is breaks math - if (currentcohort%n < min_n_safemath) then - terminate = 1 - if ( DEBUG ) then - write(iulog,*) 'terminating cohorts 0',currentCohort%n/currentPatch%area,currentCohort%dbh - endif - endif - - ! The rest of these are only allowed if we are not dealing with a recruit - if (.not.currentCohort%isnew) then - - ! Not enough n or dbh - if (currentCohort%n/currentPatch%area <= min_npm2 .or. & ! - currentCohort%n <= min_nppatch .or. & - (currentCohort%dbh < 0.00001_r8.and.currentCohort%bstore < 0._r8) ) then - terminate = 1 - - if ( DEBUG ) then - write(iulog,*) 'terminating cohorts 1',currentCohort%n/currentPatch%area,currentCohort%dbh - endif - endif - - ! In the third canopy layer - if (currentCohort%canopy_layer > cp_nclmax ) then - terminate = 1 - if ( DEBUG ) then - write(iulog,*) 'terminating cohorts 2', currentCohort%canopy_layer - endif - endif - - ! live biomass pools are terminally depleted - if (currentCohort%balive < 1e-10_r8 .or. currentCohort%bstore < 1e-10_r8) then - terminate = 1 - if ( DEBUG ) then - write(iulog,*) 'terminating cohorts 3', currentCohort%balive,currentCohort%bstore - endif - endif - - ! Total cohort biomass is negative - if (currentCohort%balive+currentCohort%bdead+currentCohort%bstore < 0._r8) then - terminate = 1 - if ( DEBUG ) then - write(iulog,*) 'terminating cohorts 4', currentCohort%balive, & - currentCohort%bstore, currentCohort%bdead, & - currentCohort%balive+currentCohort%bdead+& - currentCohort%bstore, currentCohort%n - endif - - endif - endif - - if (terminate == 1) then - if (.not. associated(currentCohort%taller)) then - currentPatch%tallest => currentCohort%shorter - else - currentCohort%taller%shorter => currentCohort%shorter - endif - if (.not. associated(currentCohort%shorter)) then - currentPatch%shortest => currentCohort%taller - else - currentCohort%shorter%taller => currentCohort%taller - endif - - !put the litter from the terminated cohorts straight into the fragmenting pools - if (currentCohort%n.gt.0.0_r8) then - do c=1,ncwd - - currentPatch%CWD_AG(c) = currentPatch%CWD_AG(c) + currentCohort%n*(currentCohort%bdead+currentCohort%bsw) / & - currentPatch%area & - * SF_val_CWD_frac(c) * ED_val_ag_biomass - currentPatch%CWD_BG(c) = currentPatch%CWD_BG(c) + currentCohort%n*(currentCohort%bdead+currentCohort%bsw) / & - currentPatch%area & - * SF_val_CWD_frac(c) * (1.0_r8 - ED_val_ag_biomass) - enddo - - currentPatch%leaf_litter(currentCohort%pft) = currentPatch%leaf_litter(currentCohort%pft) + currentCohort%n* & - (currentCohort%bl)/currentPatch%area - currentPatch%root_litter(currentCohort%pft) = currentPatch%root_litter(currentCohort%pft) + currentCohort%n* & - (currentCohort%br+currentCohort%bstore)/currentPatch%area - - deallocate(currentCohort) - endif - endif - currentCohort => nextc - enddo - - end subroutine terminate_cohorts - - !-------------------------------------------------------------------------------------! - subroutine fuse_cohorts(patchptr) - ! - ! !DESCRIPTION: - ! Join similar cohorts to reduce total number - ! - ! !USES: - use EDTypesMod , only : cp_nlevcan - ! - ! !ARGUMENTS - type (ed_patch_type), intent(inout), target :: patchptr - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort, nextc, nextnextc - integer :: i - integer :: fusion_took_place - integer :: maxcohorts !maximum total no of cohorts. Needs to be >numpft_edx2 - integer :: iterate !do we need to keep fusing to get below maxcohorts? - integer :: nocohorts - real(r8) :: newn - real(r8) :: diff - real(r8) :: dynamic_fusion_tolerance - !---------------------------------------------------------------------- - - !set initial fusion tolerance - dynamic_fusion_tolerance = fusetol - - !This needs to be a function of the canopy layer, because otherwise, at canopy closure - !the number of cohorts doubles and very dissimilar cohorts are fused together - !because c_area and biomass are non-linear with dbh, this causes several mass inconsistancies - !in theory, all of this routine therefore causes minor losses of C and area, but these are below - !detection limit normally. - iterate = 1 - fusion_took_place = 0 - currentPatch => patchptr - maxcohorts = numCohortsPerPatch - - !---------------------------------------------------------------------! - ! Keep doing this until nocohorts <= maxcohorts ! - !---------------------------------------------------------------------! - if (associated(currentPatch%shortest)) then - do while(iterate == 1) - - currentCohort => currentPatch%tallest - - ! The following logic continues the loop while the current cohort is not the shortest cohort - ! if they point to the same target (ie equivalence), then the loop ends. - ! This loop is different than the simple "continue while associated" loop in that - ! it omits the last cohort (because it has already been compared by that point) - - do while ( .not.associated(currentCohort,currentPatch%shortest) ) - - nextc => currentPatch%tallest - - do while (associated(nextc)) - nextnextc => nextc%shorter - diff = abs((currentCohort%dbh - nextc%dbh)/(0.5*(currentCohort%dbh + nextc%dbh))) - - !Criteria used to divide up the height continuum into different cohorts. - - if (diff < dynamic_fusion_tolerance) then - - ! Don't fuse a cohort with itself! - if (.not.associated(currentCohort,nextc) ) then - - if (currentCohort%pft == nextc%pft) then - - ! check cohorts in same c. layer. before fusing - - if (currentCohort%canopy_layer == nextc%canopy_layer) then - - ! Note: because newly recruited cohorts that have not experienced - ! a day yet will have un-known flux quantities or change rates - ! we don't want them fusing with non-new cohorts. We allow them - ! to fuse with other new cohorts to keep the total number of cohorts - ! down. - - if( .not.(currentCohort%isnew) .and. .not.(nextc%isnew) ) then - - newn = currentCohort%n + nextc%n - fusion_took_place = 1 - - - currentCohort%balive = (currentCohort%n*currentCohort%balive + nextc%n*nextc%balive)/newn - currentCohort%bdead = (currentCohort%n*currentCohort%bdead + nextc%n*nextc%bdead)/newn - - if ( DEBUG ) write(iulog,*) 'EDcohortDyn I ',currentCohort%bstore - - currentCohort%bstore = (currentCohort%n*currentCohort%bstore + nextc%n*nextc%bstore)/newn - - if ( DEBUG ) write(iulog,*) 'EDcohortDyn II ',currentCohort%bstore - - currentCohort%seed_prod = (currentCohort%n*currentCohort%seed_prod + nextc%n*nextc%seed_prod)/newn - currentCohort%root_md = (currentCohort%n*currentCohort%root_md + nextc%n*nextc%root_md)/newn - currentCohort%leaf_md = (currentCohort%n*currentCohort%leaf_md + nextc%n*nextc%leaf_md)/newn - currentCohort%laimemory = (currentCohort%n*currentCohort%laimemory + nextc%n*nextc%laimemory)/newn - currentCohort%md = (currentCohort%n*currentCohort%md + nextc%n*nextc%md)/newn - - currentCohort%carbon_balance = (currentCohort%n*currentCohort%carbon_balance + & - nextc%n*nextc%carbon_balance)/newn - - currentCohort%storage_flux = (currentCohort%n*currentCohort%storage_flux + & - nextc%n*nextc%storage_flux)/newn - - currentCohort%b = (currentCohort%n*currentCohort%b + nextc%n*nextc%b)/newn - currentCohort%bsw = (currentCohort%n*currentCohort%bsw + nextc%n*nextc%bsw)/newn - currentCohort%bl = (currentCohort%n*currentCohort%bl + nextc%n*nextc%bl)/newn - - if ( DEBUG ) write(iulog,*) 'EDcohortDyn 569 ',currentCohort%br - if ( DEBUG ) write(iulog,*) 'EDcohortDyn 570 ',currentCohort%n - if ( DEBUG ) write(iulog,*) 'EDcohortDyn 571 ',nextc%br - if ( DEBUG ) write(iulog,*) 'EDcohortDyn 572 ',nextc%n - - currentCohort%br = (currentCohort%n*currentCohort%br + nextc%n*nextc%br)/newn - currentCohort%hite = (currentCohort%n*currentCohort%hite + nextc%n*nextc%hite)/newn - currentCohort%dbh = (currentCohort%n*currentCohort%dbh + nextc%n*nextc%dbh)/newn - - currentCohort%gpp_acc = (currentCohort%n*currentCohort%gpp_acc + nextc%n*nextc%gpp_acc)/newn - - if ( DEBUG ) write(iulog,*) 'EDcohortDyn III ',currentCohort%npp_acc - if ( DEBUG ) write(iulog,*) 'EDcohortDyn IV ',currentCohort%resp_acc - - currentCohort%npp_acc = (currentCohort%n*currentCohort%npp_acc + nextc%n*nextc%npp_acc)/newn - currentCohort%resp_acc = (currentCohort%n*currentCohort%resp_acc + nextc%n*nextc%resp_acc)/newn - - if ( DEBUG ) write(iulog,*) 'EDcohortDyn V ',currentCohort%npp_acc - if ( DEBUG ) write(iulog,*) 'EDcohortDyn VI ',currentCohort%resp_acc - - currentCohort%resp = (currentCohort%n*currentCohort%resp + nextc%n*nextc%resp)/newn - currentCohort%npp = (currentCohort%n*currentCohort%npp + nextc%n*nextc%npp)/newn - currentCohort%gpp = (currentCohort%n*currentCohort%gpp + nextc%n*nextc%gpp)/newn - currentCohort%canopy_trim = (currentCohort%n*currentCohort%canopy_trim + nextc%n*nextc%canopy_trim)/newn - currentCohort%dmort = (currentCohort%n*currentCohort%dmort + nextc%n*nextc%dmort)/newn - currentCohort%fire_mort = (currentCohort%n*currentCohort%fire_mort + nextc%n*nextc%fire_mort)/newn - currentCohort%leaf_litter = (currentCohort%n*currentCohort%leaf_litter + nextc%n*nextc%leaf_litter)/newn - - ! mortality diagnostics - currentCohort%cmort = (currentCohort%n*currentCohort%cmort + nextc%n*nextc%cmort)/newn - currentCohort%hmort = (currentCohort%n*currentCohort%hmort + nextc%n*nextc%hmort)/newn - currentCohort%bmort = (currentCohort%n*currentCohort%bmort + nextc%n*nextc%bmort)/newn - currentCohort%imort = (currentCohort%n*currentCohort%imort + nextc%n*nextc%imort)/newn - currentCohort%fmort = (currentCohort%n*currentCohort%fmort + nextc%n*nextc%fmort)/newn - - ! npp diagnostics - currentCohort%npp_leaf = (currentCohort%n*currentCohort%npp_leaf + nextc%n*nextc%npp_leaf)/newn - currentCohort%npp_froot = (currentCohort%n*currentCohort%npp_froot + nextc%n*nextc%npp_froot)/newn - currentCohort%npp_bsw = (currentCohort%n*currentCohort%npp_bsw + nextc%n*nextc%npp_bsw)/newn - currentCohort%npp_bdead = (currentCohort%n*currentCohort%npp_bdead + nextc%n*nextc%npp_bdead)/newn - currentCohort%npp_bseed = (currentCohort%n*currentCohort%npp_bseed + nextc%n*nextc%npp_bseed)/newn - currentCohort%npp_store = (currentCohort%n*currentCohort%npp_store + nextc%n*nextc%npp_store)/newn - - do i=1, cp_nlevcan - if (currentCohort%year_net_uptake(i) == 999._r8 .or. nextc%year_net_uptake(i) == 999._r8) then - currentCohort%year_net_uptake(i) = min(nextc%year_net_uptake(i),currentCohort%year_net_uptake(i)) - else - currentCohort%year_net_uptake(i) = (currentCohort%n*currentCohort%year_net_uptake(i) + & - nextc%n*nextc%year_net_uptake(i))/newn - endif - enddo - - currentCohort%n = newn - !remove fused cohort from the list - nextc%taller%shorter => nextnextc - if (.not. associated(nextc%shorter)) then !this is the shortest cohort. - currentPatch%shortest => nextc%taller - else - nextnextc%taller => nextc%taller - endif - - if (associated(nextc)) then - deallocate(nextc) - endif - - endif ! Not a recruit - - endif !canopy layer - endif !pft - endif !index no. - endif !diff - - if (associated(nextc)) then - nextc => nextc%shorter - else - nextc => nextnextc !if we have removed next - endif - - enddo !end checking nextc cohort loop - - if (associated (currentCohort%shorter)) then - currentCohort => currentCohort%shorter - endif - enddo !end currentCohort cohort loop - - !---------------------------------------------------------------------! - ! Is the number of cohorts larger than the maximum? ! - !---------------------------------------------------------------------! - nocohorts = 0 - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - nocohorts = nocohorts + 1 - currentCohort => currentCohort%shorter - enddo - - if (nocohorts > maxcohorts) then - iterate = 1 - !---------------------------------------------------------------------! - ! Making profile tolerance larger means that more fusion will happen ! - !---------------------------------------------------------------------! - dynamic_fusion_tolerance = dynamic_fusion_tolerance * 1.1_r8 - - write(iulog,*) 'maxcohorts exceeded',dynamic_fusion_tolerance - - else - iterate = 0 - endif - - enddo !do while nocohorts>maxcohorts - - endif ! patch. - - if (fusion_took_place == 1) then ! if fusion(s) occured sort cohorts - call sort_cohorts(currentPatch) - endif - - end subroutine fuse_cohorts - -!-------------------------------------------------------------------------------------! - - subroutine sort_cohorts(patchptr) - ! ============================================================================ - ! sort cohorts into the correct order DO NOT CHANGE THIS IT WILL BREAK - ! ============================================================================ - - type(ed_patch_type) , intent(inout), target :: patchptr - - type(ed_patch_type) , pointer :: current_patch - type(ed_cohort_type), pointer :: current_c, next_c - type(ed_cohort_type), pointer :: shortestc, tallestc - type(ed_cohort_type), pointer :: storesmallcohort - type(ed_cohort_type), pointer :: storebigcohort - integer :: snull,tnull - - current_patch => patchptr - tallestc => NULL() - shortestc => NULL() - storebigcohort => null() - storesmallcohort => null() - current_c => current_patch%tallest - - do while (associated(current_c)) - next_c => current_c%shorter - tallestc => storebigcohort - shortestc => storesmallcohort - if (associated(tallestc)) then - tnull = 0 - else - tnull = 1 - tallestc => current_c - endif - - if (associated(shortestc)) then - snull = 0 - else - snull = 1 - shortestc => current_c - endif - - call insert_cohort(current_c, tallestc, shortestc, tnull, snull, storebigcohort, storesmallcohort) - - current_patch%tallest => storebigcohort - current_patch%shortest => storesmallcohort - current_c => next_c - - enddo - - end subroutine sort_cohorts - - !-------------------------------------------------------------------------------------! - subroutine insert_cohort(pcc, ptall, pshort, tnull, snull, storebigcohort, storesmallcohort) - ! - ! !DESCRIPTION: - ! Insert cohort into linked list - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_cohort_type) , intent(inout), target :: pcc - type(ed_cohort_type) , intent(inout), target :: ptall - type(ed_cohort_type) , intent(inout), target :: pshort - integer , intent(in) :: tnull - integer , intent(in) :: snull - type(ed_cohort_type) , intent(inout),pointer,optional :: storesmallcohort ! storage of the smallest cohort for insertion routine - type(ed_cohort_type) , intent(inout),pointer,optional :: storebigcohort ! storage of the largest cohort for insertion routine - ! - ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: current - type(ed_cohort_type), pointer :: tallptr, shortptr, icohort - type(ed_cohort_type), pointer :: ptallest, pshortest - real(r8) :: tsp - integer :: tallptrnull,exitloop - !---------------------------------------------------------------------- - - currentPatch => pcc%patchptr - ptallest => ptall - pshortest => pshort - - if (tnull == 1) then - ptallest => null() - endif - if (snull == 1) then - pshortest => null() - endif - - icohort => pcc ! assign address to icohort local name - !place in the correct place in the linked list of heights - !begin by finding cohort that is just taller than the new cohort - tsp = icohort%dbh - - current => pshortest - exitloop = 0 - !starting with shortest tree on the grid, find tree just - !taller than tree being considered and return its pointer - if (associated(current)) then - do while (associated(current).and.exitloop == 0) - if (current%dbh < tsp) then - current => current%taller - else - exitloop = 1 - endif - enddo - endif - - if (associated(current)) then - tallptr => current - tallptrnull = 0 - else - tallptr => null() - tallptrnull = 1 - endif - - !new cohort is tallest - if (.not.associated(tallptr)) then - !new shorter cohort to the new cohort is the old tallest cohort - shortptr => ptallest - - !new cohort is tallest cohort and next taller remains null - ptallest => icohort - if (present(storebigcohort)) then - storebigcohort => icohort - end if - currentPatch%tallest => icohort - icohort%patchptr%tallest => icohort - !new cohort is not tallest - else - !next shorter cohort to new cohort is the next shorter cohort - !to the cohort just taller than the new cohort - shortptr => tallptr%shorter - - !new cohort becomes the next shorter cohort to the cohort - !just taller than the new cohort - tallptr%shorter => icohort - endif - - !new cohort is shortest - if (.not.associated(shortptr)) then - !next shorter reamins null - !cohort is placed at the bottom of the list - pshortest => icohort - if (present(storesmallcohort)) then - storesmallcohort => icohort - end if - currentPatch%shortest => icohort - icohort%patchptr%shortest => icohort - else - !new cohort is not shortest and becomes next taller cohort - !to the cohort just below it as defined in the previous block - shortptr%taller => icohort - endif - - ! assign taller and shorter links for the new cohort - icohort%taller => tallptr - if (tallptrnull == 1) then - icohort%taller=> null() - endif - icohort%shorter => shortptr - - end subroutine insert_cohort - - !-------------------------------------------------------------------------------------! - subroutine copy_cohort( currentCohort,copyc ) - ! - ! !DESCRIPTION: - ! Copies all the variables in one cohort into another empty cohort - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_cohort_type), intent(inout) , target :: copyc ! New cohort argument. - type(ed_cohort_type), intent(in) , target :: currentCohort ! Old cohort argument. - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: n,o ! New and old cohort pointers - !---------------------------------------------------------------------- - - o => currentCohort - n => copyc - - udata%cohort_number = udata%cohort_number + 1 - n%indexnumber = udata%cohort_number - - ! VEGETATION STRUCTURE - n%pft = o%pft - n%n = o%n - n%dbh = o%dbh - n%hite = o%hite - n%b = o%b - n%balive = o%balive - n%bdead = o%bdead - n%bstore = o%bstore - n%laimemory = o%laimemory - n%bsw = o%bsw - n%bl = o%bl - n%br = o%br - n%lai = o%lai - n%sai = o%sai - n%gscan = o%gscan - n%leaf_cost = o%leaf_cost - n%canopy_layer = o%canopy_layer - n%nv = o%nv - n%status_coh = o%status_coh - n%canopy_trim = o%canopy_trim - n%status_coh = o%status_coh - n%excl_weight = o%excl_weight - n%prom_weight = o%prom_weight - - ! CARBON FLUXES - n%gpp = o%gpp - n%gpp_acc = o%gpp_acc - n%gpp_tstep = o%gpp_tstep - n%npp = o%npp - n%npp_tstep = o%npp_tstep - - if ( DEBUG ) write(iulog,*) 'EDcohortDyn Ia ',o%npp_acc - if ( DEBUG ) write(iulog,*) 'EDcohortDyn Ib ',o%resp_acc - - n%npp_acc = o%npp_acc - n%resp_tstep = o%resp_tstep - n%resp_acc = o%resp_acc - n%resp = o%resp - n%year_net_uptake = o%year_net_uptake - n%ts_net_uptake = o%ts_net_uptake - - n%npp_leaf = o%npp_leaf - n%npp_froot = o%npp_froot - n%npp_bsw = o%npp_bsw - n%npp_bdead = o%npp_bdead - n%npp_bseed = o%npp_bseed - n%npp_store = o%npp_store - - !RESPIRATION - n%rd = o%rd - n%resp_m = o%resp_m - n%resp_g = o%resp_g - n%livestem_mr = o%livestem_mr - n%livecroot_mr = o%livecroot_mr - n%froot_mr = o%froot_mr - - ! NITROGEN POOLS - n%livestemn = o%livestemn - n%livecrootn = o%livecrootn - n%frootn = o%frootn - - ! ALLOCATION - n%md = o%md - n%leaf_md = o%leaf_md - n%root_md = o%root_md - n%carbon_balance = o%carbon_balance - n%dmort = o%dmort - n%seed_prod = o%seed_prod - n%treelai = o%treelai - n%treesai = o%treesai - n%leaf_litter = o%leaf_litter - n%c_area = o%c_area - n%woody_turnover = o%woody_turnover - - ! Mortality diagnostics - n%cmort = o%cmort - n%bmort = o%bmort - n%imort = o%imort - n%fmort = o%fmort - n%hmort = o%hmort - - ! Flags - n%isnew = o%isnew - - ! VARIABLES NEEDED FOR INTEGRATION - n%dndt = o%dndt - n%dhdt = o%dhdt - n%ddbhdt = o%ddbhdt - n%dbalivedt = o%dbalivedt - n%dbdeaddt = o%dbdeaddt - n%dbstoredt = o%dbstoredt - - if ( DEBUG ) write(iulog,*) 'EDCohortDyn dpstoredt ',o%dbstoredt - - n%storage_flux = o%storage_flux - - ! FIRE - n%cfa = o%cfa - n%fire_mort = o%fire_mort - n%crownfire_mort = o%crownfire_mort - n%cambial_mort = o%cambial_mort - - !Pointers - n%taller => NULL() ! pointer to next tallest cohort - n%shorter => NULL() ! pointer to next shorter cohort - n%patchptr => o%patchptr ! pointer to patch that cohort is in - n%siteptr => o%siteptr ! pointer to site that cohort is in - - end subroutine copy_cohort - - !-------------------------------------------------------------------------------------! - function count_cohorts( currentPatch ) result ( backcount ) - ! - ! !DESCRIPTION: - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type), intent(inout), target :: currentPatch !new site - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer ::currentCohort !new patch - integer backcount - !---------------------------------------------------------------------- - - currentCohort => currentPatch%shortest - - currentPatch%countcohorts = 0 - do while (associated(currentCohort)) - currentPatch%countcohorts = currentPatch%countcohorts + 1 - currentCohort => currentCohort%taller - enddo - - backcount = 0 - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - backcount = backcount + 1 - currentCohort => currentCohort%shorter - enddo - - if (backcount /= currentPatch%countcohorts) then - write(iulog,*) 'problem with linked list, not symmetrical' - endif - - end function count_cohorts - - !-------------------------------------------------------------------------------------! -! function countCohorts( bounds, ed_allsites_inst ) result ( totNumCohorts ) - ! - ! !DESCRIPTION: - ! counts the total number of cohorts over all p levels (ed_patch_type) so we - ! can allocate vectors, copy from LL -> vector and read/write restarts. - ! - ! !USES: -! use decompMod, only : bounds_type - ! - ! !ARGUMENTS -! type(bounds_type) , intent(in) :: bounds -! type(ed_site_type) , intent(inout), target :: ed_allsites_inst( bounds%begg: ) - ! - ! !LOCAL VARIABLES: -! type (ed_patch_type) , pointer :: currentPatch -! type (ed_cohort_type) , pointer :: currentCohort -! integer :: g, totNumCohorts -! logical :: error - !---------------------------------------------------------------------- - -! totNumCohorts = 0 - -! do g = bounds%begg,bounds%endg - -! if (ed_allsites_inst(g)%istheresoil) then - -! currentPatch => ed_allsites_inst(g)%oldest_patch -! do while(associated(currentPatch)) - -! currentCohort => currentPatch%shortest -! do while(associated(currentCohort)) -! totNumCohorts = totNumCohorts + 1 -! currentCohort => currentCohort%taller -! enddo !currentCohort -! currentPatch => currentPatch%younger -! end do - -! end if -! end do - -! end function countCohorts - -end module EDCohortDynamicsMod diff --git a/src/ED/biogeochem/EDGrowthFunctionsMod.F90 b/src/ED/biogeochem/EDGrowthFunctionsMod.F90 deleted file mode 100755 index a400f46ab9..0000000000 --- a/src/ED/biogeochem/EDGrowthFunctionsMod.F90 +++ /dev/null @@ -1,384 +0,0 @@ -module EDGrowthFunctionsMod - - ! ============================================================================ - ! Functions that control the trajectory of plant growth. - ! Ideally these would all use parameters that are fed in from the parameter file. - ! At present, there is only a single allocation trajectory. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : iulog - use pftconMod , only : pftcon - use EDEcophysContype , only : EDecophyscon - use EDTypesMod , only : ed_cohort_type, cp_nlevcan, dinc_ed - - implicit none - private - - public :: bleaf - public :: hite - public :: ddbhdbd - public :: ddbhdbl - public :: dhdbd - public :: dbh - public :: bdead - public :: tree_lai - public :: tree_sai - public :: c_area - public :: mortality_rates - - logical :: DEBUG_growth = .false. - - ! ============================================================================ - ! 10/30/09: Created by Rosie Fisher - ! ============================================================================ - -contains - - real(r8) function Dbh( cohort_in ) - - ! ============================================================================ - ! Creates diameter in cm as a function of height in m - ! Height(m) diameter(cm) relationships. O'Brien et al - for 56 patch at BCI - ! ============================================================================ - - type(ed_cohort_type), intent(in) :: cohort_in - - !FIX(SPM,040214) - move to param file - real(r8) :: m !parameter of allometric equation (needs to not be hardwired... - real(r8) :: c !parameter of allometric equation (needs to not be hardwired... - - m = 0.64_r8 - c = 0.37_r8 - - dbh = (10.0_r8**((log10(cohort_in%hite) - c)/m)) - - return - - end function dbh - -! ============================================================================ - - real(r8) function Hite( cohort_in ) - - ! ============================================================================ - ! Creates height in m as a function of diameter in cm. - ! Height(m) diameter(cm) relationships. O'Brien et al - for 56 pft at BCI - ! ============================================================================ - - type(ed_cohort_type), intent(inout) :: cohort_in - - real(r8) :: m - real(r8) :: c - real(r8) :: h - - m = 0.64_r8 - c = 0.37_r8 - - if(cohort_in%dbh <= 0._r8)then - write(iulog,*) 'ED: dbh less than zero problem!',cohort_in%indexnumber - cohort_in%dbh = 0.1_r8 - endif - - ! if the hite is larger than the maximum allowable height (set by dbhmax) then - ! set the height to the maximum value. - ! this could do with at least re-factoring and probably re-thinking. RF - if(cohort_in%dbh <= EDecophyscon%max_dbh(cohort_in%pft)) then - h = (10.0_r8**(log10(cohort_in%dbh) * m + c)) - else - h = (10.0_r8**(log10(EDecophyscon%max_dbh(cohort_in%pft))*m + c)) - endif - Hite = h - - return - - end function Hite - -! ============================================================================ - - real(r8) function Bleaf( cohort_in ) - - ! ============================================================================ - ! Creates leaf biomass (kGC) as a function of tree diameter. - ! ============================================================================ - - type(ed_cohort_type), intent(in) :: cohort_in - real(r8) :: slascaler ! changes the target biomass according to the SLA - - if(cohort_in%dbh < 0._r8.or.cohort_in%pft == 0.or.cohort_in%dbh > 1000.0_r8)then - write(iulog,*) 'problems in bleaf',cohort_in%dbh,cohort_in%pft - endif - - if(cohort_in%dbh <= EDecophyscon%max_dbh(cohort_in%pft))then - bleaf = 0.0419_r8 * (cohort_in%dbh**1.56) * EDecophyscon%wood_density(cohort_in%pft)**0.55_r8 - else - bleaf = 0.0419_r8 * (EDecophyscon%max_dbh(cohort_in%pft)**1.56) * EDecophyscon%wood_density(cohort_in%pft)**0.55_r8 - endif - slascaler = 0.03_r8/pftcon%slatop(cohort_in%pft) - bleaf = bleaf * slascaler - - !write(iulog,*) 'bleaf',bleaf, slascaler,cohort_in%pft - - !Adjust for canopies that have become so deep that their bottom layer is not producing any carbon... - !nb this will change the allometry and the effects of this remain untested. RF. April 2014 - - bleaf = bleaf * cohort_in%canopy_trim - - return - end function Bleaf - -! ============================================================================ - - real(r8) function tree_lai( cohort_in ) - - ! ============================================================================ - ! LAI of individual trees is a function of the total leaf area and the total canopy area. - ! ============================================================================ - - type(ed_cohort_type), intent(inout) :: cohort_in - - real(r8) :: leafc_per_unitarea ! KgC of leaf per m2 area of ground. - real(r8) :: slat ! the sla of the top leaf layer. m2/kgC - - if( cohort_in%bl < 0._r8 .or. cohort_in%pft == 0 ) then - write(iulog,*) 'problem in treelai',cohort_in%bl,cohort_in%pft - endif - - if( cohort_in%status_coh == 2 ) then ! are the leaves on? - slat = 1000.0_r8 * pftcon%slatop(cohort_in%pft) ! m2/g to m2/kg - cohort_in%c_area = c_area(cohort_in) ! call the tree area - leafc_per_unitarea = cohort_in%bl/(cohort_in%c_area/cohort_in%n) !KgC/m2 - if(leafc_per_unitarea > 0.0_r8)then - tree_lai = leafc_per_unitarea * slat !kg/m2 * m2/kg = unitless LAI - else - tree_lai = 0.0_r8 - endif - else - tree_lai = 0.0_r8 - endif !status - cohort_in%treelai = tree_lai - - ! here, if the LAI exceeeds the maximum size of the possible array, then we have no way of accomodating it - ! at the moments cp_nlevcan default is 40, which is very large, so exceeding this would clearly illustrate a - ! huge error - if(cohort_in%treelai > cp_nlevcan*dinc_ed)then - write(iulog,*) 'too much lai' , cohort_in%treelai , cohort_in%pft , cp_nlevcan * dinc_ed - endif - - return - - end function tree_lai - - ! ============================================================================ - - real(r8) function tree_sai( cohort_in ) - - ! ============================================================================ - ! SAI of individual trees is a function of the total dead biomass per unit canopy area. - ! ============================================================================ - - type(ed_cohort_type), intent(inout) :: cohort_in - - real(r8) :: bdead_per_unitarea ! KgC of leaf per m2 area of ground. - real(r8) :: sai_scaler ! This is hardwired, but should be made a parameter - - ! I need to add a new parameter to the 'standard' parameter file but don't have permission... RF 2 july. - - sai_scaler = 0.05_r8 ! here, a high biomass of 20KgC per m2 gives us a high SAI of 1.0. - - if( cohort_in%bdead < 0._r8 .or. cohort_in%pft == 0 ) then - write(iulog,*) 'problem in treesai',cohort_in%bdead,cohort_in%pft - endif - - cohort_in%c_area = c_area(cohort_in) ! call the tree area - bdead_per_unitarea = cohort_in%bdead/(cohort_in%c_area/cohort_in%n) !KgC/m2 - tree_sai = bdead_per_unitarea * sai_scaler !kg/m2 * m2/kg = unitless LAI - - cohort_in%treesai = tree_sai - - ! here, if the LAI exceeeds the maximum size of the possible array, then we have no way of accomodating it - ! at the moments cp_nlevcan default is 40, which is very large, so exceeding this would clearly illustrate a - ! huge error - if(cohort_in%treesai > cp_nlevcan*dinc_ed)then - write(iulog,*) 'too much sai' , cohort_in%treesai , cohort_in%pft , cp_nlevcan * dinc_ed - endif - - return - - end function tree_sai - - -! ============================================================================ - - real(r8) function c_area( cohort_in ) - - ! ============================================================================ - ! Calculate area of ground covered by entire cohort. (m2) - ! Function of DBH (cm) canopy spread (m/cm) and number of individuals. - ! ============================================================================ - - use EDParamsMod , only : ED_val_grass_spread - - type(ed_cohort_type), intent(in) :: cohort_in - - real(r8) :: dbh ! Tree diameter at breat height. cm. - - if (DEBUG_growth) then - write(iulog,*) 'z_area 1',cohort_in%dbh,cohort_in%pft - write(iulog,*) 'z_area 2',EDecophyscon%max_dbh - write(iulog,*) 'z_area 3',pftcon%woody - write(iulog,*) 'z_area 4',cohort_in%n - write(iulog,*) 'z_area 5',cohort_in%patchptr%spread - write(iulog,*) 'z_area 6',cohort_in%canopy_layer - write(iulog,*) 'z_area 7',ED_val_grass_spread - end if - - dbh = min(cohort_in%dbh,EDecophyscon%max_dbh(cohort_in%pft)) - if(pftcon%woody(cohort_in%pft) == 1)then - c_area = 3.142_r8 * cohort_in%n * & - (cohort_in%patchptr%spread(cohort_in%canopy_layer)*dbh)**1.56_r8 - else - c_area = 3.142_r8 * cohort_in%n * (ED_val_grass_spread*dbh)**1.56_r8 - end if - - end function c_area - -! ============================================================================ - - real(r8) function Bdead( cohort_in ) - - ! ============================================================================ - ! Calculate stem biomass from height(m) dbh(cm) and wood density(g/cm3) - ! using allometry of J.G. Saldarriaga et al 1988 - Rio Negro - ! Journal of Ecology vol 76 p938-958 - ! ============================================================================ - - type(ed_cohort_type), intent(in) :: cohort_in - - bdead = 0.06896_r8*(cohort_in%hite**0.572_r8)*(cohort_in%dbh**1.94_r8)* & - (EDecophyscon%wood_density(cohort_in%pft)**0.931_r8) - - end function Bdead - -! ============================================================================ - - real(r8) function dHdBd( cohort_in ) - - ! ============================================================================ - ! convert changes in structural biomass to changes in height - ! consistent with Bstem and h-dbh allometries - ! ============================================================================ - - type(ed_cohort_type), intent(in) :: cohort_in - - real(r8) :: dbddh ! rate of change of dead biomass (KgC) per unit change of height (m) - - dbddh = 0.06896_r8*0.572_r8*(cohort_in%hite**(-0.428_r8))*(cohort_in%dbh**1.94_r8)* & - (EDecophyscon%wood_density(cohort_in%pft)**0.931_r8) - dHdBd = 1.0_r8/dbddh !m/KgC - - return - - end function dHdBd - -! ============================================================================ - real(r8) function dDbhdBd( cohort_in ) - - ! ============================================================================ - ! convert changes in structural biomass to changes in diameter - ! consistent with Bstem and h-dbh allometries - ! ============================================================================ - - type(ed_cohort_type), intent(in) :: cohort_in - - real(r8) :: dBD_dDBH !Rate of change of dead biomass (KgC) with change in DBH (cm) - real(r8) :: dH_dDBH !Rate of change of height (m) with change in DBH (cm) - - dBD_dDBH = 1.94_r8*0.06896_r8*(cohort_in%hite**0.572_r8)*(cohort_in%dbh**0.94_r8)* & - (EDecophyscon%wood_density(cohort_in%pft)**0.931_r8) - if(cohort_in%dbh < EDecophyscon%max_dbh(cohort_in%pft))then - dH_dDBH = 1.4976_r8*(cohort_in%dbh**(-0.36_r8)) - dBD_dDBH = dBD_dDBH + 0.572_r8*0.06896_r8*(cohort_in%hite**(0.572_r8 - 1.0_r8))* & - (cohort_in%dbh**1.94_r8)*(EDecophyscon%wood_density(cohort_in%pft)**0.931_r8)*dH_dDBH - endif - - dDbhdBd = 1.0/dBD_dDBH - - return - - end function dDbhdBd - -! ============================================================================ - - real(r8) function dDbhdBl( cohort_in ) - - ! ============================================================================ - ! convert changes in leaf biomass (KgC) to changes in DBH (cm) - ! ============================================================================ - - type(ed_cohort_type), intent(in) :: cohort_in - - real(r8) :: dblddbh ! Rate of change of leaf biomass with change in DBH - - dblddbh = 1.56_r8*0.0419_r8*(cohort_in%dbh**0.56_r8)*(EDecophyscon%wood_density(cohort_in%pft)**0.55_r8) - dblddbh = dblddbh*cohort_in%canopy_trim - - if( cohort_in%dbh 0._r8 ) then - if(Bleaf(cohort_in) > 0._r8 .and. cohort_in%bstore <= Bleaf(cohort_in))then - frac = cohort_in%bstore/(Bleaf(cohort_in)) - cmort = max(0.0_r8,ED_val_stress_mort*(1.0_r8 - frac)) - else - cmort = 0.0_r8 - endif - - else - write(iulog,*) 'dbh problem in mortality_rates', & - cohort_in%dbh,cohort_in%pft,cohort_in%n,cohort_in%canopy_layer,cohort_in%indexnumber - endif - - !mortality_rates = bmort + hmort + cmort - - end subroutine mortality_rates - -! ============================================================================ - -end module EDGrowthFunctionsMod diff --git a/src/ED/biogeochem/EDPatchDynamicsMod.F90 b/src/ED/biogeochem/EDPatchDynamicsMod.F90 deleted file mode 100755 index c011b7d407..0000000000 --- a/src/ED/biogeochem/EDPatchDynamicsMod.F90 +++ /dev/null @@ -1,1516 +0,0 @@ -module EDPatchDynamicsMod - - ! ============================================================================ - ! Controls formation, creation, fusing and termination of patch level processes. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8; - use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) - use clm_varctl , only : iulog - use pftconMod , only : pftcon - use EDCohortDynamicsMod , only : fuse_cohorts, sort_cohorts, insert_cohort - use EDtypesMod , only : ncwd, n_dbh_bins, ntol, numpft_ed, area, dbhmax, numPatchesPerCol - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type, udata - use EDTypesMod , only : min_patch_area, cp_numlevgrnd, cp_numSWb - ! - implicit none - private - ! - public :: create_patch - public :: spawn_patches - public :: zero_patch - public :: fuse_patches - public :: terminate_patches - public :: patch_pft_size_profile - public :: disturbance_rates - public :: check_patch_area - public :: set_patchno - - private:: fuse_2_patches - - - ! 10/30/09: Created by Rosie Fisher - ! ============================================================================ - -contains - - ! ============================================================================ - subroutine disturbance_rates( site_in) - ! - ! !DESCRIPTION: - ! Calculates the fire and mortality related disturbance rates for each patch, - ! and then determines which is the larger at the patch scale (for now, there an only - ! be one disturbance type for each timestep. - ! all disturbance rates here are per daily timestep. - ! - ! !USES: - use EDGrowthFunctionsMod , only : c_area, mortality_rates - use EDTypesMod , only : udata - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(inout), target :: site_in - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort - real(r8) :: cmort - real(r8) :: bmort - real(r8) :: hmort - !--------------------------------------------------------------------- - - !MORTALITY - site_in%disturbance_mortality = 0.0_r8 - - currentPatch => site_in%oldest_patch - - do while (associated(currentPatch)) - - currentCohort => currentPatch%shortest - - do while(associated(currentCohort)) - ! Mortality for trees in the understorey. - currentCohort%patchptr => currentPatch - - call mortality_rates(currentCohort,cmort,hmort,bmort) - currentCohort%dmort = cmort+hmort+bmort - currentCohort%c_area = c_area(currentCohort) - - ! Initialize diagnostic mortality rates - currentCohort%cmort = cmort - currentCohort%bmort = bmort - currentCohort%hmort = hmort - currentCohort%imort = 0.0_r8 ! Impact mortality is always zero except in new patches - currentCohort%fmort = 0.0_r8 ! Fire mortality is initialized as zero, but may be changed - - if(currentCohort%canopy_layer == 1)then - - currentPatch%disturbance_rates(1) = currentPatch%disturbance_rates(1) + & - min(1.0_r8,currentCohort%dmort)*udata%deltat*currentCohort%c_area/currentPatch%area - - endif - - currentCohort => currentCohort%taller - - enddo !currentCohort - - ! if fires occur at site - ! Fudge - fires can't burn the whole patch, as this causes /0 errors. - ! This is accumulating the daily fires over the whole 30 day patch generation phase. - currentPatch%disturbance_rates(2) = min(0.99_r8,currentPatch%disturbance_rates(2) + currentPatch%frac_burnt) - - if (currentPatch%disturbance_rates(2) > 0.98_r8)then - write(iulog,*) 'very high fire areas',currentPatch%disturbance_rates(2),currentPatch%frac_burnt - endif - - !Only use larger of two natural disturbance modes WHY? - if(currentPatch%disturbance_rates(2) > currentPatch%disturbance_rates(1))then ! DISTURBANCE IS FIRE - currentPatch%disturbance_rate = currentPatch%disturbance_rates(2) - - ! RGK 02-18-2014 - ! Since treefall mortality is not actually being applied - ! Go through and zero the diagnostic rates - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - if(currentCohort%canopy_layer == 1)then - currentCohort%cmort=0.0_r8 - currentCohort%hmort=0.0_r8 - currentCohort%bmort=0.0_r8 - end if - - ! This may be counter-intuitive, but the diagnostic fire-mortality rate - ! will stay zero in the patch that undergoes fire, this is because - ! the actual cohorts who experience the fire are only those in the - ! newly created patch so currentCohort%fmort = 0.0_r8 - ! Don't worry, the cohorts in the newly created patch will reflect burn - - currentCohort => currentCohort%taller - enddo !currentCohort - - else - currentPatch%disturbance_rate = currentPatch%disturbance_rates(1) ! DISTURBANCE IS MORTALITY - endif - - site_in%disturbance_mortality = site_in%disturbance_mortality + & - currentPatch%disturbance_rates(1)*currentPatch%area/area - currentPatch => currentPatch%younger - - enddo !patch loop - - ! FIRE - site_in%disturbance_fire = site_in%frac_burnt/AREA - - ! Use largest disturbance mode and ignore the other... This is necessary to - ! have a single type of disturbance and to calculate the survival rates etc... - if (site_in%disturbance_fire > site_in%disturbance_mortality) then - site_in%disturbance_rate = site_in%disturbance_fire - site_in%dist_type = 2 - else - site_in%disturbance_rate = site_in%disturbance_mortality - site_in%dist_type = 1 - endif - - end subroutine disturbance_rates - - ! ============================================================================ - subroutine spawn_patches( currentSite ) - ! - ! !DESCRIPTION: - ! In this subroutine, the following happens - ! 1) the total area disturbed is calculated - ! 2) a new patch is created - ! 3) properties are averaged - ! 4) litter fluxes from fire and mortality are added - ! 5) For mortality, plants in existing patch canopy are killed. - ! 6) For mortality, Plants in new and existing understorey are killed - ! 7) For fire, burned plants are killed, and unburned plants are added to new patch. - ! 8) New cohorts are added to new patch and sorted. - ! 9) New patch is added into linked list - ! 10) Area checked, and patchno recalculated. - ! - ! !USES: - use EDTypesMod , only : cp_nclmax - use EDParamsMod , only : ED_val_maxspread, ED_val_understorey_death - use EDCohortDynamicsMod , only : zero_cohort, copy_cohort, terminate_cohorts - ! - ! !ARGUMENTS: - type (ed_site_type), intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: new_patch - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort - type (ed_cohort_type), pointer :: nc - type (ed_cohort_type), pointer :: storesmallcohort - type (ed_cohort_type), pointer :: storebigcohort - real(r8) :: site_areadis ! total area disturbed in m2 per site per day - real(r8) :: patch_site_areadis ! total area disturbed in m2 per patch per day - real(r8) :: age ! notional age of this patch in years - integer :: tnull ! is there a tallest cohort? - integer :: snull ! is there a shortest cohort? - real(r8) :: root_litter_local(numpft_ed) ! initial value of root litter. KgC/m2 - real(r8) :: leaf_litter_local(numpft_ed) ! initial value of leaf litter. KgC/m2 - real(r8) :: cwd_ag_local(ncwd) ! initial value of above ground coarse woody debris. KgC/m2 - real(r8) :: cwd_bg_local(ncwd) ! initial value of below ground coarse woody debris. KgC/m2 - real(r8) :: seed_bank_local(numpft_ed) ! initial value of seed bank. KgC/m2 - real(r8) :: spread_local(cp_nclmax) ! initial value of canopy spread parameter.no units - !--------------------------------------------------------------------- - - storesmallcohort => null() ! storage of the smallest cohort for insertion routine - storebigcohort => null() ! storage of the largest cohort for insertion routine - - ! calculate area of disturbed land, in this timestep, by summing contributions from each existing patch. - currentPatch => currentSite%youngest_patch - - ! zero site-level fire fluxes - currentSite%cwd_ag_burned = 0.0_r8 - currentSite%leaf_litter_burned = 0.0_r8 - currentSite%total_burn_flux_to_atm = 0.0_r8 - - site_areadis = 0.0_r8 - do while(associated(currentPatch)) - - !FIX(RF,032414) Does using the max(fire,mort) actually make sense here? - site_areadis = site_areadis + currentPatch%area * min(1.0_r8,currentPatch%disturbance_rate) - currentPatch => currentPatch%older - - enddo ! end loop over patches. sum area disturbed for all patches. - - if (site_areadis > 0.0_r8) then - cwd_ag_local = 0.0_r8 - cwd_bg_local = 0.0_r8 - leaf_litter_local = 0.0_r8 - root_litter_local = 0.0_r8 - spread_local(1:cp_nclmax) = ED_val_maxspread - age = 0.0_r8 - seed_bank_local = 0.0_r8 - - allocate(new_patch) - -! This is called inside "create_patch" -! create_patch must first allocate some vector spaces before -! zero'ing can occur (RGK) -! call zero_patch(new_patch) - - call create_patch(currentSite, new_patch, age, site_areadis, & - spread_local, cwd_ag_local, cwd_bg_local, leaf_litter_local, & - root_litter_local, seed_bank_local) - - new_patch%tallest => null() - new_patch%shortest => null() - - currentPatch => currentSite%oldest_patch - ! loop round all the patches that contribute surviving indivduals and litter pools to the new patch. - do while(associated(currentPatch)) - patch_site_areadis = currentPatch%area * currentPatch%disturbance_rate ! how much land is disturbed in this donor patch? - - call average_patch_properties(currentPatch, new_patch, patch_site_areadis) ! MAY BE REDUNDANT CALL - if (currentSite%disturbance_mortality > currentSite%disturbance_fire) then !mortality is dominant disturbance - call mortality_litter_fluxes(currentPatch, new_patch, patch_site_areadis) - else - call fire_litter_fluxes(currentPatch, new_patch, patch_site_areadis) - endif - - !INSERT SURVIVORS FROM DISTURBANCE INTO NEW PATCH - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - - allocate(nc) - call zero_cohort(nc) - - ! nc is the new cohort that goes in the disturbed patch (new_patch)... currentCohort - ! is the curent cohort that stays in the donor patch (currentPatch) - call copy_cohort(currentCohort, nc) - - !this is the case as the new patch probably doesn't have a closed canopy, and - ! even if it does, that will be sorted out in canopy_structure. - nc%canopy_layer = 1 - - !mortality is dominant disturbance - if(currentPatch%disturbance_rates(1) > currentPatch%disturbance_rates(2))then - if(currentCohort%canopy_layer == 1)then - ! In the donor patch we are left with fewer trees because the area has decreased - ! the plant density for large trees does not actually decrease in the donor patch - ! because this is the part of the original patch where no trees have actually fallen - ! The diagnostic cmort,bmort and hmort rates have already been saved - - currentCohort%n = currentCohort%n * (1.0_r8 - min(1.0_r8,currentCohort%dmort * udata%deltat)) - - nc%n = 0.0_r8 ! kill all of the trees who caused the disturbance. - nc%cmort = nan ! The mortality diagnostics are set to nan because the cohort should dissappear - nc%hmort = nan - nc%bmort = nan - nc%fmort = nan - nc%imort = nan - else - ! small trees - if(pftcon%woody(currentCohort%pft) == 1)then - - ! Number of trees in the understory of new patch, before we impose impact mortality and survivorship - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! remaining of understory plants of those that are knocked over by the overstorey trees dying... - nc%n = (1.0_r8 - ED_val_understorey_death) * currentCohort%n * patch_site_areadis/currentPatch%area - - ! since the donor patch split and sent a fraction of its members - ! to the new patch and a fraction to be preserved in itself, - ! when reporting diagnostic rates, we must carry over the mortality rates from - ! the donor that were applied before the patch split. Remember this is only - ! for diagnostics. But think of it this way, the rates are weighted by - ! number density in EDCLMLink, and the number density of this new patch is donated - ! so with the number density must come the effective mortality rates. - - nc%fmort = 0.0_r8 ! Should had also been zero in the donor - nc%imort = ED_val_understorey_death/udata%deltat ! This was zero in the donor - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - - ! understory trees that might potentially be knocked over in the disturbance. - ! The existing (donor) patch should not have any impact mortality, it should - ! only lose cohorts due to the decrease in area. This is not mortality. - ! Besides, the current and newly created patch sum to unity - - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - else - ! grass is not killed by mortality disturbance events. Just move it into the new patch area. - ! Just split the grass into the existing and new patch structures - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! Those remaining in the existing - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - nc%fmort = nan ! These should not make it to the diagnostics - nc%imort = nan ! If they do.. they should invalidate it - nc%cmort = nan ! - nc%hmort = nan ! - nc%bmort = nan ! - - endif - endif - else !fire - - ! Number of members in the new patch, before we impose fire survivorship - nc%n = currentCohort%n * patch_site_areadis/currentPatch%area - - ! loss of individuals from source patch due to area shrinking - currentCohort%n = currentCohort%n * (1._r8 - patch_site_areadis/currentPatch%area) - - ! loss of individual from fire in new patch. - nc%n = nc%n * (1.0_r8 - currentCohort%fire_mort) - - nc%fmort = currentCohort%fire_mort/udata%deltat - nc%imort = 0.0_r8 - nc%cmort = currentCohort%cmort - nc%hmort = currentCohort%hmort - nc%bmort = currentCohort%bmort - - endif - - if (nc%n > 0.0_r8) then - storebigcohort => new_patch%tallest - storesmallcohort => new_patch%shortest - if(associated(new_patch%tallest))then - tnull = 0 - else - tnull = 1 - new_patch%tallest => nc - nc%taller => null() - endif - - if(associated(new_patch%shortest))then - snull = 0 - else - snull = 1 - new_patch%shortest => nc - nc%shorter => null() - endif - nc%patchptr => new_patch - call insert_cohort(nc, new_patch%tallest, new_patch%shortest, tnull, snull, storebigcohort, storesmallcohort) - - new_patch%tallest => storebigcohort - new_patch%shortest => storesmallcohort - else - deallocate(nc) !get rid of the new memory. - endif - - currentCohort => currentCohort%taller - enddo ! currentCohort - call sort_cohorts(currentPatch) - - !zero disturbance accumulators - currentPatch%disturbance_rate = 0._r8 - currentPatch%disturbance_rates = 0._r8 - - !update area of donor patch - currentPatch%area = currentPatch%area - patch_site_areadis - - !sort out the cohorts, since some of them may be so small as to need removing. - call fuse_cohorts(currentPatch) - call terminate_cohorts(currentPatch) - call sort_cohorts(currentPatch) - - currentPatch => currentPatch%younger - - enddo ! currentPatch patch loop. - - !*************************/ - !** INSERT NEW PATCH INTO LINKED LIST - !**********`***************/ - currentPatch => currentSite%youngest_patch - new_patch%older => currentPatch - new_patch%younger => NULL() - currentPatch%younger => new_patch - currentSite%youngest_patch => new_patch - - call fuse_cohorts(new_patch) - call terminate_cohorts(new_patch) - call sort_cohorts(new_patch) - - endif !end new_patch area - - call check_patch_area(currentSite) - call set_patchno(currentSite) - - end subroutine spawn_patches - - ! ============================================================================ - subroutine check_patch_area( currentSite ) - ! - ! !DESCRIPTION: - ! Check to see that total area is not exceeded. - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type), intent(in), target :: currentSite - ! - ! !LOCAL VARIABLES: - real(r8) :: areatot - type(ed_patch_type), pointer :: currentPatch - !--------------------------------------------------------------------- - - areatot = 0._r8 - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - areatot = areatot + currentPatch%area - currentPatch => currentPatch%younger - if (( areatot - area ) > 0._r8 ) then - write(iulog,*) 'trimming patch area - is too big' , areatot-area - currentSite%oldest_patch%area = currentSite%oldest_patch%area - (areatot - area) - endif - enddo - - end subroutine check_patch_area - - ! ============================================================================ - subroutine set_patchno( currentSite ) - ! - ! !DESCRIPTION: - ! Give patches an order number from the oldest to youngest. - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type),intent(in), target :: currentSite - ! - ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - integer patchno - !--------------------------------------------------------------------- - - patchno = 1 - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - currentPatch%patchno = patchno - patchno = patchno + 1 - currentPatch => currentPatch%younger - enddo - - end subroutine set_patchno - - ! ============================================================================ - subroutine average_patch_properties( currentPatch, newPatch, patch_site_areadis ) - ! - ! !DESCRIPTION: - ! Average together the state properties of all of the donor patches that - ! make up the new patch. - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_patch_type) , intent(in), target :: currentPatch - type(ed_patch_type) , intent(inout) :: newPatch - real(r8) , intent(out) :: patch_site_areadis ! amount of land disturbed in this patch. m2 - ! - ! !LOCAL VARIABLES: - integer :: c,p ! counters for PFT and litter size class. - !--------------------------------------------------------------------- - - patch_site_areadis = currentPatch%area * currentPatch%disturbance_rate ! how much land is disturbed in this donor patch? - - do p=1,numpft_ed - newPatch%seed_bank(p) = newPatch%seed_bank(p) + currentPatch%seed_bank(p) * patch_site_areadis/newPatch%area - enddo - - do c = 1,ncwd !move litter pool en mass into the new patch. - newPatch%cwd_ag(c) = newPatch%cwd_ag(c) + currentPatch%cwd_ag(c) * patch_site_areadis/newPatch%area - newPatch%cwd_bg(c) = newPatch%cwd_bg(c) + currentPatch%cwd_bg(c) * patch_site_areadis/newPatch%area - enddo - - do p = 1,numpft_ed !move litter pool en mass into the new patch - newPatch%root_litter(p) = newPatch%root_litter(p) + currentPatch%root_litter(p) * patch_site_areadis/newPatch%area - newPatch%leaf_litter(p) = newPatch%leaf_litter(p) + currentPatch%leaf_litter(p) * patch_site_areadis/newPatch%area - enddo - - newPatch%spread = newPatch%spread + currentPatch%spread * patch_site_areadis/newPatch%area - - end subroutine average_patch_properties - - ! ============================================================================ - subroutine fire_litter_fluxes(cp_target, new_patch_target, patch_site_areadis) - ! - ! !DESCRIPTION: - ! CWD pool burned by a fire. - ! Carbon going from burned trees into CWD pool - ! Burn parts of trees that don't die in fire - ! Burn live grasses and kill them. - ! - ! !USES: - use EDParamsMod, only : ED_val_ag_biomass - use SFParamsMod, only : SF_VAL_CWD_FRAC - use EDGrowthFunctionsMod, only : c_area - use EDtypesMod , only : dg_sf - ! - ! !ARGUMENTS: - type(ed_patch_type) , intent(inout), target :: cp_target - type(ed_patch_type) , intent(inout), target :: new_patch_target - real(r8) , intent(inout) :: patch_site_areadis - ! - ! !LOCAL VARIABLES: - type(ed_site_type) , pointer :: currentSite - type(ed_patch_type) , pointer :: currentPatch - type(ed_patch_type) , pointer :: new_patch - type(ed_cohort_type), pointer :: currentCohort - real(r8) :: bcroot ! amount of below ground coarse root per cohort kgC. (goes into CWD_BG) - real(r8) :: bstem ! amount of above ground stem biomass per cohort kgC.(goes into CWG_AG) - real(r8) :: dead_tree_density ! no trees killed by fire per m2 - reaL(r8) :: burned_litter ! amount of each litter pool burned by fire. kgC/m2/day - real(r8) :: burned_leaves ! amount of tissue consumed by fire for grass. KgC/individual/day - integer :: c, p - !--------------------------------------------------------------------- - - !check that total area is not exceeded. - currentPatch => cp_target - new_patch => new_patch_target - - if ( currentPatch%fire == 1 ) then !only do this if there was a fire in this actual patch. - patch_site_areadis = currentPatch%area * currentPatch%disturbance_rate ! how much land is disturbed in this donor patch? - currentSite => currentPatch%siteptr - - !************************************/ - !PART 1) Burn the fractions of existing litter in the new patch that were consumed by the fire. - !************************************/ - do c = 1,ncwd - burned_litter = new_patch%cwd_ag(c) * patch_site_areadis/new_patch%area * currentPatch%burnt_frac_litter(c+1) !kG/m2/day - new_patch%cwd_ag(c) = new_patch%cwd_ag(c) - burned_litter - currentSite%flux_out = currentSite%flux_out + burned_litter * new_patch%area !kG/site/day - currentSite%total_burn_flux_to_atm = currentSite%total_burn_flux_to_atm + burned_litter * new_patch%area !kG/site/day - enddo - - do p = 1,numpft_ed - burned_litter = new_patch%leaf_litter(p) * patch_site_areadis/new_patch%area * currentPatch%burnt_frac_litter(dg_sf) - new_patch%leaf_litter(p) = new_patch%leaf_litter(p) - burned_litter - currentSite%flux_out = currentSite%flux_out + burned_litter * new_patch%area !kG/site/day - currentSite%total_burn_flux_to_atm = currentSite%total_burn_flux_to_atm + burned_litter * new_patch%area !kG/site/day - enddo - - !************************************/ - !PART 2) Put unburned parts of plants that died in the fire into the litter pool of new and old patches - ! This happens BEFORE the plant numbers have been updated. So we are working with the - ! pre-fire population of plants, which is the right way round. - !************************************/ - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - p = currentCohort%pft - if(pftcon%woody(p) == 1)then !DEAD (FROM FIRE) TREES - !************************************/ - ! Number of trees that died because of the fire, per m2 of ground. - ! Divide their litter into the four litter streams, and spread evenly across ground surface. - !************************************/ - ! stem biomass per tree - bstem = (currentCohort%bsw + currentCohort%bdead) * ED_val_ag_biomass - ! coarse root biomass per tree - bcroot = (currentCohort%bsw + currentCohort%bdead) * (1.0_r8 - ED_val_ag_biomass) - ! density of dead trees per m2. - dead_tree_density = (currentCohort%fire_mort * currentCohort%n*patch_site_areadis/currentPatch%area) / AREA - - ! Unburned parts of dead tree pool. - ! Unburned leaves and roots - - new_patch%leaf_litter(p) = new_patch%leaf_litter(p) + dead_tree_density * (currentCohort%bl) & - * (1.0_r8-currentCohort%cfa) - new_patch%root_litter(p) = new_patch%root_litter(p) + dead_tree_density * (currentCohort%br+currentCohort%bstore) - currentPatch%leaf_litter(p) = currentPatch%leaf_litter(p) + dead_tree_density * & - (currentCohort%bl) * (1.0_r8-currentCohort%cfa) - currentPatch%root_litter(p) = currentPatch%root_litter(p) + dead_tree_density * & - (currentCohort%br+currentCohort%bstore) - - ! below ground coarse woody debris from burned trees - do c = 1,ncwd - new_patch%cwd_bg(c) = new_patch%cwd_bg(c) + dead_tree_density * SF_val_CWD_frac(c) * bcroot - currentPatch%cwd_bg(c) = currentPatch%cwd_bg(c) + dead_tree_density * SF_val_CWD_frac(c) * bcroot - enddo - - ! above ground coarse woody debris from unburned twigs and small branches - do c = 1,2 - new_patch%cwd_ag(c) = new_patch%cwd_ag(c) + dead_tree_density * SF_val_CWD_frac(c) * bstem & - * (1.0_r8-currentCohort%cfa) - currentPatch%cwd_ag(c) = currentPatch%cwd_ag(c) + dead_tree_density * SF_val_CWD_frac(c) * & - bstem * (1.0_r8-currentCohort%cfa) - enddo - - ! above ground coarse woody debris from large branches and stems: these do not burn in crown fires. - do c = 3,4 - new_patch%cwd_ag(c) = new_patch%cwd_ag(c) + dead_tree_density * SF_val_CWD_frac(c) * bstem - currentPatch%cwd_ag(c) = currentPatch%cwd_ag(c) + dead_tree_density * SF_val_CWD_frac(c) * bstem - enddo - - ! Burned parts of dead tree pool. - ! Burned twigs and small branches. - do c = 1,2 - - currentSite%cwd_ag_burned(c) = currentSite%cwd_ag_burned(c) + dead_tree_density * & - SF_val_CWD_frac(c) * bstem * currentCohort%cfa - currentSite%flux_out = currentSite%flux_out + dead_tree_density * & - AREA * SF_val_CWD_frac(c) * bstem * currentCohort%cfa - currentSite%total_burn_flux_to_atm = currentSite%total_burn_flux_to_atm + dead_tree_density * & - AREA * SF_val_CWD_frac(c) * bstem * currentCohort%cfa - - enddo - - !burned leaves. - do p = 1,numpft_ed - - currentSite%leaf_litter_burned(p) = currentSite%leaf_litter_burned(p) + & - dead_tree_density * currentCohort%bl * currentCohort%cfa - currentSite%flux_out = currentSite%flux_out + & - dead_tree_density * AREA * currentCohort%bl * currentCohort%cfa - currentSite%total_burn_flux_to_atm = currentSite%total_burn_flux_to_atm + & - dead_tree_density * AREA * currentCohort%bl * currentCohort%cfa - - enddo - - endif - - currentCohort => currentCohort%taller - - enddo ! currentCohort - - !************************************/ - ! PART 3) Burn parts of trees that did *not* die in the fire. - ! PART 4) Burn parts of grass that are consumed by the fire. - ! grasses are not killed directly by fire. They die by losing all of their leaves and starving. - !************************************/ - currentCohort => new_patch%shortest - do while(associated(currentCohort)) - - currentCohort%c_area = c_area(currentCohort) - if(pftcon%woody(currentCohort%pft) == 1)then - burned_leaves = (currentCohort%bl+currentCohort%bsw) * currentCohort%cfa - else - burned_leaves = (currentCohort%bl+currentCohort%bsw) * currentPatch%burnt_frac_litter(6) - endif - if (burned_leaves > 0.0_r8) then - - currentCohort%balive = max(currentCohort%br,currentCohort%balive - burned_leaves) - currentCohort%bl = max(0.00001_r8, currentCohort%bl - burned_leaves) - !KgC/gridcell/day - currentSite%flux_out = currentSite%flux_out + burned_leaves * currentCohort%n * & - patch_site_areadis/currentPatch%area * AREA - currentSite%total_burn_flux_to_atm = currentSite%total_burn_flux_to_atm+ burned_leaves * currentCohort%n * & - patch_site_areadis/currentPatch%area * AREA - - endif - currentCohort%cfa = 0.0_r8 - - currentCohort => currentCohort%taller - - enddo - - endif !currentPatch%fire. - - end subroutine fire_litter_fluxes - - ! ============================================================================ - subroutine mortality_litter_fluxes(cp_target, new_patch_target, patch_site_areadis) - ! - ! !DESCRIPTION: - ! Carbon going from ongoing mortality into CWD pools. - ! - ! !USES: - use EDParamsMod, only : ED_val_ag_biomass, ED_val_understorey_death - use SFParamsMod, only : SF_val_cwd_frac - ! - ! !ARGUMENTS: - type(ed_patch_type) , intent(inout), target :: cp_target - type(ed_patch_type) , intent(inout), target :: new_patch_target - real(r8) , intent(in) :: patch_site_areadis - ! - ! !LOCAL VARIABLES: - real(r8) :: cwd_litter_density - real(r8) :: litter_area ! area over which to distribute this litter. - type(ed_cohort_type), pointer :: currentCohort - type(ed_patch_type) , pointer :: currentPatch - type(ed_patch_type) , pointer :: new_patch - real(r8) :: understorey_dead !Number of individual dead from the canopy layer /day - real(r8) :: canopy_dead !Number of individual dead from the understorey layer /day - real(r8) :: np_mult !Fraction of the new patch which came from the current patch (and so needs the same litter) - integer :: p,c - !--------------------------------------------------------------------- - - currentPatch => cp_target - new_patch => new_patch_target - currentPatch%canopy_mortality_woody_litter = 0.0_r8 ! mortality generated litter. KgC/m2/day - currentPatch%canopy_mortality_leaf_litter(:) = 0.0_r8 - currentPatch%canopy_mortality_root_litter(:) = 0.0_r8 - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - p = currentCohort%pft - if(currentPatch%disturbance_rates(1) > currentPatch%disturbance_rates(2))then !mortality is dominant disturbance - if(currentCohort%canopy_layer == 1)then - !currentCohort%dmort = mortality_rates(currentCohort) - !the disturbance calculations are done with the previous n, c_area and d_mort. So it's probably & - !not right to recalcualte dmort here. - canopy_dead = currentCohort%n * min(1.0_r8,currentCohort%dmort * udata%deltat) - - currentPatch%canopy_mortality_woody_litter = currentPatch%canopy_mortality_woody_litter + & - canopy_dead*(currentCohort%bdead+currentCohort%bsw) - currentPatch%canopy_mortality_leaf_litter(p) = currentPatch%canopy_mortality_leaf_litter(p)+ & - canopy_dead*(currentCohort%bl) - currentPatch%canopy_mortality_root_litter(p) = currentPatch%canopy_mortality_root_litter(p)+ & - canopy_dead*(currentCohort%br+currentCohort%bstore) - - else - if(pftcon%woody(currentCohort%pft) == 1)then - - understorey_dead = ED_val_understorey_death * currentCohort%n * (patch_site_areadis/currentPatch%area) !kgC/site/day - currentPatch%canopy_mortality_woody_litter = currentPatch%canopy_mortality_woody_litter + & - understorey_dead*(currentCohort%bdead+currentCohort%bsw) - currentPatch%canopy_mortality_leaf_litter(p)= currentPatch%canopy_mortality_leaf_litter(p)+ & - understorey_dead* currentCohort%bl - currentPatch%canopy_mortality_root_litter(p)= currentPatch%canopy_mortality_root_litter(p)+ & - understorey_dead*(currentCohort%br+currentCohort%bstore) - - ! FIX(SPM,040114) - clarify this comment - ! grass is not killed by canopy mortality disturbance events. - ! Just move it into the new patch area. - else - ! no-op - endif - endif - endif - - currentCohort => currentCohort%taller - - enddo !currentCohort - - !************************************/ - !Evenly distribute the litter from the trees that died across the new and old patches - !************************************/ - !************************************/ - !Evenly distribute the litter from the trees that died across the new and old patches - !'litter' fluxes here are in KgC - !************************************/ - litter_area = currentPatch%area - np_mult = patch_site_areadis/new_patch%area - ! This litter is distributed between the current and new patches, & - ! not to any other patches. This is really the eventually area of the current patch & - ! (currentPatch%area-patch_site_areadis) +patch_site_areadis... - ! For the new patch, only some fraction of its land area (patch_areadis/np%area) is derived from the current patch - ! so we need to multiply by patch_areadis/np%area - do c = 1,ncwd - - cwd_litter_density = SF_val_CWD_frac(c) * currentPatch%canopy_mortality_woody_litter / litter_area - - new_patch%cwd_ag(c) = new_patch%cwd_ag(c) + ED_val_ag_biomass * cwd_litter_density * np_mult - currentPatch%cwd_ag(c) = currentPatch%cwd_ag(c) + ED_val_ag_biomass * cwd_litter_density - new_patch%cwd_bg(c) = new_patch%cwd_bg(c) + (1._r8-ED_val_ag_biomass) * cwd_litter_density * np_mult - currentPatch%cwd_bg(c) = currentPatch%cwd_bg(c) + (1._r8-ED_val_ag_biomass) * cwd_litter_density - - enddo - - do p = 1,numpft_ed - - new_patch%leaf_litter(p) = new_patch%leaf_litter(p) + currentPatch%canopy_mortality_leaf_litter(p) / litter_area * np_mult - new_patch%root_litter(p) = new_patch%root_litter(p) + currentPatch%canopy_mortality_root_litter(p) / litter_area * np_mult - currentPatch%leaf_litter(p) = currentPatch%leaf_litter(p) + currentPatch%canopy_mortality_leaf_litter(p) / litter_area - currentPatch%root_litter(p) = currentPatch%root_litter(p) + currentPatch%canopy_mortality_root_litter(p) / litter_area - - enddo - - end subroutine mortality_litter_fluxes - - ! ============================================================================ - subroutine create_patch(currentSite, new_patch, age, areap, spread_local,cwd_ag_local,cwd_bg_local, & - leaf_litter_local,root_litter_local,seed_bank_local) - ! - ! !DESCRIPTION: - ! Set default values for creating a new patch - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(inout), target :: currentSite - type(ed_patch_type), intent(inout), target :: new_patch - real(r8), intent(in) :: age ! notional age of this patch in years - real(r8), intent(in) :: areap ! initial area of this patch in m2. - real(r8), intent(in) :: cwd_ag_local(:) ! initial value of above ground coarse woody debris. KgC/m2 - real(r8), intent(in) :: cwd_bg_local(:) ! initial value of below ground coarse woody debris. KgC/m2 - real(r8), intent(in) :: root_litter_local(:)! initial value of root litter. KgC/m2 - real(r8), intent(in) :: leaf_litter_local(:)! initial value of leaf litter. KgC/m2 - real(r8), intent(in) :: spread_local(:) ! initial value of canopy spread parameter.no units - real(r8), intent(in) :: seed_bank_local(:) ! initial value of seed bank. KgC/m2 - ! - ! !LOCAL VARIABLES: - !--------------------------------------------------------------------- - - allocate(new_patch%tr_soil_dir(cp_numSWb)) - allocate(new_patch%tr_soil_dif(cp_numSWb)) - allocate(new_patch%tr_soil_dir_dif(cp_numSWb)) - allocate(new_patch%fab(cp_numSWb)) - allocate(new_patch%fabd(cp_numSWb)) - allocate(new_patch%fabi(cp_numSWb)) - allocate(new_patch%sabs_dir(cp_numSWb)) - allocate(new_patch%sabs_dif(cp_numSWb)) - allocate(new_patch%rootfr_ft(numpft_ed,cp_numlevgrnd)) - allocate(new_patch%rootr_ft(numpft_ed,cp_numlevgrnd)) - - call zero_patch(new_patch) !The nan value in here is not working?? - - new_patch%tallest => null() ! pointer to patch's tallest cohort - new_patch%shortest => null() ! pointer to patch's shortest cohort - new_patch%older => null() ! pointer to next older patch - new_patch%younger => null() ! pointer to next shorter patch - new_patch%siteptr => null() ! pointer to the site that the patch is in - - ! assign known patch attributes - - new_patch%siteptr => currentSite - new_patch%age = age - new_patch%area = areap - new_patch%spread = spread_local - new_patch%cwd_ag = cwd_ag_local - new_patch%cwd_bg = cwd_bg_local - new_patch%leaf_litter = leaf_litter_local - new_patch%root_litter = root_litter_local - new_patch%seed_bank = seed_bank_local - - !zeroing things because of the surfacealbedo problem... shouldnt really be necesary - new_patch%cwd_ag_in(:) = 0._r8 - new_patch%cwd_bg_in(:) = 0._r8 - - new_patch%cwd_ag_out(:) = 0._r8 - new_patch%cwd_bg_out(:) = 0._r8 - - new_patch%f_sun = 0._r8 - new_patch%ed_laisun_z(:,:,:) = 0._r8 - new_patch%ed_laisha_z(:,:,:) = 0._r8 - new_patch%ed_parsun_z(:,:,:) = 0._r8 - new_patch%ed_parsha_z(:,:,:) = 0._r8 - new_patch%fabi = 0._r8 - new_patch%fabd = 0._r8 - new_patch%tr_soil_dir(:) = 1._r8 - new_patch%tr_soil_dif(:) = 1._r8 - new_patch%tr_soil_dir_dif(:) = 0._r8 - new_patch%fabd_sun_z(:,:,:) = 0._r8 - new_patch%fabd_sha_z(:,:,:) = 0._r8 - new_patch%fabi_sun_z(:,:,:) = 0._r8 - new_patch%fabi_sha_z(:,:,:) = 0._r8 - new_patch%frac_burnt = 0._r8 - new_patch%total_tree_area = 0.0_r8 - new_patch%NCL_p = 1 - - new_patch%leaf_litter_in(:) = 0._r8 - new_patch%leaf_litter_out(:) = 0._r8 - - - - end subroutine create_patch - - ! ============================================================================ - subroutine zero_patch(cp_p) - ! - ! !DESCRIPTION: - ! Sets all the variables in the patch to nan or zero - ! (this needs to be two seperate routines, one for nan & one for zero - ! - ! !USES: - use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) - ! - ! !ARGUMENTS: - type(ed_patch_type), intent(inout), target :: cp_p - ! - ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - !--------------------------------------------------------------------- - - currentPatch => cp_p - - currentPatch%tallest => null() - currentPatch%shortest => null() - currentPatch%older => null() - currentPatch%younger => null() - currentPatch%siteptr => null() - - currentPatch%patchno = 999 - currentPatch%clm_pno = 999 - - currentPatch%age = nan - currentPatch%area = nan - currentPatch%canopy_layer_lai(:) = nan - currentPatch%total_canopy_area = nan - currentPatch%canopy_area = nan - currentPatch%bare_frac_area = nan - - currentPatch%tlai_profile(:,:,:) = nan - currentPatch%elai_profile(:,:,:) = 0._r8 - currentPatch%tsai_profile(:,:,:) = nan - currentPatch%esai_profile(:,:,:) = nan - currentPatch%canopy_area_profile(:,:,:) = nan - - currentPatch%fabd_sun_z(:,:,:) = nan - currentPatch%fabd_sha_z(:,:,:) = nan - currentPatch%fabi_sun_z(:,:,:) = nan - currentPatch%fabi_sha_z(:,:,:) = nan - - currentPatch%ed_laisun_z(:,:,:) = nan - currentPatch%ed_laisha_z(:,:,:) = nan - currentPatch%ed_parsun_z(:,:,:) = nan - currentPatch%ed_parsha_z(:,:,:) = nan - currentPatch%psn_z(:,:,:) = 0._r8 - - currentPatch%f_sun(:,:,:) = nan - currentPatch%tr_soil_dir(:) = nan ! fraction of incoming direct radiation that is transmitted to the soil as direct - currentPatch%tr_soil_dif(:) = nan ! fraction of incoming diffuse radiation that is transmitted to the soil as diffuse - currentPatch%tr_soil_dir_dif(:) = nan ! fraction of incoming direct radiation that is transmitted to the soil as diffuse - currentPatch%fabd(:) = nan ! fraction of incoming direct radiation that is absorbed by the canopy - currentPatch%fabi(:) = nan ! fraction of incoming diffuse radiation that is absorbed by the canopy - - currentPatch%present(:,:) = 999 ! is there any of this pft in this layer? - currentPatch%nrad(:,:) = 999 ! number of exposed leaf layers for each canopy layer and pft - currentPatch%ncan(:,:) = 999 ! number of total leaf layers for each canopy layer and pft - currentPatch%lai = nan ! leaf area index of patch - currentPatch%spread(:) = nan ! dynamic ratio of dbh to canopy area. - currentPatch%pft_agb_profile(:,:) = nan - currentPatch%gpp = 0._r8 - currentPatch%npp = 0._r8 - currentPatch%seed_bank(:) = 0._r8 - currentPatch%dseed_dt(:) = 0._r8 - - ! DISTURBANCE - currentPatch%disturbance_rates = 0._r8 - currentPatch%disturbance_rate = 0._r8 - - ! LITTER - currentPatch%cwd_ag(:) = 0.0_r8 ! above ground coarse woody debris gc/m2. - currentPatch%cwd_bg(:) = 0.0_r8 ! below ground coarse woody debris - currentPatch%root_litter(:) = 0.0_r8 - currentPatch%leaf_litter(:) = 0.0_r8 - - currentPatch%leaf_litter_in(:) = 0.0_r8 - currentPatch%leaf_litter_out(:) = 0.0_r8 - - ! FIRE - currentPatch%fuel_eff_moist = 0.0_r8 ! average fuel moisture content of the ground fuel - ! (incl. live grasses. omits 1000hr fuels) - currentPatch%livegrass = 0.0_r8 ! total ag grass biomass in patch. 1=c3 grass, 2=c4 grass. gc/m2 - currentPatch%sum_fuel = 0.0_r8 ! total ground fuel related to ros (omits 1000hr fuels). gc/m2 - currentPatch%fuel_bulkd = 0.0_r8 ! average fuel bulk density of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). kgc/m3 - currentPatch%fuel_sav = 0.0_r8 ! average surface area to volume ratio of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). - currentPatch%fuel_mef = 0.0_r8 ! average moisture of extinction factor of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). - currentPatch%ros_front = 0.0_r8 ! average rate of forward spread of each fire in the patch. m/min. - currentPatch%effect_wspeed = 0.0_r8 ! dailywind modified by fraction of relative grass and tree cover. m/min. - currentPatch%tau_l = 0.0_r8 ! mins p&r(1986) - currentPatch%fuel_frac(:) = 0.0_r8 ! fraction of each litter class in the sum_fuel - !- for purposes of calculating weighted averages. - currentPatch%tfc_ros = 0.0_r8 ! used in fi calc - currentPatch%fi = 0._r8 ! average fire intensity of flaming front during day. - ! backward ros plays no role. kj/m/s or kw/m. - currentPatch%fire = 999 ! sr decide_fire.1=fire hot enough to proceed. 0=stop everything- no fires today - currentPatch%fd = 0.0_r8 ! fire duration (mins) - currentPatch%ros_back = 0.0_r8 ! backward ros (m/min) - currentPatch%ab = 0.0_r8 ! area burnt daily m2 - currentPatch%nf = 0.0_r8 ! number of fires initiated daily - currentPatch%sh = 0.0_r8 ! average scorch height for the patch(m) - currentPatch%frac_burnt = 0.0_r8 ! fraction burnt in each timestep. - currentPatch%burnt_frac_litter(:) = 0.0_r8 - currentPatch%btran_ft(:) = 0.0_r8 - - currentPatch%canopy_layer_lai(:) = 0.0_r8 - currentPatch%seeds_in(:) = 0.0_r8 - currentPatch%seed_decay(:) = 0.0_r8 - currentPatch%seed_germination(:) = 0.0_r8 - - currentPatch%fab(:) = 0.0_r8 - currentPatch%sabs_dir(:) = 0.0_r8 - currentPatch%sabs_dif(:) = 0.0_r8 - - - end subroutine zero_patch - - ! ============================================================================ - subroutine fuse_patches( csite ) - ! - ! !DESCRIPTION: - ! Decide to fuse patches if their cohort structures are similar - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type), intent(inout), target :: csite - ! - ! !LOCAL VARIABLES: - type(ed_site_type) , pointer :: currentSite - type(ed_patch_type), pointer :: currentPatch,tpp,tmpptr - integer :: ft,z !counters for pft and height class - real(r8) :: norm !normalized difference between biomass profiles - real(r8) :: profiletol !tolerance of patch fusion routine. Starts off high and is reduced if there are too many patches. - integer :: maxpatch !maximum number of allowed patches. FIX-RF. These should be namelist variables. - integer :: nopatches !number of patches presently in gridcell - integer :: iterate !switch of patch reduction iteration scheme. 1 to keep going, 0 to stop - integer :: fuse_flag !do patches get fused (1) or not (0). - !--------------------------------------------------------------------- - - !maxpatch = 4 - maxpatch = numPatchesPerCol - - currentSite => csite - - profiletol = 0.6_r8 !start off with a very small profile tol, or a predefined parameter? - - nopatches = 0 - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - nopatches = nopatches +1 - currentPatch => currentPatch%older - enddo - !---------------------------------------------------------------------! - ! We only really care about fusing patches if nopatches > 1 ! - !---------------------------------------------------------------------! - iterate = 1 - - !---------------------------------------------------------------------! - ! Keep doing this until nopatches >= maxpatch ! - !---------------------------------------------------------------------! - - do while(iterate == 1) - !---------------------------------------------------------------------! - ! Calculate the biomass profile of each patch ! - !---------------------------------------------------------------------! - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - call patch_pft_size_profile(currentPatch) - currentPatch => currentPatch%older - enddo - - !---------------------------------------------------------------------! - ! Loop round current & target (currentPatch,tpp) patches to assess combinations ! - !---------------------------------------------------------------------! - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - tpp => currentSite%youngest_patch - do while(associated(tpp)) - - if(.not.associated(currentPatch))then - write(iulog,*) 'ED: issue with currentPatch' - endif - - if(associated(tpp).and.associated(currentPatch))then - fuse_flag = 1 !the default is to fuse the patches - if(currentPatch%patchno /= tpp%patchno) then !these should be the same patch - - !---------------------------------------------------------------------! - ! Calculate the difference criteria for each pft and dbh class ! - !---------------------------------------------------------------------! - do ft = 1,numpft_ed ! loop over pfts - do z = 1,n_dbh_bins ! loop over hgt bins - !is there biomass in this category? - if(currentPatch%pft_agb_profile(ft,z) > 0.0_r8.or.tpp%pft_agb_profile(ft,z) > 0.0_r8)then - norm = abs(currentPatch%pft_agb_profile(ft,z) - tpp%pft_agb_profile(ft,z))/(0.5_r8*& - &(currentPatch%pft_agb_profile(ft,z) + tpp%pft_agb_profile(ft,z))) - !---------------------------------------------------------------------! - ! Look for differences in profile biomass, above the minimum biomass ! - !---------------------------------------------------------------------! - - if(norm > profiletol)then - !looking for differences between profile density. - if(currentPatch%pft_agb_profile(ft,z) > NTOL.or.tpp%pft_agb_profile(ft,z) > NTOL)then - fuse_flag = 0 !do not fuse - keep apart. - endif - endif ! profile tol - endif ! NTOL - enddo !ht bins - enddo ! PFT - - !---------------------------------------------------------------------! - ! Call the patch fusion routine if there is a meaningful difference ! - ! any of the pft x height categories ! - !---------------------------------------------------------------------! - - if(fuse_flag == 1)then - tmpptr => currentPatch%older - call fuse_2_patches(currentPatch, tpp) - call fuse_cohorts(tpp) - call sort_cohorts(tpp) - currentPatch => tmpptr - else - ! write(iulog,*) 'patches not fused' - endif - endif !are both patches associated? - endif !are these different patches? - tpp => tpp%older - enddo !tpp loop - - if(associated(currentPatch))then - currentPatch => currentPatch%older - else - currentPatch => null() - endif !associated currentPatch - - enddo ! currentPatch loop - - !---------------------------------------------------------------------! - ! Is the number of patches larger than the maximum? ! - !---------------------------------------------------------------------! - nopatches = 0 - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - nopatches = nopatches +1 - currentPatch => currentPatch%older - enddo - - if(nopatches > maxpatch)then - iterate = 1 - profiletol = profiletol * 1.1_r8 - - !---------------------------------------------------------------------! - ! Making profile tolerance larger means that more fusion will happen ! - !---------------------------------------------------------------------! - else - iterate = 0 - endif - - enddo !do while nopatches>maxpatch - - end subroutine fuse_patches - - ! ============================================================================ - subroutine fuse_2_patches(dp, rp) - ! - ! !DESCRIPTION: - ! This function fuses the two patches specified in the argument. - ! It fuses the first patch in the argument (the "donor") into the second - ! patch in the argument (the "recipient"), and frees the memory - ! associated with the secnd patch - ! - ! !USES: - ! - ! !ARGUMENTS: - type (ed_patch_type) , intent(inout), pointer :: dp ! Donor Patch - type (ed_patch_type) , intent(inout), pointer :: rp ! Recipient Patch - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type), pointer :: currentCohort ! Current Cohort - type (ed_cohort_type), pointer :: nextc ! Remembers next cohort in list - type (ed_cohort_type), pointer :: storesmallcohort - type (ed_cohort_type), pointer :: storebigcohort - integer :: c,p !counters for pft and litter size class. - integer :: tnull,snull ! are the tallest and shortest cohorts associated? - type(ed_patch_type), pointer :: youngerp ! pointer to the patch younger than donor - type(ed_patch_type), pointer :: olderp ! pointer to the patch older than donor - type(ed_site_type), pointer :: csite ! pointer to the donor patch's site - !--------------------------------------------------------------------- - - !area weighted average of ages & litter & seed bank - rp%age = (dp%age * dp%area + rp%age * rp%area)/(dp%area + rp%area) - - do p = 1,numpft_ed - rp%seed_bank(p) = (rp%seed_bank(p)*rp%area + dp%seed_bank(p)*dp%area)/(rp%area + dp%area) - rp%seeds_in(p) = (rp%seeds_in(p)*rp%area + dp%seeds_in(p)*dp%area)/(rp%area + dp%area) - rp%seed_decay(p) = (rp%seed_decay(p)*rp%area + dp%seed_decay(p)*dp%area)/(rp%area + dp%area) - rp%seed_germination(p) = (rp%seed_germination(p)*rp%area + dp%seed_germination(p)*dp%area)/(rp%area + dp%area) - enddo - - do c = 1,ncwd - rp%cwd_ag(c) = (dp%cwd_ag(c)*dp%area + rp%cwd_ag(c)*rp%area)/(dp%area + rp%area) - rp%cwd_bg(c) = (dp%cwd_bg(c)*dp%area + rp%cwd_bg(c)*rp%area)/(dp%area + rp%area) - enddo - - do p = 1,numpft_ed - rp%leaf_litter(p) = (dp%leaf_litter(p)*dp%area + rp%leaf_litter(p)*rp%area)/(dp%area + rp%area) - rp%root_litter(p) = (dp%root_litter(p)*dp%area + rp%root_litter(p)*rp%area)/(dp%area + rp%area) - enddo - - rp%fuel_eff_moist = (dp%fuel_eff_moist*dp%area + rp%fuel_eff_moist*rp%area)/(dp%area + rp%area) - rp%livegrass = (dp%livegrass*dp%area + rp%livegrass*rp%area)/(dp%area + rp%area) - rp%sum_fuel = (dp%sum_fuel*dp%area + rp%sum_fuel*rp%area)/(dp%area + rp%area) - rp%fuel_bulkd = (dp%fuel_bulkd*dp%area + rp%fuel_bulkd*rp%area)/(dp%area + rp%area) - rp%fuel_sav = (dp%fuel_sav*dp%area + rp%fuel_sav*rp%area)/(dp%area + rp%area) - rp%fuel_mef = (dp%fuel_mef*dp%area + rp%fuel_mef*rp%area)/(dp%area + rp%area) - rp%ros_front = (dp%ros_front*dp%area + rp%ros_front*rp%area)/(dp%area + rp%area) - rp%effect_wspeed = (dp%effect_wspeed*dp%area + rp%effect_wspeed*rp%area)/(dp%area + rp%area) - rp%tau_l = (dp%tau_l*dp%area + rp%tau_l*rp%area)/(dp%area + rp%area) - rp%fuel_frac(:) = (dp%fuel_frac(:)*dp%area + rp%fuel_frac(:)*rp%area)/(dp%area + rp%area) - rp%tfc_ros = (dp%tfc_ros*dp%area + rp%tfc_ros*rp%area)/(dp%area + rp%area) - rp%fi = (dp%fi*dp%area + rp%fi*rp%area)/(dp%area + rp%area) - rp%fd = (dp%fd*dp%area + rp%fd*rp%area)/(dp%area + rp%area) - rp%ros_back = (dp%ros_back*dp%area + rp%ros_back*rp%area)/(dp%area + rp%area) - rp%ab = (dp%ab*dp%area + rp%ab*rp%area)/(dp%area + rp%area) - rp%nf = (dp%nf*dp%area + rp%nf*rp%area)/(dp%area + rp%area) - rp%sh = (dp%sh*dp%area + rp%sh*rp%area)/(dp%area + rp%area) - rp%frac_burnt = (dp%frac_burnt*dp%area + rp%frac_burnt*rp%area)/(dp%area + rp%area) - rp%burnt_frac_litter(:) = (dp%burnt_frac_litter(:)*dp%area + rp%burnt_frac_litter(:)*rp%area)/(dp%area + rp%area) - rp%btran_ft(:) = (dp%btran_ft(:)*dp%area + rp%btran_ft(:)*rp%area)/(dp%area + rp%area) - rp%dleaf_litter_dt(:) = (dp%dleaf_litter_dt(:)*dp%area + rp%dleaf_litter_dt(:)*rp%area)/(dp%area+rp%area) - rp%leaf_litter_in(:) = (dp%leaf_litter_in(:)*dp%area + rp%leaf_litter_in(:)*rp%area)/(dp%area+rp%area) - rp%leaf_litter_out(:) = (dp%leaf_litter_out(:)*dp%area + rp%leaf_litter_out(:)*rp%area)/(dp%area+rp%area) - - - rp%area = rp%area + dp%area !THIS MUST COME AT THE END! - - !insert donor cohorts into recipient patch - if(associated(dp%shortest))then - - currentCohort => dp%shortest - if(associated(currentCohort)) then - nextc => currentCohort%taller - endif - - do while(associated(dp%shortest)) - - storebigcohort => rp%tallest - storesmallcohort => rp%shortest - - if(associated(rp%tallest))then - tnull = 0 - else - tnull = 1 - rp%tallest => currentCohort - endif - - if(associated(rp%shortest))then - snull = 0 - else - snull = 1 - rp%shortest => currentCohort - endif - - call insert_cohort(currentCohort, rp%tallest, rp%shortest, tnull, snull, storebigcohort, storesmallcohort) - - rp%tallest => storebigcohort - rp%shortest => storesmallcohort - - currentCohort%patchptr => rp - currentCohort => nextc - - dp%shortest => currentCohort - - if(associated(currentCohort)) then - nextc => currentCohort%taller - endif - - enddo !cohort - endif !are there any cohorts? - - call patch_pft_size_profile(rp) ! Recalculate the patch size profile for the resulting patch - - ! Define some aliases for the donor patches younger and older neighbors - ! which may or may not exist. After we set them, we will remove the donor - ! And then we will go about re-setting the map. - csite => dp%siteptr - if(associated(dp%older))then - olderp => dp%older - else - olderp => null() - end if - if(associated(dp%younger))then - youngerp => dp%younger - else - youngerp => null() - end if - - ! We have no need for the dp pointer anymore, we have passed on it's legacy - call dealloc_patch(dp) - deallocate(dp) - - - if(associated(youngerp))then - ! Update the younger patch's new older patch (because it isn't dp anymore) - youngerp%older => olderp - else - ! There was no younger patch than dp, so the head of the young order needs - ! to be set, and it is set as the patch older than dp. That patch - ! already knows it's older patch (so no need to set or change it) - csite%youngest_patch => olderp - end if - - - if(associated(olderp))then - ! Update the older patch's new younger patch (becuase it isn't dp anymore) - olderp%younger => youngerp - else - ! There was no patch older than dp, so the head of the old patch order needs - ! to be set, and it is set as the patch younger than dp. That patch already - ! knows it's younger patch, no need to set - csite%oldest_patch => youngerp - end if - - - end subroutine fuse_2_patches - - ! ============================================================================ - subroutine terminate_patches(cs_pnt) - ! - ! !DESCRIPTION: - ! Terminate Patches if they are too small - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type), target, intent(in) :: cs_pnt - ! - ! !LOCAL VARIABLES: - type(ed_site_type), pointer :: currentSite - type(ed_patch_type), pointer :: currentPatch, tmpptr - real(r8) areatot ! variable for checking whether the total patch area is wrong. - !--------------------------------------------------------------------- - - currentSite => cs_pnt - - currentPatch => currentSite%oldest_patch - - !fuse patches if one of them is very small.... - currentPatch => currentSite%youngest_patch - do while(associated(currentPatch)) - if(currentPatch%area <= min_patch_area)then - if ( currentPatch%patchno /= currentSite%youngest_patch%patchno) then - ! Do not force the fusion of the youngest patch to its neighbour. - ! This is only really meant for very old patches. - if(associated(currentPatch%older) )then - write(iulog,*) 'fusing to older patch because this one is too small',currentPatch%area, currentPatch%lai, & - currentPatch%older%area,currentPatch%older%lai,currentPatch%seed_bank(1) - call fuse_2_patches(currentPatch%older, currentPatch) - write(iulog,*) 'after fusion to older patch',currentPatch%area,currentPatch%seed_bank(1) - else - write(iulog,*) 'fusing to younger patch because oldest one is too small',currentPatch%area, currentPatch%lai - tmpptr => currentPatch%younger - call fuse_2_patches(currentPatch, currentPatch%younger) - write(iulog,*) 'after fusion to younger patch' - currentPatch => tmpptr - endif - endif - endif - - currentPatch => currentPatch%older - - enddo - - !check area is not exceeded - areatot = 0._r8 - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - areatot = areatot + currentPatch%area - currentPatch => currentPatch%younger - if((areatot-area) > 0.0000001_r8)then - write(iulog,*) 'ED: areatot too large. end terminate', areatot - endif - enddo - - end subroutine terminate_patches - - ! ===================================================================================== - - subroutine dealloc_patch(cpatch) - - ! This Subroutine is intended to de-allocate the allocatable memory that is pointed - ! to via the patch structure. This subroutine DOES NOT deallocate the patch - ! structure itself. - - type(ed_patch_type), target :: cpatch - type(ed_cohort_type), pointer :: ccohort ! current - type(ed_cohort_type), pointer :: ncohort ! next - - ! First Deallocate the cohort space - ! ----------------------------------------------------------------------------------- - ccohort => cpatch%shortest - do while(associated(ccohort)) - - ncohort => ccohort%taller - deallocate(ccohort) - ccohort => ncohort - - end do - - ! Secondly, and lastly, deallocate the allocatable vector spaces in the patch - if(allocated(cpatch%tr_soil_dir))then - deallocate(cpatch%tr_soil_dir) - deallocate(cpatch%tr_soil_dif) - deallocate(cpatch%tr_soil_dir_dif) - deallocate(cpatch%fab) - deallocate(cpatch%fabd) - deallocate(cpatch%fabi) - deallocate(cpatch%sabs_dir) - deallocate(cpatch%sabs_dif) - deallocate(cpatch%rootfr_ft) - deallocate(cpatch%rootr_ft) - end if - - return - end subroutine dealloc_patch - - ! ============================================================================ - subroutine patch_pft_size_profile(cp_pnt) - ! - ! !DESCRIPTION: - ! Binned patch size profiles generated for patch fusion routine - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_patch_type), target, intent(inout) :: cp_pnt - ! - ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - real(r8) :: mind(N_DBH_BINS) ! Bottom of DBH bin - real(r8) :: maxd(N_DBH_BINS) ! Top of DBH bin - real(r8) :: delta_dbh ! Size of DBH bin - integer :: p ! Counter for PFT - integer :: j ! Counter for DBH bins - !--------------------------------------------------------------------- - - currentPatch => cp_pnt - - delta_dbh = (DBHMAX/N_DBH_BINS) - - do p = 1,numpft_ed - do j = 1,N_DBH_BINS - currentPatch%pft_agb_profile(p,j) = 0.0_r8 - enddo - enddo - - do j = 1,N_DBH_BINS - if (j == 1) then - mind(j) = 0.0_r8 - maxd(j) = delta_dbh - else - mind(j) = (j-1) * delta_dbh - maxd(j) = (j)*delta_dbh - endif - enddo - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - do j = 1,N_DBH_BINS - if((currentCohort%dbh > mind(j)) .AND. (currentCohort%dbh <= maxd(j)))then - - currentPatch%pft_agb_profile(currentCohort%pft,j) = currentPatch%pft_agb_profile(currentCohort%pft,j) + & - currentCohort%bdead*currentCohort%n/currentPatch%area - - endif - enddo ! dbh bins - - ! Deal with largest dbh bin - j = N_DBH_BINS-1 - if(currentCohort%dbh > j*delta_dbh)then - - currentPatch%pft_agb_profile(currentCohort%pft,j) = currentPatch%pft_agb_profile(currentCohort%pft,j) + & - currentCohort%bdead*currentCohort%n/currentPatch%area - - endif ! - - currentCohort => currentCohort%taller - - enddo !currentCohort - - end subroutine patch_pft_size_profile - - ! ============================================================================ - function countPatches( bounds, nsites, sites ) result ( totNumPatches ) - ! - ! !DESCRIPTION: - ! Loop over all Patches to count how many there are - ! - ! !USES: - use decompMod , only : bounds_type - use abortutils , only : endrun - use EDTypesMod , only : ed_site_type - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds - integer, intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - ! - ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch - integer :: totNumPatches ! total number of patches. - integer :: s - !--------------------------------------------------------------------- - - totNumPatches = 0 - - do s = 1,nsites - currentPatch => sites(s)%oldest_patch - do while(associated(currentPatch)) - totNumPatches = totNumPatches + 1 - currentPatch => currentPatch%younger - enddo - enddo - - end function countPatches - -end module EDPatchDynamicsMod diff --git a/src/ED/biogeochem/EDPhysiologyMod.F90 b/src/ED/biogeochem/EDPhysiologyMod.F90 deleted file mode 100755 index 4bdbef36cd..0000000000 --- a/src/ED/biogeochem/EDPhysiologyMod.F90 +++ /dev/null @@ -1,1651 +0,0 @@ -module EDPhysiologyMod - -#include "shr_assert.h" - - ! ============================================================================ - ! Miscellaneous physiology routines from ED. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : iulog - use spmdMod , only : masterproc - use TemperatureType , only : temperature_type - use SoilStateType , only : soilstate_type - use WaterstateType , only : waterstate_type - use pftconMod , only : pftcon - use EDEcophysContype , only : EDecophyscon - use EDCohortDynamicsMod , only : allocate_live_biomass, zero_cohort - use EDCohortDynamicsMod , only : create_cohort, fuse_cohorts, sort_cohorts - use EDTypesMod , only : dg_sf, dinc_ed, external_recruitment - use EDTypesMod , only : ncwd, cp_nlevcan, numpft_ed, senes - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type - - implicit none - private - - public :: canopy_derivs - public :: non_canopy_derivs - public :: trim_canopy - public :: phenology - public :: phenology_leafonoff - public :: Growth_Derivatives - public :: recruitment - public :: cwd_input - public :: cwd_out - public :: fragmentation_scaler - public :: seeds_in - public :: seed_decay - public :: seed_germination - public :: flux_into_litter_pools - - logical, parameter :: DEBUG = .false. ! local debug flag - - ! ============================================================================ - -contains - - ! ============================================================================ - subroutine canopy_derivs( currentPatch ) - ! - ! !DESCRIPTION: - ! spawn new cohorts of juveniles of each PFT - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type) , intent(inout), target :: currentPatch - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer ::currentCohort - !---------------------------------------------------------------------- - - ! call plant growth functions - - currentCohort => currentPatch%shortest - - do while(associated(currentCohort)) - call Growth_Derivatives(currentCohort) - currentCohort => currentCohort%taller - enddo - - end subroutine canopy_derivs - - ! ============================================================================ - subroutine non_canopy_derivs( currentPatch, temperature_inst ) - ! - ! !DESCRIPTION: - ! Returns time differentials of the state vector - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type) , intent(inout) :: currentPatch - type(temperature_type) , intent(in) :: temperature_inst - ! - ! !LOCAL VARIABLES: - integer c,p - !---------------------------------------------------------------------- - - currentPatch%leaf_litter_in(:) = 0.0_r8 - currentPatch%root_litter_in(:) = 0.0_r8 - currentPatch%dleaf_litter_dt(:) = 0.0_r8 - currentPatch%droot_litter_dt(:) = 0.0_r8 - currentPatch%leaf_litter_out(:) = 0.0_r8 - currentPatch%root_litter_out(:) = 0.0_r8 - currentPatch%cwd_AG_in(:) = 0.0_r8 - currentPatch%cwd_BG_in(:) = 0.0_r8 - currentPatch%cwd_AG_out(:) = 0.0_r8 - currentPatch%cwd_BG_out(:) = 0.0_r8 - currentPatch%seeds_in(:) = 0.0_r8 - currentPatch%seed_decay(:) = 0.0_r8 - currentPatch%seed_germination(:) = 0.0_r8 - - ! update seed fluxes - call seeds_in(currentPatch) - call seed_decay(currentPatch) - call seed_germination(currentPatch) - - ! update fragmenting pool fluxes - call cwd_input(currentPatch) - call cwd_out( currentPatch, temperature_inst) - - do p = 1,numpft_ed - currentPatch%dseed_dt(p) = currentPatch%seeds_in(p) - currentPatch%seed_decay(p) - currentPatch%seed_germination(p) - enddo - - do c = 1,ncwd - currentPatch%dcwd_AG_dt(c) = currentPatch%cwd_AG_in(c) - currentPatch%cwd_AG_out(c) - currentPatch%dcwd_BG_dt(c) = currentPatch%cwd_BG_in(c) - currentPatch%cwd_BG_out(c) - enddo - - do p = 1,numpft_ed - currentPatch%dleaf_litter_dt(p) = currentPatch%leaf_litter_in(p) - currentPatch%leaf_litter_out(p) - currentPatch%droot_litter_dt(p) = currentPatch%root_litter_in(p) - currentPatch%root_litter_out(p) - enddo - - ! currentPatch%leaf_litter_in(:) = 0.0_r8 - ! currentPatch%root_litter_in(:) = 0.0_r8 - ! currentPatch%leaf_litter_out(:) = 0.0_r8 - ! currentPatch%root_litter_out(:) = 0.0_r8 - ! currentPatch%CWD_AG_in(:) = 0.0_r8 - ! currentPatch%cwd_bg_in(:) = 0.0_r8 - ! currentPatch%CWD_AG_out(:) = 0.0_r8 - ! currentPatch%cwd_bg_out(:) = 0.0_r8 - - end subroutine non_canopy_derivs - - ! ============================================================================ - subroutine trim_canopy( currentSite ) - ! - ! !DESCRIPTION: - ! Canopy trimming / leaf optimisation. Removes leaves in negative annual carbon balance. - ! - ! !USES: - ! - use EDParamsMod, only : ED_val_grperc - use EDGrowthFunctionsMod, only : tree_lai - ! - ! !ARGUMENTS - type (ed_site_type),intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type (ed_cohort_type) , pointer :: currentCohort - type (ed_patch_type) , pointer :: currentPatch - - real(r8) :: inc ! rate at which canopy acclimates to uptake - real(r8) :: trim_limit ! this is the limit of the canopy trimming routine, so that trees - ! can't just lose all their leaves and have no reproductive costs. - integer :: z ! leaf layer - integer :: trimmed ! was this layer trimmed in this year? If not expand the canopy. - - trim_limit = 0.3_r8 ! Arbitrary limit to reductions in leaf area with stress. Without this nothing ever dies. - inc = 0.03_r8 ! Arbitrary incremental change in trimming function. Controls - ! rate at which leaves are optimised to their environment. - !---------------------------------------------------------------------- - - currentPatch => currentSite%youngest_patch - - do while(associated(currentPatch)) - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - trimmed = 0 - currentCohort%treelai = tree_lai(currentCohort) - currentCohort%nv = ceiling((currentCohort%treelai+currentCohort%treesai)/dinc_ed) - if (currentCohort%nv > cp_nlevcan)then - write(iulog,*) 'nv > cp_nlevcan',currentCohort%nv,currentCohort%treelai,currentCohort%treesai, & - currentCohort%c_area,currentCohort%n,currentCohort%bl - endif - - !Leaf cost vs netuptake for each leaf layer. - do z = 1,cp_nlevcan - if (currentCohort%year_net_uptake(z) /= 999._r8)then !there was activity this year in this leaf layer. - !Leaf Cost kgC/m2/year-1 - !decidous costs. - if (pftcon%season_decid(currentCohort%pft) == 1.or.pftcon%stress_decid(currentCohort%pft) == 1)then - currentCohort%leaf_cost = 1._r8/(pftcon%slatop(currentCohort%pft)*1000.0_r8) - currentCohort%leaf_cost = currentCohort%leaf_cost + 1.0_r8/(pftcon%slatop(currentCohort%pft)*1000.0_r8) * & - pftcon%froot_leaf(currentCohort%pft) / EDecophyscon%root_long(currentCohort%pft) - currentCohort%leaf_cost = currentCohort%leaf_cost * (ED_val_grperc(currentCohort%pft) + 1._r8) - else !evergreen costs - currentCohort%leaf_cost = 1.0_r8/(pftcon%slatop(currentCohort%pft)* & - pftcon%leaf_long(currentCohort%pft)*1000.0_r8) !convert from sla in m2g-1 to m2kg-1 - currentCohort%leaf_cost = currentCohort%leaf_cost + 1.0_r8/(pftcon%slatop(currentCohort%pft)*1000.0_r8) * & - pftcon%froot_leaf(currentCohort%pft) / EDecophyscon%root_long(currentCohort%pft) - currentCohort%leaf_cost = currentCohort%leaf_cost * (ED_val_grperc(currentCohort%pft) + 1._r8) - endif - if (currentCohort%year_net_uptake(z) < currentCohort%leaf_cost)then - if (currentCohort%canopy_trim > trim_limit)then - - if ( DEBUG ) then - write(iulog,*) 'trimming leaves',currentCohort%canopy_trim,currentCohort%leaf_cost - endif - - ! keep trimming until none of the canopy is in negative carbon balance. - if (currentCohort%hite > EDecophyscon%hgt_min(currentCohort%pft))then - currentCohort%canopy_trim = currentCohort%canopy_trim - inc - if (pftcon%evergreen(currentCohort%pft) /= 1)then - currentCohort%laimemory = currentCohort%laimemory*(1.0_r8 - inc) - endif - trimmed = 1 - endif - endif - endif - endif !leaf activity? - enddo !z - if (currentCohort%NV.gt.2)then - ! leaf_cost may be uninitialized, removing its diagnostic from the log - ! to allow checking with fpe_traps (RGK) - write(iulog,*) 'nv>4',currentCohort%year_net_uptake(1:6),currentCohort%canopy_trim - endif - - currentCohort%year_net_uptake(:) = 999.0_r8 - if (trimmed == 0.and.currentCohort%canopy_trim < 1.0_r8)then - currentCohort%canopy_trim = currentCohort%canopy_trim + inc - endif - - if ( DEBUG ) then - write(iulog,*) 'trimming',currentCohort%canopy_trim - endif - - ! currentCohort%canopy_trim = 1.0_r8 !FIX(RF,032414) this turns off ctrim for now. - currentCohort => currentCohort%shorter - enddo - currentPatch => currentPatch%older - enddo - - end subroutine trim_canopy - - ! ============================================================================ - subroutine phenology( currentSite, temperature_inst, waterstate_inst) - ! - ! !DESCRIPTION: - ! Phenology. - ! - ! !USES: - use clm_varcon, only : tfrz - use clm_time_manager, only : get_curr_date - use clm_time_manager, only : get_ref_date, timemgr_datediff - use EDTypesMod, only : udata - use PatchType , only : patch - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(inout), target :: currentSite - type(temperature_type) , intent(in) :: temperature_inst - type(waterstate_type) , intent(in) :: waterstate_inst - ! - ! !LOCAL VARIABLES: - real(r8), pointer :: t_veg24(:) - integer :: t ! day of year - integer :: ncolddays ! no days underneath the threshold for leaf drop - integer :: ncolddayslim ! critical no days underneath the threshold for leaf drop - integer :: i - integer :: timesincedleafon,timesincedleafoff,timesinceleafon,timesinceleafoff - integer :: refdate - integer :: curdate - - integer :: yr ! year (0, ...) - integer :: mon ! month (1, ..., 12) - integer :: day ! day of month (1, ..., 31) - integer :: sec ! seconds of the day - integer :: patchi ! the first CLM/ALM patch index of the associated column - integer :: coli ! the CLM/ALM column index of the associated site - - real(r8) :: gdd_threshold - real(r8) :: a,b,c ! params of leaf-pn model from botta et al. 2000. - real(r8) :: cold_t ! threshold below which cold days are counted - real(r8) :: coldday ! definition of a 'chilling day' for botta model - integer :: ncdstart ! beginning of counting period for chilling degree days. - integer :: gddstart ! beginning of counting period for growing degree days. - real(r8) :: drought_threshold - real(r8) :: off_time ! minimum number of days between leaf off and leaf on for drought phenology - real(r8) :: temp_in_C ! daily averaged temperature in celcius - real(r8) :: mindayson - real(r8) :: modelday - - !------------------------------------------------------------------------ - - ! INTERF-TODO: THIS IS A BAND-AID, AS I WAS HOPING TO REMOVE CLM_PNO - ! ALREADY REMOVED currentSite%clmcolumn, hence the need for these - - patchi = currentSite%oldest_patch%clm_pno-1 - coli = patch%column(patchi) - - t_veg24 => temperature_inst%t_veg24_patch ! Input: [real(r8) (:)] avg pft vegetation temperature for last 24 hrs - - call get_curr_date(yr, mon, day, sec) - curdate = yr*10000 + mon*100 + day - - call get_ref_date(yr, mon, day, sec) - refdate = yr*10000 + mon*100 + day - - call timemgr_datediff(refdate, 0, curdate, sec, modelday) - if ( masterproc ) write(iulog,*) 'modelday',modelday - - ! Parameter of drought decid leaf loss in mm in top layer...FIX(RF,032414) - ! - this is arbitrary and poorly understood. Needs work. ED_ - drought_threshold = 0.15 - off_time = 100.0_r8 - - !Parameters of Botta et al. 2000 GCB,6 709-725 - a = -68.0_r8 - b = 638.0_r8 - c = -0.001_r8 - coldday = 5.0_r8 !ed_ph_chiltemp - - mindayson = 30 - - !Parameters from SDGVM model of senesence - ncolddayslim = 5 - cold_t = 7.5_r8 ! ed_ph_coldtemp - - t = udata%time_period - temp_in_C = t_veg24(patchi) - tfrz - - !-----------------Cold Phenology--------------------! - - !Zero growing degree and chilling day counters - if (currentSite%lat > 0)then - ncdstart = 270 !Northern Hemisphere begining November - gddstart = 1 !Northern Hemisphere begining January - else - ncdstart = 120 !Southern Hemisphere beginning May - gddstart = 181 !Northern Hemisphere begining July - endif - - ! FIX(SPM,032414) - this will only work for the first year, no? - if (t == ncdstart)then - currentSite%ncd = 0._r8 - endif - - !Accumulate growing/chilling days after start of counting period - if (temp_in_C < coldday)then - currentSite%ncd = currentSite%ncd + 1.0_r8 - endif - - gdd_threshold = a + b*exp(c*currentSite%ncd) !GDD accumulation function, which also depends on chilling days. - - !Accumulate temperature of last 10 days. - currentSite%last_n_days(2:senes) = currentSite%last_n_days(1:senes-1) - currentSite%last_n_days(1) = temp_in_C - !count number of days for leaves off - ncolddays = 0 - do i = 1,senes - if (currentSite%last_n_days(i) < cold_t)then - ncolddays = ncolddays + 1 - endif - enddo - - ! Here is where we do the GDD accumulation calculation - ! - ! reset GDD on set dates - if (t == gddstart)then - currentSite%ED_GDD_site = 0._r8 - endif - ! - ! accumulate the GDD using daily mean temperatures - if (t_veg24(patchi) .gt. tfrz) then - currentSite%ED_GDD_site = currentSite%ED_GDD_site + t_veg24(currentSite%oldest_patch%clm_pno-1) - tfrz - endif - - - timesinceleafoff = modelday - currentSite%leafoffdate - !LEAF ON: COLD DECIDUOUS. Needs to - !1) have exceeded the growing degree day threshold - !2) The leaves should not be on already - !3) There should have been at least on chilling day in the counting period. - if (currentSite%ED_GDD_site > gdd_threshold)then - if (currentSite%status == 1) then - if (currentSite%ncd >= 1) then - currentSite%status = 2 !alter status of site to 'leaves on' - ! NOTE(bja, 2015-01) should leafondate = modelday to be consistent with leaf off? - currentSite%leafondate = t !record leaf on date - if ( DEBUG ) write(iulog,*) 'leaves on' - endif !ncd - endif !status - endif !GDD - - timesinceleafon = modelday - currentSite%leafondate - - - !LEAF OFF: COLD THRESHOLD - !Needs to: - !1) have exceeded the number of cold days threshold - !2) have exceeded the minimum leafon time. - !3) The leaves should not be off already - !4) The day of the year should be larger than the counting period. (not sure if we need this/if it will break the restarting) - - if (ncolddays > ncolddayslim)then - if (timesinceleafon > mindayson)then - if (currentSite%status == 2)then - currentSite%status = 1 !alter status of site to 'leaves on' - currentSite%leafoffdate = modelday !record leaf off date - if ( DEBUG ) write(iulog,*) 'leaves off' - endif - endif - endif - - !LEAF OFF: COLD LIFESPAN THRESHOLD - if(timesinceleafoff > 400)then !remove leaves after a whole year when there is no 'off' period. - if(currentSite%status == 2)then - currentSite%status = 1 !alter status of site to 'leaves on' - currentSite%leafoffdate = modelday !record leaf off date - if ( DEBUG ) write(iulog,*) 'leaves off' - endif - endif - - !-----------------Drought Phenology--------------------! - ! Principles of drought-deciduos phenology model... - ! The 'dstatus' flag is 2 when leaves are on, and 1 when leaves area off. - ! The following sets those site-level flags, which are acted on in phenology_deciduos. - ! A* The leaves live for either the length of time the soil moisture is over the threshold - ! or the lifetime of the leaves, whichever is shorter. - ! B*: If the soil is only wet for a very short time, then the leaves stay on for 100 days - ! C*: The leaves are only permitted to come ON for a 60 day window around when they last came on, - ! to prevent 'flickering' on in response to wet season storms - ! D*: We don't allow anything to happen in the first ten days to allow the water memory window to come into equlibirum. - ! E*: If the soil is always wet, the leaves come on at the beginning of the window, and then last for their lifespan. - ! ISSUES - ! 1. It's not clear what water content we should track. Here we are tracking the top layer, - ! but we probably should track something like BTRAN, - ! but BTRAN is defined for each PFT, and there could potentially be more than one stress-dec PFT.... ? - ! 2. In the beginning, the window is set at an arbitrary time of the year, so the leaves might come on - ! in the dry season, using up stored reserves - ! for the stress-dec plants, and potentially killing them. To get around this, we need to read in the - ! 'leaf on' date from some kind of start-up file - ! but we would need that to happen for every resolution, etc. - ! 3. Will this methodology properly kill off the stress-dec trees where there is no water stress? - ! What about where the wet period coincides with the - ! warm period? We would just get them overlapping with the cold-dec trees, even though that isn't appropriate.... - ! Why don't the drought deciduous trees grow - ! in the North? Is cold decidousness maybe even the same as drought deciduosness there (and so does this - ! distinction actually matter??).... - - !Accumulate surface water memory of last 10 days. - currentSite%water_memory(1) = waterstate_inst%h2osoi_vol_col(coli,1) - do i = 1,9 !shift memory along one - currentSite%water_memory(11-i) = currentSite%water_memory(10-i) - enddo - - !In drought phenology, we often need to force the leaves to stay on or off as moisture fluctuates... - timesincedleafoff = 0 - if (currentSite%dstatus == 1)then !the leaves are off. How long have they been off? - !leaves have come on, but last year, so at a later date than now. - if (currentSite%dleafoffdate > 0.and.currentSite%dleafoffdate > t)then - timesincedleafoff = t + (360 - currentSite%dleafoffdate) - else - timesincedleafoff = t - currentSite%dleafoffdate - endif - endif - - timesincedleafon = 0 - !the leaves are on. How long have they been on? - if (currentSite%dstatus == 2)then - !leaves have come on, but last year, so at a later date than now. - if (currentSite%dleafondate > 0.and.currentSite%dleafondate > t)then - timesincedleafon = t + (360 - currentSite%dleafondate) - else - timesincedleafon = t - currentSite%dleafondate - endif - endif - - !LEAF ON: DROUGHT DECIDUOUS WETNESS - !Here, we used a window of oppurtunity to determine if we are close to the time when then leaves came on last year - if ((t >= currentSite%dleafondate - 30.and.t <= currentSite%dleafondate + 30).or.(t > 360 - 15.and. & - currentSite%dleafondate < 15))then ! are we in the window? - if (sum(currentSite%water_memory(1:10)/10._r8) >= drought_threshold.and.currentSite%dstatus == 1.and.t >= 10)then - ! leave some minimum time between leaf off and leaf on to prevent 'flickering'. - if (timesincedleafoff > off_time)then - currentSite%dstatus = 2 !alter status of site to 'leaves on' - currentSite%dleafondate = t !record leaf on date - endif - endif - endif - - !we still haven't done budburst by end of window - if (t == currentSite%dleafondate+30.and.currentSite%dstatus == 1)then - currentSite%dstatus = 2 ! force budburst! - currentSite%dleafondate = t ! record leaf on date - endif - - !LEAF OFF: DROUGHT DECIDUOUS LIFESPAN - if the leaf gets to the end of its useful life. A*, E* - if (currentSite%dstatus == 2.and.t >= 10)then !D* - !Are the leaves at the end of their lives? !FIX(RF,0401014)- this is hardwiring.... - if (timesincedleafon > 365.0*pftcon%leaf_long(7))then - currentSite%dstatus = 1 !alter status of site to 'leaves on' - currentSite%dleafoffdate = t !record leaf on date - endif - endif - - !LEAF OFF: DROUGHT DECIDUOUS DRYNESS - if the soil gets too dry, and the leaves have already been on a while... - if (currentSite%dstatus == 2.and.t >= 10)then !D* - if (sum(currentSite%water_memory(1:10)/10._r8) <= drought_threshold)then - if (timesincedleafon > 100)then !B* Have the leaves been on for some reasonable length of time? To prevent flickering. - currentSite%dstatus = 1 !alter status of site to 'leaves on' - currentSite%dleafoffdate = t !record leaf on date - endif - endif - endif - - call phenology_leafonoff(currentSite) - - end subroutine phenology - - ! ============================================================================ - subroutine phenology_leafonoff(currentSite) - ! - ! !DESCRIPTION: - ! Controls the leaf on and off economics - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type), intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - real(r8) :: store_output ! the amount of the store to put into leaves - is a barrier against negative storage and C starvation. - - !------------------------------------------------------------------------ - - currentPatch => CurrentSite%oldest_patch - - store_output = 0.5_r8 - - do while(associated(currentPatch)) - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - - !COLD LEAF ON - if (pftcon%season_decid(currentCohort%pft) == 1)then - if (currentSite%status == 2)then !we have just moved to leaves being on . - if (currentCohort%status_coh == 1)then !Are the leaves currently off? - currentCohort%status_coh = 2 !Leaves are on, so change status to stop flow of carbon out of bstore. - if (currentCohort%laimemory <= currentCohort%bstore)then - currentCohort%bl = currentCohort%laimemory !extract stored carbon to make new leaves. - else - ! we can only put on as much carbon as there is in the store... - ! nb. Putting all of bstore into leaves is C-starvation suicidal. - ! The tendency for this could be parameterized - currentCohort%bl = currentCohort%bstore * store_output - endif - - ! Add deployed carbon to alive biomass pool - currentCohort%balive = currentCohort%balive + currentCohort%bl - - if ( DEBUG ) write(iulog,*) 'EDPhysMod 1 ',currentCohort%bstore - - currentCohort%bstore = currentCohort%bstore - currentCohort%bl ! Drain store - - if ( DEBUG ) write(iulog,*) 'EDPhysMod 2 ',currentCohort%bstore - - currentCohort%laimemory = 0.0_r8 - - endif !pft phenology - endif ! growing season - - !COLD LEAF OFF - currentCohort%leaf_litter = 0.0_r8 !zero leaf litter for today. - if (currentSite%status == 1)then !past leaf drop day? Leaves still on tree? - if (currentCohort%status_coh == 2)then ! leaves have not dropped - currentCohort%status_coh = 1 - !remember what the lai was this year to put the same amount back on in the spring... - currentCohort%laimemory = currentCohort%bl - ! decrement balive for leaf litterfall - currentCohort%balive = currentCohort%balive - currentCohort%bl - ! add lost carbon to litter - currentCohort%leaf_litter = currentCohort%bl - currentCohort%bl = 0.0_r8 - endif !leaf status - endif !currentSite status - endif !season_decid - - !DROUGHT LEAF ON - if (pftcon%stress_decid(currentCohort%pft) == 1)then - if (currentSite%dstatus == 2)then !we have just moved to leaves being on . - if (currentCohort%status_coh == 1)then !is it the leaf-on day? Are the leaves currently off? - currentCohort%status_coh = 2 !Leaves are on, so change status to stop flow of carbon out of bstore. - if (currentCohort%laimemory <= currentCohort%bstore)then - currentCohort%bl = currentCohort%laimemory !extract stored carbon to make new leaves. - else - currentCohort%bl = currentCohort%bstore * store_output !we can only put on as much carbon as there is in the store... - endif - currentCohort%balive = currentCohort%balive + currentCohort%bl - - if ( DEBUG ) write(iulog,*) 'EDPhysMod 3 ',currentCohort%bstore - - currentCohort%bstore = currentCohort%bstore - currentCohort%bl ! empty store - - if ( DEBUG ) write(iulog,*) 'EDPhysMod 4 ',currentCohort%bstore - - currentCohort%laimemory = 0.0_r8 - - endif !currentCohort status again? - endif !currentSite status - - !DROUGHT LEAF OFF - if (currentSite%dstatus == 1)then - if (currentCohort%status_coh == 2)then ! leaves have not dropped - currentCohort%status_coh = 1 - currentCohort%laimemory = currentCohort%bl - ! decrement balive for leaf litterfall - currentCohort%balive = currentCohort%balive - currentCohort%bl - ! add retranslocated carbon (very small) to store. - currentCohort%bstore = currentCohort%bstore - ! add falling leaves to litter pools . convert to KgC/m2 - currentCohort%leaf_litter = currentCohort%bl - currentCohort%bl = 0.0_r8 - endif - endif !status - endif !drought dec. - currentCohort => currentCohort%shorter - enddo !currentCohort - - currentPatch => currentPatch%younger - - enddo !currentPatch - - end subroutine phenology_leafonoff - - - ! ============================================================================ - subroutine seeds_in( cp_pnt ) - ! - ! !DESCRIPTION: - ! Flux from plants into seed pool. - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type), intent(inout), target :: cp_pnt ! seeds go to these patches. - ! - ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - type(ed_site_type), pointer :: currentSite - type(ed_cohort_type), pointer :: currentCohort - integer :: p - !---------------------------------------------------------------------- - - currentPatch => cp_pnt - currentSite => currentPatch%siteptr - - currentPatch%seeds_in(:) = 0.0_r8 - currentPatch%seed_rain_flux(:) = 0.0_r8 - - currentCohort => currentPatch%tallest - do while (associated(currentCohort)) - p = currentCohort%pft - currentPatch%seeds_in(p) = currentPatch%seeds_in(p) + currentCohort%seed_prod * currentCohort%n/currentPatch%area - currentCohort => currentCohort%shorter - enddo !cohort loop - - currentPatch => currentSite%oldest_patch - - do while(associated(currentPatch)) - if (EXTERNAL_RECRUITMENT == 1) then !external seed rain - needed to prevent extinction - do p = 1,numpft_ed - currentPatch%seeds_in(p) = currentPatch%seeds_in(p) + EDecophyscon%seed_rain(p) !KgC/m2/year - currentPatch%seed_rain_flux(p) = currentPatch%seed_rain_flux(p) + EDecophyscon%seed_rain(p) !KgC/m2/year - enddo - endif - currentPatch => currentPatch%younger - enddo - - end subroutine seeds_in - - ! ============================================================================ - subroutine seed_decay( currentPatch ) - ! - ! !DESCRIPTION: - ! Flux from seed pool into leaf litter pool - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type),intent(inout) :: currentPatch ! seeds go to these patches. - ! - ! !LOCAL VARIABLES: - integer :: p - real(r8) :: seed_turnover !complete seed turnover rate in yr-1. - !---------------------------------------------------------------------- - - seed_turnover = 0.51_r8 ! from Liscke and Loffler 2006 - ! decays the seed pool according to exponential model - ! sd_mort is in yr-1 - do p = 1,numpft_ed - currentPatch%seed_decay(p) = currentPatch%seed_bank(p) * seed_turnover - enddo - - end subroutine seed_decay - - ! ============================================================================ - subroutine seed_germination( currentPatch ) - ! - ! !DESCRIPTION: - ! Flux from seed pool into sapling pool - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type),intent(inout) :: currentPatch ! seeds go to these patches. - ! - ! !LOCAL VARIABLES: - integer :: p - real(r8) max_germination !cap on germination rates. KgC/m2/yr Lishcke et al. 2009 - real(r8) germination_timescale !yr-1 - !---------------------------------------------------------------------- - - germination_timescale = 0.5_r8 !this is arbitrary - max_germination = 1.0_r8 !this is arbitrary - - do p = 1,numpft_ed - currentPatch%seed_germination(p) = min(currentPatch%seed_bank(p) * germination_timescale,max_germination) - enddo - - end subroutine seed_germination - - ! ============================================================================ - subroutine Growth_Derivatives( currentCohort) - ! - ! !DESCRIPTION: - ! Main subroutine controlling growth and allocation derivatives - ! - ! !USES: - use EDGrowthFunctionsMod , only : Bleaf, dDbhdBd, dhdbd, hite, mortality_rates,dDbhdBl - use EDTypesMod , only : udata - ! - ! !ARGUMENTS - type(ed_cohort_type),intent(inout), target :: currentCohort - ! - ! !LOCAL VARIABLES: - type(ed_site_type), pointer :: currentSite - real(r8) :: dbldbd !rate of change of dead biomass per unit dbh - real(r8) :: dbrdbd !rate of change of root biomass per unit dbh - real(r8) :: dbswdbd !rate of change of sapwood biomass per unit dbh - real(r8) :: dhdbd_fn !rate of change of height per unit dbh - real(r8) :: va !fraction of growth going to alive biomass - real(r8) :: vs !fraction of growth going to structural biomass - real(r8) :: u,h !intermediates - real(r8) :: frac !fraction the stored carbon is of target store amount - real(r8) :: f_store !fraction of NPP allocated to storage in this timestep (functionf of stored pool) - real(r8) :: gr_fract !fraction of carbon balance that is allocated to growth (not reproduction) - real(r8) :: target_balive !target leaf biomass under allometric optimum. - real(r8) :: cmort ! starvation mortality rate (fraction per year) - real(r8) :: bmort ! background mortality rate (fraction per year) - real(r8) :: hmort ! hydraulic failure mortality rate (fraction per year) - real(r8) :: balive_loss - !---------------------------------------------------------------------- - - currentSite => currentCohort%siteptr - - ! Mortality for trees in the understorey. - !if trees are in the canopy, then their death is 'disturbance'. This probably needs a different terminology - if (currentCohort%canopy_layer > 1)then - call mortality_rates(currentCohort,cmort,hmort,bmort) - currentCohort%dndt = -1.0_r8 * (cmort+hmort+bmort) * currentCohort%n - else - currentCohort%dndt = 0._r8 - endif - - ! Height - currentCohort%hite = Hite(currentCohort) - h = currentCohort%hite - - call allocate_live_biomass(currentCohort,0) - - ! calculate target size of living biomass compartment for a given dbh. - target_balive = Bleaf(currentCohort) * (1.0_r8 + pftcon%froot_leaf(currentCohort%pft) + & - EDecophyscon%sapwood_ratio(currentCohort%pft)*h) - !target balive without leaves. - if (currentCohort%status_coh == 1)then - target_balive = Bleaf(currentCohort) * (pftcon%froot_leaf(currentCohort%pft) + & - EDecophyscon%sapwood_ratio(currentCohort%pft) * h) - endif - - ! NPP - if ( DEBUG ) write(iulog,*) 'EDphys 716 ',currentCohort%npp_acc - - currentCohort%npp = currentCohort%npp_acc * udata%n_sub !Link to CLM. convert from kgC/indiv/day into kgC/indiv/year - currentCohort%gpp = currentCohort%gpp_acc * udata%n_sub !Link to CLM. convert from kgC/indiv/day into kgC/indiv/year - currentCohort%resp = currentCohort%resp_acc * udata%n_sub !Link to CLM. convert from kgC/indiv/day into kgC/indiv/year - - currentSite%flux_in = currentSite%flux_in + currentCohort%npp_acc * currentCohort%n - - ! Maintenance demands - if (pftcon%evergreen(currentCohort%pft) == 1)then !grass and EBT - currentCohort%leaf_md = currentCohort%bl / pftcon%leaf_long(currentCohort%pft) - currentCohort%root_md = currentCohort%br / EDecophyscon%root_long(currentCohort%pft) - currentCohort%md = currentCohort%root_md + currentCohort%leaf_md - endif - - !FIX(RF,032414) - I took out the stem turnover demand as it seemed excesively high and caused odd size-reated - ! decline affect - !with which I am not especially comfortable, particularly as the concept of sapwood turnover is unclear for trees that - !are still in an expansion phase. - - if (pftcon%season_decid(currentCohort%pft) == 1)then - currentCohort%root_md = currentCohort%br /EDecophyscon%root_long(currentCohort%pft) - currentCohort%leaf_md = 0._r8 - currentCohort%md = currentCohort%root_md + currentCohort%leaf_md - endif - - if (pftcon%stress_decid(currentCohort%pft) == 1)then - currentCohort%root_md = currentCohort%br /EDecophyscon%root_long(currentCohort%pft) - currentCohort%leaf_md = 0._r8 - currentCohort%md = currentCohort%root_md + currentCohort%leaf_md - endif - - if (pftcon%stress_decid(currentCohort%pft) /= 1.and.pftcon%season_decid(currentCohort%pft) /= 1.and. & - pftcon%evergreen(currentCohort%pft) /= 1)then - write(iulog,*) 'problem with phenology definitions',currentCohort%pft,pftcon%stress_decid(currentCohort%pft), & - pftcon%season_decid(currentCohort%pft),pftcon%evergreen(currentCohort%pft) - endif - - ! FIX(RF,032414) -turned off for now as it makes balive go negative.... - ! FIX(RF,032414) jan2012 0.01_r8 * currentCohort%bdead - currentCohort%woody_turnover = 0.0_r8 - currentCohort%md = currentCohort%md + currentCohort%woody_turnover - - ! Calculate carbon balance - ! this is the fraction of maintenance demand we -have- to do... - - if ( DEBUG ) write(iulog,*) 'EDphys 760 ',currentCohort%npp, currentCohort%md, & - EDecophyscon%leaf_stor_priority(currentCohort%pft) - - currentCohort%carbon_balance = currentCohort%npp - currentCohort%md * EDecophyscon%leaf_stor_priority(currentCohort%pft) - - ! Allowing only carbon from NPP pool to account for npp flux into the maintenance pools - ! ie this does not include any use of storage carbon or balive to make up for missing carbon balance in the transfer - currentCohort%npp_leaf = min(currentCohort%npp*currentCohort%leaf_md/currentCohort%md, & - currentCohort%leaf_md*EDecophyscon%leaf_stor_priority(currentCohort%pft)) - currentCohort%npp_froot = min(currentCohort%npp*currentCohort%root_md/currentCohort%md, & - currentCohort%root_md*EDecophyscon%leaf_stor_priority(currentCohort%pft)) - - - if (Bleaf(currentCohort) > 0._r8)then - - if ( DEBUG ) write(iulog,*) 'EDphys A ',currentCohort%carbon_balance - - if (currentCohort%carbon_balance > 0._r8)then !spend C on growing and storing - - !what fraction of the target storage do we have? - frac = max(0.0_r8,currentCohort%bstore/(Bleaf(currentCohort) * EDecophyscon%cushion(currentCohort%pft))) - ! FIX(SPM,080514,fstore never used ) - f_store = max(exp(-1.*frac**4._r8) - exp( -1.0_r8 ),0.0_r8) - !what fraction of allocation do we divert to storage? - !what is the flux into the store? - currentCohort%storage_flux = currentCohort%carbon_balance * f_store - - if ( DEBUG ) write(iulog,*) 'EDphys B ',f_store - - !what is the tax on the carbon available for growth? - currentCohort%carbon_balance = currentCohort%carbon_balance * (1.0_r8 - f_store) - else !cbalance is negative. Take C out of store to pay for maintenance respn. - currentCohort%storage_flux = currentCohort%carbon_balance - currentCohort%carbon_balance = 0._r8 - endif - - else - - currentCohort%storage_flux = 0._r8 - currentCohort%carbon_balance = 0._r8 - write(iulog,*) 'ED: no leaf area in gd', currentCohort%indexnumber,currentCohort%n,currentCohort%bdead, & - currentCohort%dbh,currentCohort%balive - - endif - - !Do we have enough carbon left over to make up the rest of the turnover demand? - balive_loss = 0._r8 - if (currentCohort%carbon_balance > currentCohort%md*(1.0_r8- EDecophyscon%leaf_stor_priority(currentCohort%pft)))then ! Yes... - currentCohort%carbon_balance = currentCohort%carbon_balance - currentCohort%md * (1.0_r8 - & - EDecophyscon%leaf_stor_priority(currentCohort%pft)) - - currentCohort%npp_leaf = currentCohort%npp_leaf + & - currentCohort%leaf_md * (1.0_r8-EDecophyscon%leaf_stor_priority(currentCohort%pft)) - currentCohort%npp_froot = currentCohort%npp_froot + & - currentCohort%root_md * (1.0_r8-EDecophyscon%leaf_stor_priority(currentCohort%pft)) - - else ! we can't maintain constant leaf area and root area. Balive is reduced - - currentCohort%npp_leaf = currentCohort%npp_leaf + & - max(0.0_r8,currentCohort%carbon_balance*(currentCohort%leaf_md/currentCohort%md)) - currentCohort%npp_froot = currentCohort%npp_froot + & - max(0.0_r8,currentCohort%carbon_balance*(currentCohort%root_md/currentCohort%md)) - - balive_loss = currentCohort%md *(1.0_r8- EDecophyscon%leaf_stor_priority(currentCohort%pft))- currentCohort%carbon_balance - currentCohort%carbon_balance = 0._r8 - endif - - !********************************************/ - ! Allometry & allocation of remaining carbon*/ - !********************************************/ - !Use remaining carbon to refill balive or to get larger. - - !only if carbon balance is +ve - if ((currentCohort%balive >= target_balive).AND.(currentCohort%carbon_balance > 0._r8))then - ! fraction of carbon going into active vs structural carbon - if (currentCohort%dbh <= EDecophyscon%max_dbh(currentCohort%pft))then ! cap on leaf biomass - dbldbd = dDbhdBd(currentCohort)/dDbhdBl(currentCohort) - dbrdbd = pftcon%froot_leaf(currentCohort%pft) * dbldbd - dhdbd_fn = dhdbd(currentCohort) - dbswdbd = EDecophyscon%sapwood_ratio(currentCohort%pft) * (h*dbldbd + currentCohort%bl*dhdbd_fn) - u = 1.0_r8 / (dbldbd + dbrdbd + dbswdbd) - va = 1.0_r8 / (1.0_r8 + u) - vs = u / (1.0_r8 + u) - gr_fract = 1.0_r8 - EDecophyscon%seed_alloc(currentCohort%pft) - else - dbldbd = 0._r8; dbrdbd = 0._r8 ;dbswdbd = 0._r8 - va = 0.0_r8 - vs = 1.0_r8 - gr_fract = 1.0_r8 - (EDecophyscon%seed_alloc(currentCohort%pft) + EDecophyscon%clone_alloc(currentCohort%pft)) - endif - - !FIX(RF,032414) - to fix high bl's. needed to prevent numerical errors without the ODEINT. - if (currentCohort%balive > target_balive*1.1_r8)then - va = 0.0_r8; vs = 1._r8 - write(iulog,*) 'using high bl cap',target_balive,currentCohort%balive - endif - - else - dbldbd = 0._r8; dbrdbd = 0._r8; dbswdbd = 0._r8 - va = 1.0_r8; vs = 0._r8 - gr_fract = 1.0_r8 - endif - - ! calculate derivatives of living and dead carbon pools - currentCohort%dbalivedt = gr_fract * va * currentCohort%carbon_balance - balive_loss - currentCohort%dbdeaddt = gr_fract * vs * currentCohort%carbon_balance - currentCohort%dbstoredt = currentCohort%storage_flux - - if ( DEBUG ) write(iulog,*) 'EDPhys dbstoredt I ',currentCohort%dbstoredt - - currentCohort%seed_prod = (1.0_r8 - gr_fract) * currentCohort%carbon_balance - if (abs(currentCohort%npp-(currentCohort%dbalivedt+currentCohort%dbdeaddt+currentCohort%dbstoredt+ & - currentCohort%seed_prod+currentCohort%md)) > 0.0000000001_r8)then - write(iulog,*) 'error in carbon check growth derivs',currentCohort%npp- & - (currentCohort%dbalivedt+currentCohort%dbdeaddt+currentCohort%dbstoredt+currentCohort%seed_prod+currentCohort%md) - write(iulog,*) 'cohort fluxes',currentCohort%pft,currentCohort%canopy_layer,currentCohort%n, & - currentCohort%npp,currentCohort%dbalivedt,balive_loss, & - currentCohort%dbdeaddt,currentCohort%dbstoredt,currentCohort%seed_prod,currentCohort%md * & - EDecophyscon%leaf_stor_priority(currentCohort%pft) - write(iulog,*) 'proxies' ,target_balive,currentCohort%balive,currentCohort%dbh,va,vs,gr_fract - endif - - ! prevent negative leaf pool (but not negative store pool). This is also a numerical error prevention, - ! but it shouldn't happen actually... - if (-1.0_r8*currentCohort%dbalivedt * udata%deltat > currentCohort%balive*0.99)then - write(iulog,*) 'using non-neg leaf mass cap',currentCohort%balive , currentCohort%dbalivedt,currentCohort%dbstoredt, & - currentCohort%carbon_balance - currentCohort%dbstoredt = currentCohort%dbstoredt + currentCohort%dbalivedt - - if ( DEBUG ) write(iulog,*) 'EDPhys dbstoredt II ',currentCohort%dbstoredt - - currentCohort%dbalivedt = 0._r8 - endif - - currentCohort%npp_bseed = currentCohort%seed_prod - currentCohort%npp_store = max(0.0_r8,currentCohort%storage_flux) - - ! calculate change in diameter and height - currentCohort%ddbhdt = currentCohort%dbdeaddt * dDbhdBd(currentCohort) - currentCohort%dhdt = currentCohort%dbdeaddt * dHdBd(currentCohort) - - ! If the cohort has grown, it is not new - currentCohort%isnew=.false. - - end subroutine Growth_Derivatives - - ! ============================================================================ - subroutine recruitment( t, currentPatch ) - ! - ! !DESCRIPTION: - ! spawn new cohorts of juveniles of each PFT - ! - ! !USES: - use EDGrowthFunctionsMod, only : bdead,dbh, Bleaf - use EDTypesMod, only : udata - ! - ! !ARGUMENTS - integer, intent(in) :: t - type(ed_patch_type), intent(inout), pointer :: currentPatch - ! - ! !LOCAL VARIABLES: - integer :: ft - type (ed_cohort_type) , pointer :: temp_cohort - integer :: cohortstatus - !---------------------------------------------------------------------- - - allocate(temp_cohort) ! create temporary cohort - call zero_cohort(temp_cohort) - - do ft = 1,numpft_ed - - temp_cohort%canopy_trim = 0.8_r8 !starting with the canopy not fully expanded - temp_cohort%pft = ft - temp_cohort%hite = EDecophyscon%hgt_min(ft) - temp_cohort%dbh = Dbh(temp_cohort) - temp_cohort%bdead = Bdead(temp_cohort) - temp_cohort%balive = Bleaf(temp_cohort)*(1.0_r8 + pftcon%froot_leaf(ft) & - + EDecophyscon%sapwood_ratio(ft)*temp_cohort%hite) - temp_cohort%bstore = EDecophyscon%cushion(ft)*(temp_cohort%balive/ (1.0_r8 + pftcon%froot_leaf(ft) & - + EDecophyscon%sapwood_ratio(ft)*temp_cohort%hite)) - temp_cohort%n = currentPatch%area * currentPatch%seed_germination(ft)*udata%deltat & - / (temp_cohort%bdead+temp_cohort%balive+temp_cohort%bstore) - - if (t == 1)then - write(iulog,*) 'filling in cohorts where there are none left; this will break carbon balance', & - currentPatch%patchno,currentPatch%area - temp_cohort%n = 0.1_r8*currentPatch%area - write(iulog,*) 'cohort n',ft,temp_cohort%n - endif - - temp_cohort%laimemory = 0.0_r8 - if (pftcon%season_decid(temp_cohort%pft) == 1.and.currentPatch%siteptr%status == 1)then - temp_cohort%laimemory = (1.0_r8/(1.0_r8 + pftcon%froot_leaf(ft) + & - EDecophyscon%sapwood_ratio(ft)*temp_cohort%hite))*temp_cohort%balive - endif - if (pftcon%stress_decid(temp_cohort%pft) == 1.and.currentPatch%siteptr%dstatus == 1)then - temp_cohort%laimemory = (1.0_r8/(1.0_r8 + pftcon%froot_leaf(ft) + & - EDecophyscon%sapwood_ratio(ft)*temp_cohort%hite))*temp_cohort%balive - endif - - cohortstatus = currentPatch%siteptr%status - if (pftcon%stress_decid(ft) == 1)then !drought decidous, override status. - cohortstatus = currentPatch%siteptr%dstatus - endif - - if (temp_cohort%n > 0.0_r8 )then - if ( DEBUG ) write(iulog,*) 'EDPhysiologyMod.F90 call create_cohort ' - call create_cohort(currentPatch, temp_cohort%pft, temp_cohort%n, temp_cohort%hite, temp_cohort%dbh, & - temp_cohort%balive, temp_cohort%bdead, temp_cohort%bstore, & - temp_cohort%laimemory, cohortstatus, temp_cohort%canopy_trim, currentPatch%NCL_p) - endif - - enddo !pft loop - - deallocate(temp_cohort) ! delete temporary cohort - - end subroutine recruitment - - ! ============================================================================ - subroutine CWD_Input( currentPatch) - ! - ! !DESCRIPTION: - ! Generate litter fields from turnover. - ! - ! !USES: - use SFParamsMod , only : SF_val_CWD_frac - use EDParamsMod , only : ED_val_ag_biomass - use EDTypesMod , only : udata - ! - ! !ARGUMENTS - type(ed_patch_type),intent(inout), target :: currentPatch - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: currentCohort - integer :: c,p - real(r8) :: not_dead_n !projected remaining number of trees in understorey cohort after turnover - real(r8) :: dead_n !understorey dead tree density - integer :: pft - !---------------------------------------------------------------------- - - ! ================================================ - ! Other direct litter fluxes happen in phenology and in spawn_patches. - ! ================================================ - - currentCohort => currentPatch%shortest - - do while(associated(currentCohort)) - pft = currentCohort%pft - ! ================================================ - ! Litter from tissue turnover. KgC/m2/year - ! ================================================ - currentPatch%leaf_litter_in(pft) = currentPatch%leaf_litter_in(pft) + & - currentCohort%leaf_md * currentCohort%n/currentPatch%area !turnover - - currentPatch%root_litter_in(pft) = currentPatch%root_litter_in(pft) + & - currentCohort%root_md * currentCohort%n/currentPatch%area !turnover - currentPatch%leaf_litter_in(pft) = currentPatch%leaf_litter_in(pft) + & - currentCohort%leaf_litter * currentCohort%n/currentPatch%area/udata%deltat - - !daily leaf loss needs to be scaled up to the annual scale here. - - do c = 1,ncwd - currentPatch%cwd_AG_in(c) = currentPatch%cwd_AG_in(c) + currentCohort%woody_turnover * & - SF_val_CWD_frac(c) * currentCohort%n/currentPatch%area *ED_val_ag_biomass - currentPatch%cwd_BG_in(c) = currentPatch%cwd_BG_in(c) + currentCohort%woody_turnover * & - SF_val_CWD_frac(c) * currentCohort%n/currentPatch%area *(1.0_r8-ED_val_ag_biomass) - enddo - - if (currentCohort%canopy_layer > 1)then - - ! ================================================ - ! Litter fluxes for understorey mortality. KgC/m2/year - ! ================================================ - dead_n = -1.0_r8 * currentCohort%dndt / currentPatch%area - - currentPatch%leaf_litter_in(pft) = currentPatch%leaf_litter_in(pft) + & - (currentCohort%bl+currentCohort%leaf_litter/udata%deltat)* dead_n - currentPatch%root_litter_in(pft) = currentPatch%root_litter_in(pft) + & - (currentCohort%br+currentCohort%bstore) * dead_n - - do c = 1,ncwd - currentPatch%cwd_AG_in(c) = currentPatch%cwd_AG_in(c) + (currentCohort%bdead+currentCohort%bsw) * & - SF_val_CWD_frac(c) * dead_n * ED_val_ag_biomass - currentPatch%cwd_BG_in(c) = currentPatch%cwd_BG_in(c) + (currentCohort%bdead+currentCohort%bsw) * & - SF_val_CWD_frac(c) * dead_n * (1.0_r8-ED_val_ag_biomass) - - if (currentPatch%cwd_AG_in(c) < 0.0_r8)then - write(iulog,*) 'negative CWD in flux',currentPatch%cwd_AG_in(c), & - (currentCohort%bdead+currentCohort%bsw), dead_n - endif - enddo - - endif !canopy layer - - currentCohort => currentCohort%taller - - enddo ! end loop over cohorts - - do p = 1,numpft_ed - currentPatch%leaf_litter_in(p) = currentPatch%leaf_litter_in(p) + currentPatch%seed_decay(p) !KgC/m2/yr - enddo - - end subroutine CWD_Input - - ! ============================================================================ - subroutine fragmentation_scaler( currentPatch, temperature_inst ) - ! - ! !DESCRIPTION: - ! Simple CWD fragmentation Model - ! FIX(SPM, 091914) this should be a function as it returns a value in currentPatch%fragmentation_scaler - ! - ! !USES: - use shr_const_mod , only : SHR_CONST_PI, SHR_CONST_TKFRZ - use EDSharedParamsMod , only : EDParamsShareInst - - ! - ! !ARGUMENTS - type(ed_patch_type) , intent(inout) :: currentPatch - type(temperature_type) , intent(in) :: temperature_inst - ! - ! !LOCAL VARIABLES: - logical :: use_century_tfunc = .false. - type(ed_site_type), pointer :: currentSite - integer :: p,j - real(r8) :: t_scalar - real(r8) :: w_scalar - real(r8) :: catanf ! hyperbolic temperature function from CENTURY - real(r8) :: catanf_30 ! hyperbolic temperature function from CENTURY - real(r8) :: t1 ! temperature argument - real(r8) :: Q10 ! temperature dependence - real(r8) :: froz_q10 ! separate q10 for frozen soil respiration rates. default to same as above zero rates - real(r8), pointer :: t_veg24(:) - !---------------------------------------------------------------------- - - catanf(t1) = 11.75_r8 +(29.7_r8 / SHR_CONST_PI) * atan( SHR_CONST_PI * 0.031_r8 * ( t1 - 15.4_r8 )) - - t_veg24 => temperature_inst%t_veg24_patch ! Input: [real(r8) (:)] avg pft vegetation temperature for last 24 hrs - - catanf_30 = catanf(30._r8) - -! c = currentPatch%siteptr%clmcolumn - p = currentPatch%clm_pno - - ! set "froz_q10" parameter - froz_q10 = EDParamsShareInst%froz_q10 - Q10 = EDParamsShareInst%Q10 - - if ( .not. use_century_tfunc ) then - !calculate rate constant scalar for soil temperature,assuming that the base rate constants - !are assigned for non-moisture limiting conditions at 25C. - if (t_veg24(p) >= SHR_CONST_TKFRZ) then - t_scalar = Q10**((t_veg24(p)-(SHR_CONST_TKFRZ+25._r8))/10._r8) - ! Q10**((t_soisno(c,j)-(SHR_CONST_TKFRZ+25._r8))/10._r8) - else - t_scalar = (Q10**(-25._r8/10._r8))*(froz_q10**((t_veg24(p)-SHR_CONST_TKFRZ)/10._r8)) - !Q10**(-25._r8/10._r8))*(froz_q10**((t_soisno(c,j)-SHR_CONST_TKFRZ)/10._r8) - endif - else - ! original century uses an arctangent function to calculate the temperature dependence of decomposition - t_scalar = max(catanf(t_veg24(p)-SHR_CONST_TKFRZ)/catanf_30,0.01_r8) - endif - - !Moisture Limitations - !BTRAN APPROACH - is quite simple, but max's out decomp at all unstressed soil moisture values, which is not realistic. - !litter decomp is proportional to water limitation on average... - w_scalar = sum(currentPatch%btran_ft(1:numpft_ed))/numpft_ed - - currentPatch%fragmentation_scaler = min(1.0_r8,max(0.0_r8,t_scalar * w_scalar)) - - end subroutine fragmentation_scaler - - ! ============================================================================ - subroutine cwd_out( currentPatch, temperature_inst ) - ! - ! !DESCRIPTION: - ! Simple CWD fragmentation Model - ! spawn new cohorts of juveniles of each PFT - ! - ! !USES: - use SFParamsMod, only : SF_val_max_decomp - use EDTypesMod , only : udata - ! - ! !ARGUMENTS - type(ed_patch_type) , intent(inout), target :: currentPatch - type(temperature_type) , intent(in) :: temperature_inst - ! - ! !LOCAL VARIABLES: - type(ed_site_type), pointer :: currentSite - integer :: c,ft - !---------------------------------------------------------------------- - - currentSite => currentPatch%siteptr - currentPatch%root_litter_out(:) = 0.0_r8 - currentPatch%leaf_litter_out(:) = 0.0_r8 - - call fragmentation_scaler(currentPatch, temperature_inst) - - !Flux of coarse woody debris into decomposing litter pool. - - currentPatch%cwd_ag_out(1:ncwd) = 0.0_r8 - currentPatch%cwd_bg_out(1:ncwd) = 0.0_r8 - currentPatch%leaf_litter_out(1:numpft_ed) = 0.0_r8 - currentPatch%root_litter_out(1:numpft_ed) = 0.0_r8 - - do c = 1,ncwd - currentPatch%cwd_ag_out(c) = max(0.0_r8, currentPatch%cwd_ag(c) * & - SF_val_max_decomp(c+1) * currentPatch%fragmentation_scaler ) - currentPatch%cwd_bg_out(c) = max(0.0_r8, currentPatch%cwd_bg(c) * & - SF_val_max_decomp(c+1) * currentPatch%fragmentation_scaler ) - enddo - - ! this is the rate at which dropped leaves stop being part of the burnable pool and begin to be part of the - ! decomposing pool. This should probably be highly sensitive to moisture, but also to the type of leaf - ! thick leaves can dry out before they are decomposed, for example. - ! this section needs further scientific input. - - do ft = 1,numpft_ed - currentPatch%leaf_litter_out(ft) = max(0.0_r8,currentPatch%leaf_litter(ft)* SF_val_max_decomp(dg_sf) * & - currentPatch%fragmentation_scaler ) - currentPatch%root_litter_out(ft) = max(0.0_r8,currentPatch%root_litter(ft)* SF_val_max_decomp(dg_sf) * & - currentPatch%fragmentation_scaler ) - if ( currentPatch%leaf_litter_out(ft)<0.0_r8.or.currentPatch%root_litter_out(ft)<0.0_r8)then - write(iulog,*) 'root or leaf out is negative?',SF_val_max_decomp(dg_sf),currentPatch%fragmentation_scaler - endif - enddo - - !add up carbon going into fragmenting pools - currentSite%flux_out = currentSite%flux_out + sum(currentPatch%leaf_litter_out) * & - currentPatch%area *udata%deltat!kgC/site/day - currentSite%flux_out = currentSite%flux_out + sum(currentPatch%root_litter_out) * & - currentPatch%area *udata%deltat!kgC/site/day - currentSite%flux_out = currentSite%flux_out + sum(currentPatch%cwd_ag_out) * & - currentPatch%area *udata%deltat!kgC/site/day - currentSite%flux_out = currentSite%flux_out + sum(currentPatch%cwd_bg_out) * & - currentPatch%area *udata%deltat!kgC/site/day - - end subroutine cwd_out - - - - subroutine flux_into_litter_pools(nsites, sites, bc_in, bc_out) - ! Created by Charlie Koven and Rosie Fisher, 2014-2015 - ! take the flux out of the fragmenting litter pools and port into the decomposing litter pools. - ! in this implementation, decomposing pools are assumed to be humus and non-flammable, whereas fragmenting pools - ! are assumed to be physically fragmenting but not respiring. This is a simplification, but allows us to - ! a) reconcile the need to track both chemical fractions (lignin, cellulose, labile) and size fractions (trunk, branch, etc.) - ! b) to impose a realistic delay on the surge of nutrients into the litter pools when large CWD is added to the system via mortality - - ! because of the different subgrid structure, this subroutine includes the functionality that in the big-leaf BGC model, is calculated in SoilBiogeochemVerticalProfileMod - - ! The ED code is resolved at a daily timestep, but all of the CN-BGC fluxes are passed in as derivatives per second, - ! and then accumulated in the CNStateUpdate routines. One way of doing this is to pass back the CN fluxes per second, - ! and keep them constant for the whole day (making sure they are not overwritten. - ! This means that the carbon gets passed back and forth between the photosynthesis code (fast timestepping) to the ED code (slow timestepping), back to the BGC code (fast timestepping). - ! This means that the state update for the litter pools and for the CWD pools occurs at different timescales. - - - use EDTypesMod, only : AREA, numpft_ed, cp_numlevdecomp_full, cp_numlevdecomp - use SoilBiogeochemVerticalProfileMod, only: surfprof_exp - use EDCLMLinkMod, only: cwd_fcel_ed, cwd_flig_ed - use pftconMod, only : pftcon - use shr_const_mod, only: SHR_CONST_CDAY - use clm_varcon, only : zisoi, dzsoi_decomp, zsoi - use EDParamsMod, only : ED_val_ag_biomass - use FatesInterfaceMod, only : bc_in_type, bc_out_type - use clm_varctl, only : use_vertsoilc - use abortutils , only : endrun - - ! INTERF-TODO: remove the control parameters: exponential_rooting_profile, pftspecific_rootingprofile, rootprof_exp, surfprof_exp, zisoi, dzsoi_decomp, zsoi - ! - implicit none - ! - ! !ARGUMENTS - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - type(bc_in_type) , intent(in) :: bc_in(:) - type(bc_out_type) , intent(inout) :: bc_out(:) - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort - type(ed_site_type), pointer :: cs - integer p,ci,j,s - real(r8) time_convert ! from year to seconds - real(r8) mass_convert ! ED uses kg, CLM uses g - integer :: begp,endp - integer :: begc,endc !bounds - !------------------------------------------------------------------------ - real(r8) :: cinput_rootfr(1:numpft_ed, 1:cp_numlevdecomp_full) ! column by pft root fraction used for calculating inputs - real(r8) :: croot_prof_perpatch(1:cp_numlevdecomp_full) - real(r8) :: surface_prof(1:cp_numlevdecomp_full) - integer :: ft - real(r8) :: rootfr_tot(1:numpft_ed), biomass_bg_ft(1:numpft_ed) - real(r8) :: surface_prof_tot, leaf_prof_sum, stem_prof_sum, froot_prof_sum, biomass_bg_tot - real(r8) :: delta - - ! NOTE(bja, 201608) these were removed from clm in clm4_5_10_r187 - logical, parameter :: exponential_rooting_profile = .true. - logical, parameter :: pftspecific_rootingprofile = .true. - - ! NOTE(bja, 201608) as of clm4_5_10_r187 rootprof_exp is now a - ! private function level parameter in RootBiophysMod.F90::exponential_rootfr() - real(r8), parameter :: rootprof_exp = 3. ! how steep profile is - ! for root C inputs (1/ e-folding depth) (1/m) - - ! NOTE(bja, 201608) as of clm4_5_10_r187 rootprof_beta is now a - ! two dimensional array with the second dimension being water,1, - ! or carbon,2,. These are currently hard coded, but may be - ! overwritten by the namelist. - - ! Note cdk 2016/08 we actually want to use the carbon index here rather than the water index. - ! Doing so will be answer changing though so perhaps easiest to do this in steps. - integer, parameter :: rooting_profile_varindex_water = 1 - - real(r8) :: leaf_prof(1:nsites, 1:cp_numlevdecomp) - real(r8) :: froot_prof(1:nsites, 1:numpft_ed, 1:cp_numlevdecomp) - real(r8) :: croot_prof(1:nsites, 1:cp_numlevdecomp) - real(r8) :: stem_prof(1:nsites, 1:cp_numlevdecomp) - - - delta = 0.001_r8 - !no of seconds in a year. - time_convert = 365.0_r8*SHR_CONST_CDAY - - ! number of grams in a kilogram - mass_convert = 1000._r8 - - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! first calculate vertical profiles - ! define two types of profiles: - ! (1) a surface profile, for leaves and stem inputs, which is the same for each pft but differs from one site to the next to avoid inputting any C into permafrost or bedrock - ! (2) a fine root profile, which is indexed by both site and pft, differs for each pft and also from one site to the next to avoid inputting any C into permafrost or bedrock - ! (3) a coarse root profile, which is the root-biomass=weighted average of the fine root profiles - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (use_vertsoilc) then - - ! define a single shallow surface profile for surface additions (leaves, stems, and N deposition) - surface_prof(:) = 0._r8 - do j = 1, cp_numlevdecomp - surface_prof(j) = exp(-surfprof_exp * zsoi(j)) / dzsoi_decomp(j) - end do - - ! initialize profiles to zero - leaf_prof(1:nsites, :) = 0._r8 - froot_prof(1:nsites, 1:numpft_ed, :) = 0._r8 - croot_prof(1:nsites, :) = 0._r8 - stem_prof(1:nsites, :) = 0._r8 - - cinput_rootfr(1:numpft_ed, :) = 0._r8 - - ! calculate pft-specific rooting profiles in the absence of permafrost or bedrock limitations - if ( exponential_rooting_profile ) then - if ( .not. pftspecific_rootingprofile ) then - ! define rooting profile from exponential parameters - do ft = 1, numpft_ed - do j = 1, cp_numlevdecomp - cinput_rootfr(ft,j) = exp(-rootprof_exp * zsoi(j)) / dzsoi_decomp(j) - end do - end do - else - ! use beta distribution parameter from Jackson et al., 1996 - do ft = 1, numpft_ed - do j = 1, cp_numlevdecomp - cinput_rootfr(ft,j) = ( pftcon%rootprof_beta(ft, rooting_profile_varindex_water) ** (zisoi(j-1)*100._r8) - & - pftcon%rootprof_beta(ft, rooting_profile_varindex_water) ** (zisoi(j)*100._r8) ) & - / dzsoi_decomp(j) - end do - end do - endif - else - do ft = 1,numpft_ed - do j = 1, cp_numlevdecomp - ! use standard CLM root fraction profiles; - cinput_rootfr(ft,j) = ( .5_r8*( & - exp(-pftcon%roota_par(ft) * zisoi(j-1)) & - + exp(-pftcon%rootb_par(ft) * zisoi(j-1)) & - - exp(-pftcon%roota_par(ft) * zisoi(j)) & - - exp(-pftcon%rootb_par(ft) * zisoi(j)))) / dzsoi_decomp(j) - end do - end do - endif - ! - - do s = 1,nsites - ! - ! now add permafrost constraint: integrate rootfr over active layer of soil site, - ! truncate below permafrost or bedrock table where present, and rescale so that integral = 1 - do ft = 1,numpft_ed - rootfr_tot(ft) = 0._r8 - end do - surface_prof_tot = 0._r8 - ! - do j = 1, min(max(bc_in(s)%max_rooting_depth_index_col, 1), cp_numlevdecomp) - surface_prof_tot = surface_prof_tot + surface_prof(j) * dzsoi_decomp(j) - end do - do ft = 1,numpft_ed - do j = 1, min(max(bc_in(s)%max_rooting_depth_index_col, 1), cp_numlevdecomp) - rootfr_tot(ft) = rootfr_tot(ft) + cinput_rootfr(ft,j) * dzsoi_decomp(j) - end do - end do - ! - ! rescale the fine root profile - do ft = 1,numpft_ed - if ( (bc_in(s)%max_rooting_depth_index_col > 0) .and. (rootfr_tot(ft) > 0._r8) ) then - ! where there is not permafrost extending to the surface, integrate the profiles over the active layer - ! this is equivalent to integrating over all soil layers outside of permafrost regions - do j = 1, min(max(bc_in(s)%max_rooting_depth_index_col, 1), cp_numlevdecomp) - froot_prof(s,ft,j) = cinput_rootfr(ft,j) / rootfr_tot(ft) - end do - else - ! if fully frozen, or no roots, put everything in the top layer - froot_prof(s,ft,1) = 1._r8/dzsoi_decomp(1) - endif - end do - ! - ! rescale the shallow profiles - if ( (bc_in(s)%max_rooting_depth_index_col > 0) .and. (surface_prof_tot > 0._r8) ) then - ! where there is not permafrost extending to the surface, integrate the profiles over the active layer - ! this is equivalent to integrating over all soil layers outside of permafrost regions - do j = 1, min(max(bc_in(s)%max_rooting_depth_index_col, 1), cp_numlevdecomp) - ! set all surface processes to shallower profile - leaf_prof(s,j) = surface_prof(j)/ surface_prof_tot - stem_prof(s,j) = surface_prof(j)/ surface_prof_tot - end do - else - ! if fully frozen, or no roots, put everything in the top layer - leaf_prof(s,1) = 1._r8/dzsoi_decomp(1) - stem_prof(s,1) = 1._r8/dzsoi_decomp(1) - do j = 2, cp_numlevdecomp - leaf_prof(s,j) = 0._r8 - stem_prof(s,j) = 0._r8 - end do - endif - end do - - else - - ! for one layer decomposition model, set profiles to unity - leaf_prof(1:nsites, :) = 1._r8 - froot_prof(1:nsites, 1:numpft_ed, :) = 1._r8 - stem_prof(1:nsites, :) = 1._r8 - - end if - - ! sanity check to ensure they integrate to 1 - do s = 1, nsites - ! check the leaf and stem profiles - leaf_prof_sum = 0._r8 - stem_prof_sum = 0._r8 - do j = 1, cp_numlevdecomp - leaf_prof_sum = leaf_prof_sum + leaf_prof(s,j) * dzsoi_decomp(j) - stem_prof_sum = stem_prof_sum + stem_prof(s,j) * dzsoi_decomp(j) - end do - if ( ( abs(stem_prof_sum - 1._r8) > delta ) .or. ( abs(leaf_prof_sum - 1._r8) > delta ) ) then - write(iulog, *) 'profile sums: ', leaf_prof_sum, stem_prof_sum - write(iulog, *) 'surface_prof: ', surface_prof - write(iulog, *) 'surface_prof_tot: ', surface_prof_tot - write(iulog, *) 'leaf_prof: ', leaf_prof(s,:) - write(iulog, *) 'stem_prof: ', stem_prof(s,:) - write(iulog, *) 'max_rooting_depth_index_col: ', bc_in(s)%max_rooting_depth_index_col - write(iulog, *) 'dzsoi_decomp: ', dzsoi_decomp - call endrun() - endif - ! now check each fine root profile - do ft = 1,numpft_ed - froot_prof_sum = 0._r8 - do j = 1, cp_numlevdecomp - froot_prof_sum = froot_prof_sum + froot_prof(s,ft,j) * dzsoi_decomp(j) - end do - if ( ( abs(froot_prof_sum - 1._r8) > delta ) ) then - write(iulog, *) 'profile sums: ', froot_prof_sum - call endrun() - endif - end do - end do - - ! zero the site-level C input variables - do s = 1, nsites - do j = 1, cp_numlevdecomp - bc_out(s)%FATES_c_to_litr_lab_c_col(j) = 0._r8 - bc_out(s)%FATES_c_to_litr_cel_c_col(j) = 0._r8 - bc_out(s)%FATES_c_to_litr_lig_c_col(j) = 0._r8 - croot_prof(s,j) = 0._r8 - end do - end do - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! now disaggregate the inputs vertically, using the vertical profiles - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - do s = 1,nsites - - ! do g = bounds%begg,bounds%endg - ! if (firstsoilpatch(g) >= 0 .and. ed_allsites_inst(g)%istheresoil) then - currentPatch => sites(s)%oldest_patch - - do while(associated(currentPatch)) - - ! the CWD pools lose information about which PFT they came from; for the stems this doesn't matter as they all have the same profile, - ! however for the coarse roots they may have different profiles. to approximately recover this information, loop over all cohorts in patch - ! to calculate the total root biomass in that patch of each pft, and then rescale the croot_prof as the weighted average of the froot_prof - biomass_bg_ft(1:numpft_ed) = 0._r8 - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - biomass_bg_ft(currentCohort%pft) = biomass_bg_ft(currentCohort%pft) + & - currentCohort%b * (currentCohort%n / currentPatch%area) * (1.0_r8-ED_val_ag_biomass) - currentCohort => currentCohort%shorter - enddo !currentCohort - ! - biomass_bg_tot = 0._r8 - do ft = 1,numpft_ed - biomass_bg_tot = biomass_bg_tot + biomass_bg_ft(ft) - end do - ! - do j = 1, cp_numlevdecomp - ! zero this for each patch - croot_prof_perpatch(j) = 0._r8 - end do - ! - if ( biomass_bg_tot .gt. 0._r8) then - do ft = 1,numpft_ed - do j = 1, cp_numlevdecomp - croot_prof_perpatch(j) = croot_prof_perpatch(j) + froot_prof(s,ft,j) * biomass_bg_ft(ft) / biomass_bg_tot - end do - end do - else ! no biomass - croot_prof_perpatch(1) = 1./dzsoi_decomp(1) - end if - - ! - ! add croot_prof as weighted average (weighted by patch area) of croot_prof_perpatch - do j = 1, cp_numlevdecomp - croot_prof(s, j) = croot_prof(s, j) + croot_prof_perpatch(j) * currentPatch%area / AREA - end do - ! - ! now disaggregate, vertically and by decomposition substrate type, the actual fluxes from CWD and litter pools - ! - ! do c = 1, ncwd - ! write(iulog,*)'cdk CWD_AG_out', c, currentpatch%CWD_AG_out(c), cwd_fcel_ed, currentpatch%area/AREA - ! write(iulog,*)'cdk CWD_BG_out', c, currentpatch%CWD_BG_out(c), cwd_fcel_ed, currentpatch%area/AREA - ! end do - ! do ft = 1,numpft_ed - ! write(iulog,*)'cdk leaf_litter_out', ft, currentpatch%leaf_litter_out(ft), cwd_fcel_ed, currentpatch%area/AREA - ! write(iulog,*)'cdk root_litter_out', ft, currentpatch%root_litter_out(ft), cwd_fcel_ed, currentpatch%area/AREA - ! end do - ! ! - ! CWD pools fragmenting into decomposing litter pools. - do ci = 1, ncwd - do j = 1, cp_numlevdecomp - bc_out(s)%FATES_c_to_litr_cel_c_col(j) = bc_out(s)%FATES_c_to_litr_cel_c_col(j) + & - currentpatch%CWD_AG_out(ci) * cwd_fcel_ed * currentpatch%area/AREA * stem_prof(s,j) - bc_out(s)%FATES_c_to_litr_lig_c_col(j) = bc_out(s)%FATES_c_to_litr_lig_c_col(j) + & - currentpatch%CWD_AG_out(ci) * cwd_flig_ed * currentpatch%area/AREA * stem_prof(s,j) - ! - bc_out(s)%FATES_c_to_litr_cel_c_col(j) = bc_out(s)%FATES_c_to_litr_cel_c_col(j) + & - currentpatch%CWD_BG_out(ci) * cwd_fcel_ed * currentpatch%area/AREA * croot_prof_perpatch(j) - bc_out(s)%FATES_c_to_litr_lig_c_col(j) = bc_out(s)%FATES_c_to_litr_lig_c_col(j) + & - currentpatch%CWD_BG_out(ci) * cwd_flig_ed * currentpatch%area/AREA * croot_prof_perpatch(j) - end do - end do - - ! leaf and fine root pools. - do ft = 1,numpft_ed - do j = 1, cp_numlevdecomp - bc_out(s)%FATES_c_to_litr_lab_c_col(j) = bc_out(s)%FATES_c_to_litr_lab_c_col(j) + & - currentpatch%leaf_litter_out(ft) * pftcon%lf_flab(ft) * currentpatch%area/AREA * leaf_prof(s,j) - bc_out(s)%FATES_c_to_litr_cel_c_col(j) = bc_out(s)%FATES_c_to_litr_cel_c_col(j) + & - currentpatch%leaf_litter_out(ft) * pftcon%lf_fcel(ft) * currentpatch%area/AREA * leaf_prof(s,j) - bc_out(s)%FATES_c_to_litr_lig_c_col(j) = bc_out(s)%FATES_c_to_litr_lig_c_col(j) + & - currentpatch%leaf_litter_out(ft) * pftcon%lf_flig(ft) * currentpatch%area/AREA * leaf_prof(s,j) - ! - bc_out(s)%FATES_c_to_litr_lab_c_col(j) = bc_out(s)%FATES_c_to_litr_lab_c_col(j) + & - currentpatch%root_litter_out(ft) * pftcon%fr_flab(ft) * currentpatch%area/AREA * froot_prof(s,ft,j) - bc_out(s)%FATES_c_to_litr_cel_c_col(j) = bc_out(s)%FATES_c_to_litr_cel_c_col(j) + & - currentpatch%root_litter_out(ft) * pftcon%fr_fcel(ft) * currentpatch%area/AREA * froot_prof(s,ft,j) - bc_out(s)%FATES_c_to_litr_lig_c_col(j) = bc_out(s)%FATES_c_to_litr_lig_c_col(j) + & - currentpatch%root_litter_out(ft) * pftcon%fr_flig(ft) * currentpatch%area/AREA * froot_prof(s,ft,j) - ! - !! and seed_decay too. for now, use the same lability fractions as for leaf litter - bc_out(s)%FATES_c_to_litr_lab_c_col(j) = bc_out(s)%FATES_c_to_litr_lab_c_col(j) + & - currentpatch%seed_decay(ft) * pftcon%lf_flab(ft) * currentpatch%area/AREA * leaf_prof(s,j) - bc_out(s)%FATES_c_to_litr_cel_c_col(j) = bc_out(s)%FATES_c_to_litr_cel_c_col(j) + & - currentpatch%seed_decay(ft) * pftcon%lf_fcel(ft) * currentpatch%area/AREA * leaf_prof(s,j) - bc_out(s)%FATES_c_to_litr_lig_c_col(j) = bc_out(s)%FATES_c_to_litr_lig_c_col(j) + & - currentpatch%seed_decay(ft) * pftcon%lf_flig(ft) * currentpatch%area/AREA * leaf_prof(s,j) - ! - enddo - end do - - currentPatch => currentPatch%younger - end do !currentPatch - - end do ! do sites(s) - - do s = 1, nsites - do j = 1, cp_numlevdecomp - ! time unit conversion - bc_out(s)%FATES_c_to_litr_lab_c_col(j)=bc_out(s)%FATES_c_to_litr_lab_c_col(j) * mass_convert / time_convert - bc_out(s)%FATES_c_to_litr_cel_c_col(j)=bc_out(s)%FATES_c_to_litr_cel_c_col(j) * mass_convert / time_convert - bc_out(s)%FATES_c_to_litr_lig_c_col(j)=bc_out(s)%FATES_c_to_litr_lig_c_col(j) * mass_convert / time_convert - - end do - end do - - ! write(iulog,*)'cdk FATES_c_to_litr_lab_c: ', FATES_c_to_litr_lab_c - ! write_col(iulog,*)'cdk FATES_c_to_litr_cel_c: ', FATES_c_to_litr_cel_c - ! write_col(iulog,*)'cdk FATES_c_to_litr_lig_c: ', FATES_c_to_litr_lig_c - ! write_col(iulog,*)'cdk cp_numlevdecomp_full, bounds%begc, bounds%endc: ', cp_numlevdecomp_full, bounds%begc, bounds%endc - ! write(iulog,*)'cdk leaf_prof: ', leaf_prof - ! write(iulog,*)'cdk stem_prof: ', stem_prof - ! write(iulog,*)'cdk froot_prof: ', froot_prof - ! write(iulog,*)'cdk croot_prof_perpatch: ', croot_prof_perpatch - ! write(iulog,*)'cdk croot_prof: ', croot_prof - - end subroutine flux_into_litter_pools - -end module EDPhysiologyMod diff --git a/src/ED/biogeochem/EDSharedParamsMod.F90 b/src/ED/biogeochem/EDSharedParamsMod.F90 deleted file mode 100644 index c4111c124f..0000000000 --- a/src/ED/biogeochem/EDSharedParamsMod.F90 +++ /dev/null @@ -1,57 +0,0 @@ -module EDSharedParamsMod - - !----------------------------------------------------------------------- - ! - ! !USES: - use shr_kind_mod , only: r8 => shr_kind_r8 - implicit none - - ! EDParamsShareInst. PGI wants the type decl. public but the instance - ! is indeed protected. A generic private statement at the start of the module - ! overrides the protected functionality with PGI - - type, public :: EDParamsShareType - real(r8) :: Q10 ! temperature dependence - real(r8) :: froz_q10 ! separate q10 for frozen soil respiration rates - end type EDParamsShareType - - type(EDParamsShareType), protected :: EDParamsShareInst - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - - !----------------------------------------------------------------------- - -contains - - !----------------------------------------------------------------------- - subroutine EDParamsReadShared(ncid) - ! - use ncdio_pio , only : file_desc_t,ncd_io - use abortutils , only : endrun - use shr_log_mod , only : errMsg => shr_log_errMsg - ! - type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id - ! - character(len=32) :: subname = 'EDParamsReadShared' - character(len=100) :: errCode = '-Error reading in ED shared params file. Var:' - 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 - !----------------------------------------------------------------------- - ! - ! netcdf read here - ! - tString='q10_mr' - 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__)) - EDParamsShareInst%Q10=tempr - - tString='froz_q10' - call ncd_io(trim(tString),tempr, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) - EDParamsShareInst%froz_q10=tempr - - end subroutine EDParamsReadShared - -end module EDSharedParamsMod diff --git a/src/ED/biogeophys/EDAccumulateFluxesMod.F90 b/src/ED/biogeophys/EDAccumulateFluxesMod.F90 deleted file mode 100644 index f44a202954..0000000000 --- a/src/ED/biogeophys/EDAccumulateFluxesMod.F90 +++ /dev/null @@ -1,92 +0,0 @@ -module EDAccumulateFluxesMod - - !------------------------------------------------------------------------------ - ! !DESCRIPTION: - ! This routine accumulates NPP, GPP and respiration of each cohort over the course of each 24 hour period. - ! The fluxes are stored per cohort, and the npp_tstep (etc) fluxes are calcualted in EDPhotosynthesis - ! This routine cannot be in EDPhotosynthesis because EDPhotosynthesis is a loop and therefore would - ! erroneously add these things up multiple times. - ! Rosie Fisher. March 2014. - ! - ! !USES: - implicit none - private - ! - public :: AccumulateFluxes_ED - - logical :: DEBUG = .false. ! for debugging this module - !------------------------------------------------------------------------------ - -contains - - !------------------------------------------------------------------------------ - subroutine AccumulateFluxes_ED(nsites, sites, bc_in, bc_out) - ! - ! !DESCRIPTION: - ! see above - ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : iulog - use EDTypesMod , only : ed_patch_type, ed_cohort_type, ed_site_type - use FatesInterfaceMod , only : bc_in_type,bc_out_type - ! - ! !ARGUMENTS - integer, intent(in) :: nsites - type(ed_site_type), intent(inout), target :: sites(nsites) - type(bc_in_type), intent(in) :: bc_in(nsites) - type(bc_out_type), intent(inout) :: bc_out(nsites) - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type), pointer :: ccohort ! current cohort - type(ed_patch_type) , pointer :: cpatch ! current patch - integer :: iv !leaf layer - integer :: c ! clm/alm column - integer :: s ! ed site - integer :: ifp ! index fates patch - !---------------------------------------------------------------------- - - do s = 1, nsites - - ifp = 0 - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ifp = ifp+1 - - if( bc_in(s)%filter_photo_pa(ifp) == 3 ) then - ccohort => cpatch%shortest - do while(associated(ccohort)) - - ! Accumulate fluxes from hourly to daily values. - ! _tstep fluxes are KgC/indiv/timestep _acc are KgC/indiv/day - - if ( DEBUG ) then - write(iulog,*) 'EDAccumFlux 64 ',ccohort%npp_acc, & - ccohort%npp_tstep - write(iulog,*) 'EDAccumFlux 66 ',ccohort%gpp_tstep - write(iulog,*) 'EDAccumFlux 67 ',ccohort%resp_tstep - endif - - ccohort%npp_acc = ccohort%npp_acc + ccohort%npp_tstep - ccohort%gpp_acc = ccohort%gpp_acc + ccohort%gpp_tstep - ccohort%resp_acc = ccohort%resp_acc + ccohort%resp_tstep - - do iv=1,ccohort%nv - if(ccohort%year_net_uptake(iv) == 999._r8)then ! note that there were leaves in this layer this year. - ccohort%year_net_uptake(iv) = 0._r8 - end if - ccohort%year_net_uptake(iv) = ccohort%year_net_uptake(iv) + ccohort%ts_net_uptake(iv) - enddo - - ccohort => ccohort%taller - enddo ! while(associated(ccohort)) - end if - cpatch => cpatch%younger - end do ! while(associated(cpatch)) - end do - return - - end subroutine AccumulateFluxes_ED - -end module EDAccumulateFluxesMod - diff --git a/src/ED/biogeophys/EDBtranMod.F90 b/src/ED/biogeophys/EDBtranMod.F90 deleted file mode 100644 index 8ac4a51b36..0000000000 --- a/src/ED/biogeophys/EDBtranMod.F90 +++ /dev/null @@ -1,338 +0,0 @@ -module EDBtranMod - - !------------------------------------------------------------------------------------- - ! Description: - ! - ! ------------------------------------------------------------------------------------ - - use pftconMod , only : pftcon - use clm_varcon , only : tfrz - use EDTypesMod , only : ed_site_type, & - ed_patch_type, & - ed_cohort_type, & - numpft_ed, & - cp_numlevgrnd - use shr_kind_mod , only : r8 => shr_kind_r8 - use FatesInterfaceMod , only : bc_in_type, & - bc_out_type - use clm_varctl , only : iulog !INTERF-TODO: THIS SHOULD BE MOVED - - ! - implicit none - private - - public :: btran_ed - public :: get_active_suction_layers - -contains - - ! ==================================================================================== - - logical function check_layer_water(h2o_liq_vol, tempk) - - implicit none - ! Arguments - real(r8),intent(in) :: h2o_liq_vol - real(r8),intent(in) :: tempk - - check_layer_water = .false. - - if ( h2o_liq_vol .gt. 0._r8 ) then - if ( tempk .gt. tfrz-2._r8) then - check_layer_water = .true. - end if - end if - return - end function check_layer_water - - ! ===================================================================================== - - subroutine get_active_suction_layers(nsites, sites, bc_in, bc_out) - - ! Arguments - - integer,intent(in) :: nsites - type(ed_site_type),intent(inout),target :: sites(nsites) - type(bc_in_type),intent(in) :: bc_in(nsites) - type(bc_out_type),intent(inout) :: bc_out(nsites) - - ! !LOCAL VARIABLES: - integer :: s ! site - integer :: j ! soil layer - !------------------------------------------------------------------------------ - - do s = 1,nsites - if (bc_in(s)%filter_btran) then - do j = 1,cp_numlevgrnd - bc_out(s)%active_suction_gl(j) = check_layer_water( bc_in(s)%h2o_liqvol_gl(j),bc_in(s)%tempk_gl(j) ) - end do - else - bc_out(s)%active_suction_gl(:) = .false. - end if - end do - - end subroutine get_active_suction_layers - - ! ===================================================================================== - - subroutine btran_ed( nsites, sites, bc_in, bc_out) - - ! --------------------------------------------------------------------------------- - ! Calculate the transpiration wetness function (BTRAN) and the root uptake - ! distribution (ROOTR). - ! Boundary conditions in: bc_in(s)%eff_porosity_gl(j) unfrozen porosity - ! bc_in(s)%watsat_gl(j) porosity - ! bc_in(s)%active_uptake_gl(j) frozen/not frozen - ! bc_in(s)%smp_gl(j) suction - ! Boundary conditions out: bc_out(s)%rootr_pagl root uptake distribution - ! bc_out(s)%btran_pa wetness factor - ! --------------------------------------------------------------------------------- - - ! Arguments - - integer,intent(in) :: nsites - type(ed_site_type),intent(inout),target :: sites(nsites) - type(bc_in_type),intent(in) :: bc_in(nsites) - type(bc_out_type),intent(inout) :: bc_out(nsites) - - ! - ! !LOCAL VARIABLES: - type(ed_patch_type),pointer :: cpatch ! Current Patch Pointer - type(ed_cohort_type),pointer :: ccohort ! Current cohort pointer - integer :: s ! site - integer :: j ! soil layer - integer :: ifp ! patch vector index for the site - integer :: ft ! plant functional type index - real(r8) :: smp_node ! matrix potential - real(r8) :: rresis ! suction limitation to transpiration independent - ! of root density - real(r8) :: pftgs(numpft_ed) ! pft weighted stomatal conductance s/m - real(r8) :: temprootr - !------------------------------------------------------------------------------ - - associate( & - smpsc => pftcon%smpsc , & ! INTERF-TODO: THESE SHOULD BE FATES PARAMETERS - smpso => pftcon%smpso & ! INTERF-TODO: THESE SHOULD BE FATES PARAMETERS - ) - - do s = 1,nsites - - bc_out(s)%rootr_pagl(:,:) = 0._r8 - - ifp = 0 - cpatch => sites(s)%oldest_patch - do while (associated(cpatch)) - ifp=ifp+1 - - ! THIS SHOULD REALLY BE A COHORT LOOP ONCE WE HAVE rootfr_ft FOR COHORTS (RGK) - - do ft = 1,numpft_ed - cpatch%btran_ft(ft) = 0.0_r8 - do j = 1,cp_numlevgrnd - - ! Calculations are only relevant where liquid water exists - ! see clm_fates%wrap_btran for calculation with CLM/ALM - - if ( check_layer_water(bc_in(s)%h2o_liqvol_gl(j),bc_in(s)%tempk_gl(j)) ) then - - smp_node = max(smpsc(ft), bc_in(s)%smp_gl(j)) - - rresis = min( (bc_in(s)%eff_porosity_gl(j)/bc_in(s)%watsat_gl(j))* & - (smp_node - smpsc(ft)) / (smpso(ft) - smpsc(ft)), 1._r8) - - cpatch%rootr_ft(ft,j) = cpatch%rootfr_ft(ft,j)*rresis - - ! root water uptake is not linearly proportional to root density, - ! to allow proper deep root funciton. Replace with equations from SPA/Newman. FIX(RF,032414) - ! cpatch%rootr_ft(ft,j) = cpatch%rootfr_ft(ft,j)**0.3*rresis_ft(ft,j)/ & - ! sum(cpatch%rootfr_ft(ft,1:nlevgrnd)**0.3) - cpatch%btran_ft(ft) = cpatch%btran_ft(ft) + cpatch%rootr_ft(ft,j) - - else - cpatch%rootr_ft(ft,j) = 0._r8 - end if - - end do !j - - ! Normalize root resistances to get layer contribution to ET - do j = 1,cp_numlevgrnd - if (cpatch%btran_ft(ft) > 0.0_r8) then - cpatch%rootr_ft(ft,j) = cpatch%rootr_ft(ft,j)/cpatch%btran_ft(ft) - else - cpatch%rootr_ft(ft,j) = 0._r8 - end if - end do - - end do !PFT - - ! PFT-averaged point level root fraction for extraction purposese. - ! This probably needs to be weighted by actual transpiration from each pft. FIX(RF,032414). - pftgs(:) = 0._r8 - ccohort => cpatch%tallest - do while(associated(ccohort)) - pftgs(ccohort%pft) = pftgs(ccohort%pft) + ccohort%gscan * ccohort%n - ccohort => ccohort%shorter - enddo - - ! Process the boundary output, this is necessary for calculating the soil-moisture - ! sink term across the different layers in driver/host. Photosynthesis will - ! pass the host a total transpiration for the patch. This needs rootr to be - ! distributed over the soil layers. - - do j = 1,cp_numlevgrnd - bc_out(s)%rootr_pagl(ifp,j) = 0._r8 - do ft = 1,numpft_ed - if(sum(pftgs) > 0._r8)then !prevent problem with the first timestep - might fail - !bit-retart test as a result? FIX(RF,032414) - bc_out(s)%rootr_pagl(ifp,j) = bc_out(s)%rootr_pagl(ifp,j) + & - cpatch%rootr_ft(ft,j) * pftgs(ft)/sum(pftgs) - else - bc_out(s)%rootr_pagl(ifp,j) = bc_out(s)%rootr_pagl(ifp,j) + & - cpatch%rootr_ft(ft,j) * 1./numpft_ed - end if - enddo - enddo - - !weight patch level output BTRAN for the - bc_out(s)%btran_pa(ifp) = 0.0_r8 - do ft = 1,numpft_ed - if(sum(pftgs) > 0._r8)then !prevent problem with the first timestep - might fail - !bit-retart test as a result? FIX(RF,032414) - bc_out(s)%btran_pa(ifp) = bc_out(s)%btran_pa(ifp) + cpatch%btran_ft(ft) * pftgs(ft)/sum(pftgs) - else - bc_out(s)%btran_pa(ifp) = bc_out(s)%btran_pa(ifp) + cpatch%btran_ft(ft) * 1./numpft_ed - end if - enddo - - temprootr = sum(bc_out(s)%rootr_pagl(ifp,:)) - if(abs(1.0_r8-temprootr) > 1.0e-10_r8 .and. temprootr > 1.0e-10_r8)then - write(iulog,*) 'error with rootr in canopy fluxes',temprootr,sum(pftgs),sum(cpatch%rootr_ft(1:2,:),dim=2) - do j = 1,cp_numlevgrnd - bc_out(s)%rootr_pagl(ifp,j) = bc_out(s)%rootr_pagl(ifp,j)/temprootr - enddo - end if - - cpatch => cpatch%younger - end do - - - end do - - end associate - - end subroutine btran_ed - - ! ========================================================================================= - - !--------------------------------------------------------------------------------------- - ! SPA based recalculation of BTRAN and water uptake. - !--------------------------------------------------------------------------------------- - -! if (SPA_soil) then ! normal case don't run this. -! rootr(p,:) = 0._r8 -! do FT = 1,numpft_ed - -! ! Soil Physics -! do j = 1,nlevgrnd -! ! CLM water retention curve. Clapp and Hornberger equation. -! s1 = max(h2osoi_vol(c,j)/watsat(c,j), 0.01_r8) -! s1 = min(1.0_r8,s1) -! smp_node = -sucsat(c,j)*s1**(-bsw(c,j)) -! swp_mpa(j) = smp_node *10.0_r8/1000000.0_r8 !convert from mm to Mpa - -! ! CLM hydraulic conductivity curve. -! ! As opposed to the Richard's equation solution in SoilHydrology.Mod -! ! the conductivity here is defined in the middle of the layer in question, not at the edge... -! xksat = 0.0070556_r8 * (10._r8**(-0.884_r8+0.0153_r8*sand(p)) ) -! hk(j) = xksat*s1**(2._r8*bsw(c,j)+2._r8) !removed the ice from here to avoid 1st ts crashing -! enddo - -! ! Root resistance -! rootxsecarea=3.14159*rootrad**2 -! do j = 1,nlevgrnd -! rootmass(j) = EDecophyscon%soilbeta(FT) * cpatch%rootfr_ft(FT,j) -! rootlength(j) = rootmass(j)/(rootdens*rootxsecarea) !m m-3 soil -! Lsoil(j) = hk(j)/1000/head !converts from mms-1 to ms-1 and then to m2 s-1 MPa-1 -! if(Lsoil(j) < 1e-35_r8.or.cpatch%rootfr_ft(ft,j) <= 0.0_r8)then !prevent floating point error -! soilr_z(j) = 1e35_r8 -! soilr2(j) = 1e35_r8 -! else -! ! Soil-to-root water uptake from Newman (1969). -! rs = sqrt (1._r8 / (rootlength(j) * pi)) -! soilr1(j) = log(rs/rootrad) / (2.0_r8 * pi * rootlength(j) * Lsoil(j) * dz(c,j)) -! ! convert from MPa s m2 m-3 to MPa s m2 mmol-1 -! soilr1(j) = soilr1(j) * 1E-6_r8 * 18_r8 * 0.001_r8 -! ! second component of below ground resistance is related to root hydraulics -! soilr2(j) = EDecophyscon%rootresist(FT)/(rootmass(j)*dz(c,j)) -! soilr_z(j) = soilr1(j)+soilr2(j) -! end if -! enddo - - ! Aggregate soil layers -! totestevap=0._r8 -! weighted_SWP=0._r8 -! estevap=0._r8 -! fraction_uptake=0._r8 -! canopy_soil_resistance=0._r8 !Reset Counters -! totmaxevap = 0._r8 - - ! Estimated max transpiration from LWP gradient / soil resistance -! do j = 1,nlevgrnd -! estevap(j) = (swp_mpa(j) - minlwp)/(soilr_z(j)) -! estevap(j) = max(0._r8,estevap(j)) ! no negative uptake -! maxevap(j) = (0.0_r8 - minlwp)/(soilr2(j)) -! enddo -! totestevap = sum(estevap) -! totmaxevap = sum(maxevap) - - ! Weighted soil water potential -! do j = 1,nlevgrnd -! if(totestevap > 0._r8)then -! fraction_uptake(j) = estevap(j)/totestevap !Fraction of total ET taken from this soil layer -! else -! estevap(j) = 0._r8 -! fraction_uptake(j)=1._r8/nlevgrnd -! end if -! weighted_SWP = weighted_SWP + swp_mpa(j) * estevap(j) -! enddo - -! if(totestevap > 0._r8)then -! weighted_swp = weighted_swp/totestevap -! ! weight SWP for the total evaporation -! else -! write(iulog,*) 'empty soil', totestevap -! ! error check -! weighted_swp = minlwp -! end if - - ! Weighted soil-root resistance. Aggregate the conductances (1/soilR) for each soil layer -! do iv = 1,nv !leaf layers -! fleaf = 1.0_r8/nv -! do j = 1,nlevgrnd !root layers -! ! Soil resistance for each canopy layer is related to leaf area -! ! The conductance of the root system to the -! ! whole canopy is reduced by the fraction of leaves in this layer... -! canopy_soil_resistance(iv) = canopy_soil_resistance(iv)+fleaf * 1.0_r8/(soilr_z(j)) -! enddo -! ! Turn aggregated conductance back into resistance. mmol MPa-1 s-1 m-2 to MPa s m2 mmol-1 -! canopy_soil_resistance(iv) = 1./canopy_soil_resistance(iv) -! enddo -! -! cpatch%btran_ft(FT) = totestevap/totmaxevap -! do j = 1,nlevgrnd -! if(sum(pftgs) > 0._r8)then !prevent problem with the first timestep - might fail -! !bit-retart test as a result? FIX(RF,032414) -! rootr(p,j) = rootr(p,j) + fraction_uptake(j) * pftgs(ft)/sum(pftgs) -! else -! rootr(p,j) = rootr(p,j) + fraction_uptake(j) * 1./numpft_ed -! end if -! enddo -! enddo !pft loop -! end if ! - !--------------------------------------------------------------------------------------- - ! end of SPA based recalculation of BTRAN and water uptake. - !--------------------------------------------------------------------------------------- - - - -end module EDBtranMod diff --git a/src/ED/biogeophys/EDPhotosynthesisMod.F90 b/src/ED/biogeophys/EDPhotosynthesisMod.F90 deleted file mode 100644 index ecad435267..0000000000 --- a/src/ED/biogeophys/EDPhotosynthesisMod.F90 +++ /dev/null @@ -1,1124 +0,0 @@ -module EDPhotosynthesisMod - - !------------------------------------------------------------------------------ - ! !DESCRIPTION: - ! Calculates the photosynthetic fluxes for the ED model - ! This code is equivalent to the 'photosynthesis' subroutine in PhotosynthesisMod.F90. - ! We have split this out to reduce merge conflicts until we can pull out - ! common code used in both the ED and CLM versions. - ! - ! !USES: - ! - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use abortutils , only : endrun - use clm_varctl , only : iulog - implicit none - private - ! - - - - ! PUBLIC MEMBER FUNCTIONS: - public :: Photosynthesis_ED !ED specific photosynthesis routine - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - !------------------------------------------------------------------------------ - -contains - - !--------------------------------------------------------- - subroutine Photosynthesis_ED (nsites, sites,bc_in,bc_out,dtime) - - - ! - ! !DESCRIPTION: - ! Leaf photosynthesis and stomatal conductance calculation as described by - ! Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 and extended to - ! a multi-layer canopy - ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use abortutils , only : endrun - use clm_varcon , only : rgas, tfrz, namep - use clm_varpar , only : nlevsoi, mxpft - use clm_varctl , only : iulog - use pftconMod , only : pftcon - use EDParamsMod , only : ED_val_grperc - use EDSharedParamsMod , only : EDParamsShareInst - use EDTypesMod , only : numpft_ed, dinc_ed - use EDtypesMod , only : ed_patch_type, ed_cohort_type, ed_site_type, numpft_ed - use EDEcophysContype , only : EDecophyscon - use FatesInterfaceMod , only : bc_in_type,bc_out_type - use EDtypesMod , only : numpatchespercol, cp_nlevcan, cp_nclmax - use EDCanopyStructureMod,only: calc_areaindex - - - ! - ! !ARGUMENTS: - integer,intent(in) :: nsites - type(ed_site_type),intent(inout),target :: sites(nsites) - type(bc_in_type),intent(in) :: bc_in(nsites) - type(bc_out_type),intent(inout) :: bc_out(nsites) - real(r8),intent(in) :: dtime - - ! - ! !CALLED FROM: - ! subroutine CanopyFluxes - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort - ! - integer , parameter :: psn_type = 2 !c3 or c4. - - logical :: DEBUG = .false. - - ! - ! Leaf photosynthesis parameters - real(r8) :: vcmax_z(cp_nclmax,mxpft,cp_nlevcan) ! maximum rate of carboxylation (umol co2/m**2/s) - real(r8) :: jmax_z(cp_nclmax,mxpft,cp_nlevcan) ! maximum electron transport rate (umol electrons/m**2/s) - real(r8) :: tpu_z(cp_nclmax,mxpft,cp_nlevcan) ! triose phosphate utilization rate (umol CO2/m**2/s) - real(r8) :: kp_z(cp_nclmax,mxpft,cp_nlevcan) ! initial slope of CO2 response curve (C4 plants) - real(r8) :: lmr_z(cp_nclmax,mxpft,cp_nlevcan) ! initial slope of CO2 response curve (C4 plants) - real(r8) :: rs_z(cp_nclmax,mxpft,cp_nlevcan) ! stomatal resistance s/m - real(r8) :: gs_z(cp_nclmax,mxpft,cp_nlevcan) ! stomatal conductance m/s - - real(r8) :: ci(cp_nclmax,mxpft,cp_nlevcan) ! intracellular leaf CO2 (Pa) - real(r8) :: lnc(mxpft) ! leaf N concentration (gN leaf/m^2) - - real(r8) :: kc( numpatchespercol ) ! Michaelis-Menten constant for CO2 (Pa) - real(r8) :: ko( numpatchespercol ) ! Michaelis-Menten constant for O2 (Pa) - real(r8) :: co2_cp( numpatchespercol ) ! CO2 compensation point (Pa) - - ! --------------------------------------------------------------- - ! TO-DO: bbbopt is slated to be transferred to the parameter file - ! ---------------------------------------------------------------- - real(r8) :: bbbopt(psn_type) ! Ball-Berry minimum leaf conductance, unstressed (umol H2O/m**2/s) - real(r8) :: bbb(mxpft) ! Ball-Berry minimum leaf conductance (umol H2O/m**2/s) - - real(r8) :: kn(mxpft) ! leaf nitrogen decay coefficient - real(r8) :: vcmax25top(mxpft) ! canopy top: maximum rate of carboxylation at 25C (umol CO2/m**2/s) - real(r8) :: jmax25top(mxpft) ! canopy top: maximum electron transport rate at 25C (umol electrons/m**2/s) - real(r8) :: tpu25top(mxpft) ! canopy top: triose phosphate utilization rate at 25C (umol CO2/m**2/s) - real(r8) :: lmr25top(mxpft) ! canopy top: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) - real(r8) :: kp25top(mxpft) ! canopy top: initial slope of CO2 response curve (C4 plants) at 25C - - real(r8) :: vcmax25 ! leaf layer: maximum rate of carboxylation at 25C (umol CO2/m**2/s) - real(r8) :: jmax25 ! leaf layer: maximum electron transport rate at 25C (umol electrons/m**2/s) - real(r8) :: tpu25 ! leaf layer: triose phosphate utilization rate at 25C (umol CO2/m**2/s) - real(r8) :: lmr25 ! leaf layer: leaf maintenance respiration rate at 25C (umol CO2/m**2/s) - real(r8) :: kp25 ! leaf layer: Initial slope of CO2 response curve (C4 plants) at 25C - real(r8) :: kc25 ! Michaelis-Menten constant for CO2 at 25C (Pa) - real(r8) :: ko25 ! Michaelis-Menten constant for O2 at 25C (Pa) - real(r8) :: cp25 ! CO2 compensation point at 25C (Pa) - - real(r8) :: vcmaxha ! activation energy for vcmax (J/mol) - real(r8) :: jmaxha ! activation energy for jmax (J/mol) - real(r8) :: tpuha ! activation energy for tpu (J/mol) - real(r8) :: lmrha ! activation energy for lmr (J/mol) - real(r8) :: kcha ! activation energy for kc (J/mol) - real(r8) :: koha ! activation energy for ko (J/mol) - real(r8) :: cpha ! activation energy for cp (J/mol) - - real(r8) :: vcmaxhd ! deactivation energy for vcmax (J/mol) - real(r8) :: jmaxhd ! deactivation energy for jmax (J/mol) - real(r8) :: tpuhd ! deactivation energy for tpu (J/mol) - real(r8) :: lmrhd ! deactivation energy for lmr (J/mol) - - real(r8) :: vcmaxse ! entropy term for vcmax (J/mol/K) - real(r8) :: jmaxse ! entropy term for jmax (J/mol/K) - real(r8) :: tpuse ! entropy term for tpu (J/mol/K) - real(r8) :: lmrse ! entropy term for lmr (J/mol/K) - - real(r8) :: vcmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) - real(r8) :: jmaxc ! scaling factor for high temperature inhibition (25 C = 1.0) - real(r8) :: tpuc ! scaling factor for high temperature inhibition (25 C = 1.0) - real(r8) :: lmrc ! scaling factor for high temperature inhibition (25 C = 1.0) - - real(r8) :: qe(psn_type) ! quantum efficiency, used only for C4 (mol CO2 / mol photons) - real(r8) :: fnps ! fraction of light absorbed by non-photosynthetic pigments - real(r8) :: theta_psii ! empirical curvature parameter for electron transport rate - - real(r8) :: theta_cj(psn_type) ! empirical curvature parameter for ac, aj photosynthesis co-limitation - real(r8) :: theta_ip ! empirical curvature parameter for ap photosynthesis co-limitation - - ! Other - integer :: c,CL,f,s,iv,j,ps,ft,ifp ! indices - integer :: NCL_p ! number of canopy layers in patch - real(r8) :: cf ! s m**2/umol -> s/m - real(r8) :: rsmax0 ! maximum stomatal resistance [s/m] - real(r8) :: gb ! leaf boundary layer conductance (m/s) - real(r8) :: gb_mol ! leaf boundary layer conductance (umol H2O/m**2/s) - real(r8) :: cs ! CO2 partial pressure at leaf surface (Pa) - real(r8) :: gs_mol ! leaf stomatal conductance (umol H2O/m**2/s) - real(r8) :: gs ! leaf stomatal conductance (m/s) - real(r8) :: hs ! fractional humidity at leaf surface (dimensionless) - real(r8) :: sco ! relative specificity of rubisco - real(r8) :: tl ! leaf temperature in photosynthesis temperature function (K) - real(r8) :: ha ! activation energy in photosynthesis temperature function (J/mol) - real(r8) :: hd ! deactivation energy in photosynthesis temperature function (J/mol) - real(r8) :: se ! entropy term in photosynthesis temperature function (J/mol/K) - real(r8) :: cc2 ! scaling factor for high temperature inhibition (25 C = 1.0) - real(r8) :: ciold ! previous value of Ci for convergence check - real(r8) :: gs_mol_err ! gs_mol for error check - real(r8) :: je ! electron transport rate (umol electrons/m**2/s) - real(r8) :: qabs ! PAR absorbed by PS II (umol photons/m**2/s) - real(r8) :: aquad,bquad,cquad ! terms for quadratic equations - real(r8) :: r1,r2 ! roots of quadratic equation - real(r8) :: ceair ! vapor pressure of air, constrained (Pa) - real(r8) :: act25 ! (umol/mgRubisco/min) Rubisco activity at 25 C - integer :: niter ! iteration loop index - real(r8) :: nscaler ! leaf nitrogen scaling coefficient - real(r8) :: leaf_frac ! ratio of to leaf biomass to total alive biomass - - real(r8) :: ac ! Rubisco-limited gross photosynthesis (umol CO2/m**2/s) - real(r8) :: aj ! RuBP-limited gross photosynthesis (umol CO2/m**2/s) - real(r8) :: ap ! product-limited (C3) or CO2-limited (C4) gross photosynthesis (umol CO2/m**2/s) - real(r8) :: ag(cp_nclmax,mxpft,cp_nlevcan) ! co-limited gross leaf photosynthesis (umol CO2/m**2/s) - real(r8) :: an(cp_nclmax,mxpft,cp_nlevcan) ! net leaf photosynthesis (umol CO2/m**2/s) - real(r8) :: an_av(cp_nclmax,mxpft,cp_nlevcan) ! net leaf photosynthesis (umol CO2/m**2/s) averaged over sun and shade leaves. - real(r8) :: ai ! intermediate co-limited photosynthesis (umol CO2/m**2/s) - - real(r8) :: laican ! canopy sum of lai_z - real(r8) :: vai ! leaf and steam area in ths layer. - integer :: exitloop - real(r8) :: laifrac - real(r8) :: tcsoi ! Temperature response function for root respiration. - real(r8) :: tc ! Temperature response function for wood - - real(r8) :: br ! Base rate of root respiration. (gC/gN/s) - real(r8) :: q10 ! temperature dependence of root respiration - integer :: sunsha ! sun (1) or shaded (2) leaves... - real(r8) :: dr(2) - real(r8) :: coarse_wood_frac ! amount of woody biomass that is coarse... - real(r8) :: tree_area - real(r8) :: gs_cohort - real(r8) :: rscanopy - real(r8) :: elai - - associate( & - c3psn => pftcon%c3psn , & ! photosynthetic pathway: 0. = c4, 1. = c3 - slatop => pftcon%slatop , & ! specific leaf area at top of canopy, projected area basis [m^2/gC] - flnr => pftcon%flnr , & ! fraction of leaf N in the Rubisco enzyme (gN Rubisco / gN leaf) - woody => pftcon%woody , & ! Is vegetation woody or not? - fnitr => pftcon%fnitr , & ! foliage nitrogen limitation factor (-) - leafcn => pftcon%leafcn , & ! leaf C:N (gC/gN) - bb_slope => EDecophyscon%BB_slope ) ! slope of BB relationship - - ! Assign local pointers to derived type members (gridcell-level) - dr(1) = 0.025_r8; dr(2) = 0.015_r8 - - ! Peter Thornton: 3/13/09 - ! Q10 was originally set to 2.0, an arbitrary choice, but reduced to 1.5 as part of the tuning - ! to improve seasonal cycle of atmospheric CO2 concentration in global - ! simulatoins - q10 = 1.5_r8 - Q10 = EDParamsShareInst%Q10 - - !==============================================================================! - ! Photosynthesis and stomatal conductance parameters, from: - ! Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 - !==============================================================================! - - ! vcmax25 parameters, from CN - - act25 = 3.6_r8 !umol/mgRubisco/min - ! Convert rubisco activity units from umol/mgRubisco/min -> umol/gRubisco/s - act25 = act25 * 1000.0_r8 / 60.0_r8 - - ! Activation energy, from: - ! Bernacchi et al (2001) Plant, Cell and Environment 24:253-259 - ! Bernacchi et al (2003) Plant, Cell and Environment 26:1419-1430 - ! except TPU from: Harley et al (1992) Plant, Cell and Environment 15:271-282 - - kcha = 79430._r8 - koha = 36380._r8 - cpha = 37830._r8 - vcmaxha = 65330._r8 - jmaxha = 43540._r8 - tpuha = 53100._r8 - lmrha = 46390._r8 - - ! High temperature deactivation, from: - ! Leuning (2002) Plant, Cell and Environment 25:1205-1210 - ! The factor "c" scales the deactivation to a value of 1.0 at 25C - - vcmaxhd = 149250._r8 - jmaxhd = 152040._r8 - tpuhd = 150650._r8 - lmrhd = 150650._r8 - - vcmaxse = 485._r8 - jmaxse = 495._r8 - tpuse = 490._r8 - lmrse = 490._r8 - - vcmaxc = fth25_f(vcmaxhd, vcmaxse) - jmaxc = fth25_f(jmaxhd, jmaxse) - tpuc = fth25_f(tpuhd, tpuse) - lmrc = fth25_f(lmrhd, lmrse) - - ! Miscellaneous parameters, from Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 - - fnps = 0.15_r8 - theta_psii = 0.7_r8 - theta_ip = 0.95_r8 - - qe(1) = 0._r8 - theta_cj(1) = 0.98_r8 - bbbopt(1) = 10000._r8 - - qe(2) = 0.05_r8 - theta_cj(2) = 0.80_r8 - bbbopt(2) = 40000._r8 - - do s = 1,nsites - - ifp = 0 - currentpatch => sites(s)%oldest_patch - do while (associated(currentpatch)) - ifp = ifp+1 - - bc_out(s)%psncanopy_pa(ifp) = 0._r8 - bc_out(s)%lmrcanopy_pa(ifp) = 0._r8 - bc_out(s)%rssun_pa(ifp) = 0._r8 - bc_out(s)%rssha_pa(ifp) = 0._r8 - bc_out(s)%gccanopy_pa(ifp) = 0._r8 - - ! Patch level filter flag for photosynthesis calculations - ! has a short memory, flags: - ! 1 = patch has not been called - ! 2 = patch is currently marked for photosynthesis - ! 3 = patch has been called for photosynthesis at least once - if(bc_in(s)%filter_photo_pa(ifp)==2)then - - currentPatch%ncan(:,:) = 0 - !redo the canopy structure algorithm to get round a bug that is happening for site 125, FT13. - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - - currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft) = & - max(currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft),currentCohort%NV) - - currentCohort => currentCohort%shorter - - enddo !cohort - - currentPatch%nrad = currentPatch%ncan - do CL = 1,cp_nclmax - do ft = 1,numpft_ed - currentPatch%present(CL,ft) = 0 - do iv = 1, currentPatch%nrad(CL,ft); - if(currentPatch%canopy_area_profile(CL,ft,iv) > 0._r8)then - currentPatch%present(CL,ft) = 1 - end if - end do !iv - enddo !ft - enddo !CL - - - ! kc, ko, currentPatch, from: Bernacchi et al (2001) Plant, Cell and Environment 24:253-259 - ! - ! kc25 = 404.9 umol/mol - ! ko25 = 278.4 mmol/mol - ! cp25 = 42.75 umol/mol - ! - ! Derive sco from currentPatch and O2 using present-day O2 (0.209 mol/mol) and re-calculate - ! currentPatch to account for variation in O2 using currentPatch = 0.5 O2 / sco - ! - - kc25 = (404.9_r8 / 1.e06_r8) * bc_in(s)%forc_pbot - ko25 = (278.4_r8 / 1.e03_r8) * bc_in(s)%forc_pbot - sco = 0.5_r8 * 0.209_r8 / (42.75_r8 / 1.e06_r8) - cp25 = 0.5_r8 * bc_in(s)%oair_pa(ifp) / sco - - if(bc_in(s)%t_veg_pa(ifp).gt.150_r8.and.bc_in(s)%t_veg_pa(ifp).lt.350_r8)then - kc(ifp) = kc25 * ft1_f(bc_in(s)%t_veg_pa(ifp), kcha) - ko(ifp) = ko25 * ft1_f(bc_in(s)%t_veg_pa(ifp), koha) - co2_cp(ifp) = cp25 * ft1_f(bc_in(s)%t_veg_pa(ifp), cpha) - else - kc(ifp) = 1 - ko(ifp) = 1 - co2_cp(ifp) = 1 - end if - - end if - - currentpatch => currentpatch%younger - end do - - ! Multi-layer parameters scaled by leaf nitrogen profile. - ! Loop through each canopy layer to calculate nitrogen profile using - ! cumulative lai at the midpoint of the layer - - ifp = 0 - currentpatch => sites(s)%oldest_patch - do while (associated(currentpatch)) - ifp = ifp+1 - - if(bc_in(s)%filter_photo_pa(ifp)==2)then - - NCL_p = currentPatch%NCL_p - - do FT = 1,numpft_ed !calculate patch and pft specific propserties at canopy top. - - if (nint(c3psn(FT)) == 1)then - ps = 1 - else - ps = 2 - end if - bbb(FT) = max (bbbopt(ps)*currentPatch%btran_ft(FT), 1._r8) - - ! THIS CALL APPEARS TO BE REDUNDANT WITH LINE 650 (RGK) - if (nint(c3psn(FT)) == 1)then - ci(:,FT,:) = 0.7_r8 * bc_in(s)%cair_pa(ifp) - else - ci(:,FT,:) = 0.4_r8 * bc_in(s)%cair_pa(ifp) - end if - - - ! Leaf nitrogen concentration at the top of the canopy (g N leaf / m**2 leaf) - lnc(FT) = 1._r8 / (slatop(FT) * leafcn(FT)) - - !at the moment in ED we assume that there is no active N cycle. This should change, of course. FIX(RF,032414) Sep2011. - vcmax25top(FT) = fnitr(FT) !fudge - shortcut using fnitr as a proxy for vcmax... - - ! Parameters derived from vcmax25top. Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 - ! used jmax25 = 1.97 vcmax25, from Wullschleger (1993) Journal of Experimental Botany 44:907-920. - ! Here use a factor "1.67", from Medlyn et al (2002) Plant, Cell and Environment 25:1167-1179 - - !RF - copied this from the CLM trunk code, but where did it come from, and how can we make these consistant? - !jmax25top(FT) = (2.59_r8 - 0.035_r8*min(max((t10(p)-tfrz),11._r8),35._r8)) * vcmax25top(FT) - - jmax25top(FT) = 1.67_r8 * vcmax25top(FT) - tpu25top(FT) = 0.167_r8 * vcmax25top(FT) - kp25top(FT) = 20000._r8 * vcmax25top(FT) - - ! Nitrogen scaling factor. Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 used - ! kn = 0.11. Here, derive kn from vcmax25 as in Lloyd et al (2010) Biogeosciences, 7, 1833-1859 - ! Remove daylength factor from vcmax25 so that kn is based on maximum vcmax25 - - if (bc_in(s)%dayl_factor_pa(ifp) == 0._r8) then - kn(FT) = 0._r8 - else - kn(FT) = exp(0.00963_r8 * vcmax25top(FT) - 2.43_r8) - end if - - ! Leaf maintenance respiration to match the base rate used in CN - ! but with the new temperature functions for C3 and C4 plants. - ! - ! Base rate for maintenance respiration is from: - ! M. Ryan, 1991. Effects of climate change on plant respiration. - ! Ecological Applications, 1(2), 157-167. - ! Original expression is br = 0.0106 molC/(molN h) - ! Conversion by molecular weights of C and N gives 2.525e-6 gC/(gN s) - ! - ! Base rate is at 20C. Adjust to 25C using the CN Q10 = 1.5 - ! - ! CN respiration has units: g C / g N [leaf] / s. This needs to be - ! converted from g C / g N [leaf] / s to umol CO2 / m**2 [leaf] / s - ! - ! Then scale this value at the top of the canopy for canopy depth - - lmr25top(FT) = 2.525e-6_r8 * (1.5_r8 ** ((25._r8 - 20._r8)/10._r8)) - lmr25top(FT) = lmr25top(FT) * lnc(FT) / 12.e-06_r8 - - end do !FT - - !==============================================================================! - ! Calculate Nitrogen scaling factors and photosynthetic parameters. - !==============================================================================! - do CL = 1, NCL_p - do FT = 1,numpft_ed - - do iv = 1, currentPatch%nrad(CL,FT) - if(currentPatch%canopy_area_profile(CL,FT,iv)>0._r8.and.currentPatch%present(CL,FT) /= 1)then - write(iulog,*) 'CF: issue with present structure',CL,FT,iv, & - currentPatch%canopy_area_profile(CL,FT,iv),currentPatch%present(CL,FT), & - currentPatch%nrad(CL,FT),currentPatch%ncl_p,cp_nclmax - currentPatch%present(CL,FT) = 1 - end if - enddo - - if(currentPatch%present(CL,FT) == 1)then ! are there any leaves of this pft in this layer? - - if(CL==NCL_p)then !are we in the top canopy layer or a shaded layer? - laican = 0._r8 - else - laican = sum(currentPatch%canopy_layer_lai(CL+1:NCL_p)) - end if - - ! Loop through canopy layers (above snow). Respiration needs to be - ! calculated every timestep. Others are calculated only if daytime - do iv = 1, currentPatch%nrad(CL,FT) - vai = (currentPatch%elai_profile(CL,FT,iv)+currentPatch%esai_profile(CL,FT,iv)) !vegetation area index. - if (iv == 1) then - laican = laican + 0.5_r8 * vai - else - laican = laican + 0.5_r8 * (currentPatch%elai_profile(CL,FT,iv-1)+ & - currentPatch%esai_profile(CL,FT,iv-1))+vai - end if - - ! Scale for leaf nitrogen profile - nscaler = exp(-kn(FT) * laican) - - - ! Maintenance respiration: umol CO2 / m**2 [leaf] / s - lmr25 = lmr25top(FT) * nscaler - - if (nint(c3psn(FT)) == 1)then - lmr_z(CL,FT,iv) = lmr25 * ft1_f(bc_in(s)%t_veg_pa(ifp), lmrha) * & - fth_f(bc_in(s)%t_veg_pa(ifp), lmrhd, lmrse, lmrc) - else - lmr_z(CL,FT,iv) = lmr25 * 2._r8**((bc_in(s)%t_veg_pa(ifp)-(tfrz+25._r8))/10._r8) - lmr_z(CL,FT,iv) = lmr_z(CL,FT,iv) / (1._r8 + exp( 1.3_r8*(bc_in(s)%t_veg_pa(ifp)-(tfrz+55._r8)) )) - end if - - if (currentPatch%ed_parsun_z(CL,FT,iv) <= 0._r8) then ! night time - vcmax_z(CL,FT,iv) = 0._r8 - jmax_z(CL,FT,iv) = 0._r8 - tpu_z(CL,FT,iv) = 0._r8 - kp_z(CL,FT,iv) = 0._r8 - else ! day time - vcmax25 = vcmax25top(FT) * nscaler - jmax25 = jmax25top(FT) * nscaler - tpu25 = tpu25top(FT) * nscaler - kp25 = kp25top(FT) * nscaler - - ! Adjust for temperature - vcmax_z(CL,FT,iv) = vcmax25 * ft1_f(bc_in(s)%t_veg_pa(ifp), vcmaxha) * & - fth_f(bc_in(s)%t_veg_pa(ifp), vcmaxhd, vcmaxse, vcmaxc) - jmax_z(CL,FT,iv) = jmax25 * ft1_f(bc_in(s)%t_veg_pa(ifp), jmaxha) * & - fth_f(bc_in(s)%t_veg_pa(ifp), jmaxhd, jmaxse, jmaxc) - tpu_z(CL,FT,iv) = tpu25 * ft1_f(bc_in(s)%t_veg_pa(ifp), tpuha) * & - fth_f(bc_in(s)%t_veg_pa(ifp), tpuhd, tpuse, tpuc) - - if (nint(c3psn(FT)) /= 1) then - vcmax_z(CL,FT,iv) = vcmax25 * 2._r8**((bc_in(s)%t_veg_pa(ifp)-(tfrz+25._r8))/10._r8) - vcmax_z(CL,FT,iv) = vcmax_z(CL,FT,iv) / (1._r8 + & - exp( 0.2_r8*((tfrz+15._r8)-bc_in(s)%t_veg_pa(ifp)) )) - vcmax_z(CL,FT,iv) = vcmax_z(CL,FT,iv) / (1._r8 + & - exp( 0.3_r8*(bc_in(s)%t_veg_pa(ifp)-(tfrz+40._r8)) )) - end if - kp_z(CL,FT,iv) = kp25 * 2._r8**((bc_in(s)%t_veg_pa(ifp)-(tfrz+25._r8))/10._r8) !q10 response of product limited psn. - end if - ! Adjust for soil water:(umol co2/m**2/s) - - vcmax_z(CL,FT,iv) = vcmax_z(CL,FT,iv) * currentPatch%btran_ft(FT) - ! completely removed respiration drought response - ! - (lmr_z(CL,FT,iv) * (1.0_r8-currentPatch%btran_ft(FT)) *pftcon%resp_drought_response(FT)) - lmr_z(CL,FT,iv) = lmr_z(CL,FT,iv) - - end do ! iv - end if !present - enddo !PFT - enddo !CL - - !==============================================================================! - ! Leaf-level photosynthesis and stomatal conductance - !==============================================================================! - - rsmax0 = 2.e4_r8 - - ! Leaf boundary layer conductance, umol/m**2/s - - cf = bc_in(s)%forc_pbot/(rgas*1.e-3_r8*bc_in(s)%tgcm_pa(ifp))*1.e06_r8 - gb = 1._r8/bc_in(s)%rb_pa(ifp) - gb_mol = gb * cf - - ! Constrain eair >= 0.05*esat_tv so that solution does not blow up. This ensures - ! that hs does not go to zero. Also eair <= esat_tv so that hs <= 1 - ceair = min( max(bc_in(s)%eair_pa(ifp), 0.05_r8*bc_in(s)%esat_tv_pa(ifp)), bc_in(s)%esat_tv_pa(ifp) ) - - ! Loop through canopy layers (above snow). Only do calculations if daytime - do CL = 1, NCL_p - do FT = 1,numpft_ed - if (nint(c3psn(FT)) == 1)then - ps = 1 - else - ps = 2 - end if - if(currentPatch%present(CL,FT) == 1)then ! are there any leaves of this pft in this layer? - do iv = 1, currentPatch%nrad(CL,FT) - if ( DEBUG ) write(iulog,*) 'EDphoto 581 ',currentPatch%ed_parsun_z(CL,ft,iv) - if (currentPatch%ed_parsun_z(CL,FT,iv) <= 0._r8) then ! night time - - ac = 0._r8 - aj = 0._r8 - ap = 0._r8 - ag(CL,FT,iv) = 0._r8 - an(CL,FT,iv) = ag(CL,FT,iv) - lmr_z(CL,FT,iv) - an_av(cl,ft,iv) = 0._r8 - currentPatch%psn_z(cl,ft,iv) = 0._r8 - rs_z(CL,FT,iv) = min(rsmax0, 1._r8/bbb(FT) * cf) - - else ! day time - !is there leaf area? - (NV can be larger than 0 with only stem area if deciduous) - - if ( DEBUG ) write(iulog,*) 'EDphot 594 ',currentPatch%ed_laisun_z(CL,ft,iv) - if ( DEBUG ) write(iulog,*) 'EDphot 595 ',currentPatch%ed_laisha_z(CL,ft,iv) - - if(currentPatch%ed_laisun_z(CL,ft,iv)+currentPatch%ed_laisha_z(cl,ft,iv) > 0._r8)then - - if ( DEBUG ) write(iulog,*) '600 in laisun, laisha loop ' - - !Loop aroun shaded and unshaded leaves - currentPatch%psn_z(CL,ft,iv) = 0._r8 ! psn is accumulated across sun and shaded leaves. - rs_z(CL,FT,iv) = 0._r8 ! 1/rs is accumulated across sun and shaded leaves. - gs_z(CL,FT,iv) = 0._r8 - an_av(CL,FT,iv) = 0._r8 - do sunsha = 1,2 - ! Electron transport rate for C3 plants. Convert par from W/m2 to umol photons/m**2/s - ! using the factor 4.6 - ! Convert from units of par absorbed per unit ground area to par absorbed per unit leaf area. - - if(sunsha == 1)then !sunlit - if((currentPatch%ed_laisun_z(CL,FT,iv) * currentPatch%canopy_area_profile(CL,FT,iv)) > & - 0.0000000001_r8)then - - qabs = currentPatch%ed_parsun_z(CL,FT,iv) / (currentPatch%ed_laisun_z(CL,FT,iv) * & - currentPatch%canopy_area_profile(CL,FT,iv)) - qabs = qabs * 0.5_r8 * (1._r8 - fnps) * 4.6_r8 - - else - qabs = 0.0_r8 - end if - else - - qabs = currentPatch%ed_parsha_z(CL,FT,iv) / (currentPatch%ed_laisha_z(CL,FT,iv) * & - currentPatch%canopy_area_profile(CL,FT,iv)) - qabs = qabs * 0.5_r8 * (1._r8 - fnps) * 4.6_r8 - - end if - - !convert the absorbed par into absorbed par per m2 of leaf, - ! so it is consistant with the vcmax and lmr numbers. - aquad = theta_psii - bquad = -(qabs + jmax_z(cl,ft,iv)) - cquad = qabs * jmax_z(cl,ft,iv) - call quadratic_f (aquad, bquad, cquad, r1, r2) - je = min(r1,r2) - - ! Iterative loop for ci beginning with initial guess - ! THIS CALL APPEARS TO BE REDUNDANT WITH LINE 423 (RGK) - - if (nint(c3psn(FT)) == 1)then - ci(cl,ft,iv) = 0.7_r8 * bc_in(s)%cair_pa(ifp) - else - ci(cl,ft,iv) = 0.4_r8 * bc_in(s)%cair_pa(ifp) - end if - - niter = 0 - exitloop = 0 - do while(exitloop == 0) - ! Increment iteration counter. Stop if too many iterations - niter = niter + 1 - - ! Save old ci - ciold = ci(cl,ft,iv) - - ! Photosynthesis limitation rate calculations - if (nint(c3psn(FT)) == 1)then - ! C3: Rubisco-limited photosynthesis - ac = vcmax_z(cl,ft,iv) * max(ci(cl,ft,iv)-co2_cp(ifp), 0._r8) / (ci(cl,ft,iv)+kc(ifp)* & - (1._r8+bc_in(s)%oair_pa(ifp)/ko(ifp))) - ! C3: RuBP-limited photosynthesis - aj = je * max(ci(cl,ft,iv)-co2_cp(ifp), 0._r8) / (4._r8*ci(cl,ft,iv)+8._r8*co2_cp(ifp)) - ! C3: Product-limited photosynthesis - ap = 3._r8 * tpu_z(cl,ft,iv) - else - ! C4: Rubisco-limited photosynthesis - ac = vcmax_z(cl,ft,iv) - ! C4: RuBP-limited photosynthesis - if(sunsha == 1)then !sunlit - if((currentPatch%ed_laisun_z(cl,ft,iv) * currentPatch%canopy_area_profile(cl,ft,iv)) > & - 0.0000000001_r8)then !guard against /0's in the night. - aj = qe(ps) * currentPatch%ed_parsun_z(cl,ft,iv) * 4.6_r8 - !convert from per cohort to per m2 of leaf) - aj = aj / (currentPatch%ed_laisun_z(cl,ft,iv) * & - currentPatch%canopy_area_profile(cl,ft,iv)) - else - aj = 0._r8 - end if - else - aj = qe(ps) * currentPatch%ed_parsha_z(cl,ft,iv) * 4.6_r8 - aj = aj / (currentPatch%ed_laisha_z(cl,ft,iv) * & - currentPatch%canopy_area_profile(cl,ft,iv)) - end if - - ! C4: PEP carboxylase-limited (CO2-limited) - ap = kp_z(cl,ft,iv) * max(ci(cl,ft,iv), 0._r8) / bc_in(s)%forc_pbot - end if - ! Gross photosynthesis smoothing calculations. First co-limit ac and aj. Then co-limit ap - aquad = theta_cj(ps) - bquad = -(ac + aj) - cquad = ac * aj - call quadratic_f (aquad, bquad, cquad, r1, r2) - ai = min(r1,r2) - - aquad = theta_ip - bquad = -(ai + ap) - cquad = ai * ap - call quadratic_f (aquad, bquad, cquad, r1, r2) - ag(cl,ft,iv) = min(r1,r2) - - ! Net carbon assimilation. Exit iteration if an < 0 - an(cl,ft,iv) = ag(cl,ft,iv) - lmr_z(cl,ft,iv) - if (an(cl,ft,iv) < 0._r8) then - exitloop = 1 - end if - - ! Quadratic gs_mol calculation with an known. Valid for an >= 0. - ! With an <= 0, then gs_mol = bbb - - cs = bc_in(s)%cair_pa(ifp) - 1.4_r8/gb_mol * an(cl,ft,iv) * bc_in(s)%forc_pbot - cs = max(cs,1.e-06_r8) - aquad = cs - bquad = cs*(gb_mol - bbb(FT)) - bb_slope(ft)*an(cl,ft,iv)*bc_in(s)%forc_pbot - cquad = -gb_mol*(cs*bbb(FT) + & - bb_slope(ft)*an(cl,ft,iv)*bc_in(s)%forc_pbot*ceair/bc_in(s)%esat_tv_pa(ifp)) - call quadratic_f (aquad, bquad, cquad, r1, r2) - gs_mol = max(r1,r2) - - ! Derive new estimate for ci - ci(cl,ft,iv) = bc_in(s)%cair_pa(ifp) - an(cl,ft,iv) * bc_in(s)%forc_pbot * & - (1.4_r8*gs_mol+1.6_r8*gb_mol) / (gb_mol*gs_mol) - - ! Check for ci convergence. Delta ci/pair = mol/mol. Multiply by 10**6 to - ! convert to umol/mol (ppm). Exit iteration if convergence criteria of +/- 1 x 10**-6 ppm - ! is met OR if at least ten iterations (niter=10) are completed - - if ((abs(ci(cl,ft,iv)-ciold)/bc_in(s)%forc_pbot*1.e06_r8 <= 2.e-06_r8) .or. niter == 5) then - exitloop = 1 - end if - end do !iteration loop - - ! End of ci iteration. Check for an < 0, in which case gs_mol = bbb - if (an(cl,ft,iv) < 0._r8) then - gs_mol = bbb(FT) - end if - - ! Final estimates for cs and ci (needed for early exit of ci iteration when an < 0) - cs = bc_in(s)%cair_pa(ifp) - 1.4_r8/gb_mol * an(cl,ft,iv) * bc_in(s)%forc_pbot - cs = max(cs,1.e-06_r8) - ci(cl,ft,iv) = bc_in(s)%cair_pa(ifp) - & - an(cl,ft,iv) * bc_in(s)%forc_pbot * (1.4_r8*gs_mol+1.6_r8*gb_mol) / (gb_mol*gs_mol) - ! Convert gs_mol (umol H2O/m**2/s) to gs (m/s) and then to rs (s/m) - gs = gs_mol / cf - - if ( DEBUG ) write(iulog,*) 'EDPhoto 737 ', currentPatch%psn_z(cl,ft,iv) - if ( DEBUG ) write(iulog,*) 'EDPhoto 738 ', ag(cl,ft,iv) - if ( DEBUG ) write(iulog,*) 'EDPhoto 739 ', currentPatch%f_sun(cl,ft,iv) - - !accumulate total photosynthesis umol/m2 ground/s-1. weight per unit sun and sha leaves. - if(sunsha == 1)then !sunlit - - currentPatch%psn_z(cl,ft,iv) = currentPatch%psn_z(cl,ft,iv) + ag(cl,ft,iv) * & - currentPatch%f_sun(cl,ft,iv) - an_av(cl,ft,iv) = an_av(cl,ft,iv) + an(cl,ft,iv) * & - currentPatch%f_sun(cl,ft,iv) - gs_z(cl,ft,iv) = gs_z(cl,ft,iv) + 1._r8/(min(1._r8/gs, rsmax0)) * & - currentPatch%f_sun(cl,ft,iv) - - else - - currentPatch%psn_z(cl,ft,iv) = currentPatch%psn_z(cl,ft,iv) + ag(cl,ft,iv) & - * (1.0_r8-currentPatch%f_sun(cl,ft,iv)) - an_av(cl,ft,iv) = an_av(cl,ft,iv) + an(cl,ft,iv) & - * (1.0_r8-currentPatch%f_sun(cl,ft,iv)) - gs_z(cl,ft,iv) = gs_z(cl,ft,iv) + & - 1._r8/(min(1._r8/gs, rsmax0)) * (1.0_r8-currentPatch%f_sun(cl,ft,iv)) - - end if - - if ( DEBUG ) write(iulog,*) 'EDPhoto 758 ', currentPatch%psn_z(cl,ft,iv) - if ( DEBUG ) write(iulog,*) 'EDPhoto 759 ', ag(cl,ft,iv) - if ( DEBUG ) write(iulog,*) 'EDPhoto 760 ', currentPatch%f_sun(cl,ft,iv) - - ! Make sure iterative solution is correct - if (gs_mol < 0._r8) then - write (iulog,*)'Negative stomatal conductance:' - write (iulog,*)'ifp,iv,gs_mol= ',ifp,iv,gs_mol - call endrun(msg=errmsg(sourcefile, __LINE__)) - end if - - ! Compare with Ball-Berry model: gs_mol = m * an * hs/cs p + b - hs = (gb_mol*ceair + gs_mol*bc_in(s)%esat_tv_pa(ifp)) / ((gb_mol+gs_mol)*bc_in(s)%esat_tv_pa(ifp)) - gs_mol_err = bb_slope(ft)*max(an(cl,ft,iv), 0._r8)*hs/cs*bc_in(s)%forc_pbot + bbb(FT) - - if (abs(gs_mol-gs_mol_err) > 1.e-01_r8) then - write (iulog,*) 'CF: Ball-Berry error check - stomatal conductance error:' - write (iulog,*) gs_mol, gs_mol_err - end if - - enddo !sunsha loop - !average leaf-level stomatal resistance rate over sun and shade leaves... - rs_z(cl,ft,iv) = 1._r8/gs_z(cl,ft,iv) - else !No leaf area. This layer is present only because of stems. (leaves are off, or have reduced to 0 - currentPatch%psn_z(cl,ft,iv) = 0._r8 - rs_z(CL,FT,iv) = min(rsmax0, 1._r8/bbb(FT) * cf) - - end if !is there leaf area? - - - end if ! night or day - end do ! iv canopy layer - end if ! present(L,ft) ? rd_array - end do ! PFT loop - end do !canopy layer - - !==============================================================================! - ! Unpack fluxes from arrays into cohorts - !==============================================================================! - - call currentPatch%set_root_fraction() - - if(currentPatch%countcohorts > 0.0)then !avoid errors caused by empty patches - - currentCohort => currentPatch%tallest ! Cohort loop - - do while (associated(currentCohort)) ! Cohort loop - - if(currentCohort%n > 0._r8)then - - ! Zero cohort flux accumulators. - currentCohort%npp_tstep = 0.0_r8 - currentCohort%resp_tstep = 0.0_r8 - currentCohort%gpp_tstep = 0.0_r8 - currentCohort%rd = 0.0_r8 - currentCohort%resp_m = 0.0_r8 - - ! Select canopy layer and PFT. - FT = currentCohort%pft !are we going to have ftindex? - CL = currentCohort%canopy_layer - !------------------------------------------------------------------------------ - ! Accumulate fluxes over the sub-canopy layers of each cohort. - !------------------------------------------------------------------------------ - ! Convert from umolC/m2leaf/s to umolC/indiv/s ( x canopy area x 1m2 leaf area). - tree_area = currentCohort%c_area/currentCohort%n - if ( DEBUG ) write(iulog,*) 'EDPhoto 816 ', currentCohort%gpp_tstep - if ( DEBUG ) write(iulog,*) 'EDPhoto 817 ', currentPatch%psn_z(cl,ft,1:currentCohort%nv-1) - if ( DEBUG ) write(iulog,*) 'EDPhoto 818 ', cl - if ( DEBUG ) write(iulog,*) 'EDPhoto 819 ', ft - if ( DEBUG ) write(iulog,*) 'EDPhoto 820 ', currentCohort%nv - if ( DEBUG ) write(iulog,*) 'EDPhoto 821 ', currentPatch%elai_profile(cl,ft,1:currentCohort%nv-1) - - if (currentCohort%nv > 1) then !is there canopy, and are the leaves on? - - currentCohort%gpp_tstep = sum(currentPatch%psn_z(cl,ft,1:currentCohort%nv-1) * & - currentPatch%elai_profile(cl,ft,1:currentCohort%nv-1)) * tree_area - - currentCohort%rd = sum(lmr_z(cl,ft,1:currentCohort%nv-1) * & - currentPatch%elai_profile(cl,ft,1:currentCohort%nv-1)) * tree_area - - currentCohort%gscan = sum((1.0_r8/(rs_z(cl,ft,1:currentCohort%nv-1)+bc_in(s)%rb_pa(ifp)))) * tree_area - currentCohort%ts_net_uptake(1:currentCohort%nv) = an_av(cl,ft,1:currentCohort%nv) * 12E-9 * dtime - - else - - currentCohort%gpp_tstep = 0.0_r8 - currentCohort%rd = 0.0_r8 - currentCohort%gscan = 0.0_r8 - currentCohort%ts_net_uptake(:) = 0.0_r8 - - end if - - if ( DEBUG ) write(iulog,*) 'EDPhoto 832 ', currentCohort%gpp_tstep - - laifrac = (currentCohort%treelai+currentCohort%treesai)-(currentCohort%nv-1)*dinc_ed - - gs_cohort = 1.0_r8/(rs_z(cl,ft,currentCohort%nv)+bc_in(s)%rb_pa(ifp))*laifrac*tree_area - currentCohort%gscan = currentCohort%gscan+gs_cohort - - if ( DEBUG ) then - write(iulog,*) 'EDPhoto 868 ', currentCohort%gpp_tstep - write(iulog,*) 'EDPhoto 869 ', currentPatch%psn_z(cl,ft,currentCohort%nv) - write(iulog,*) 'EDPhoto 870 ', currentPatch%elai_profile(cl,ft,currentCohort%nv) - write(iulog,*) 'EDPhoto 871 ', laifrac - write(iulog,*) 'EDPhoto 872 ', tree_area - write(iulog,*) 'EDPhoto 873 ', currentCohort%nv, cl, ft - endif - - currentCohort%gpp_tstep = currentCohort%gpp_tstep + currentPatch%psn_z(cl,ft,currentCohort%nv) * & - currentPatch%elai_profile(cl,ft,currentCohort%nv) * laifrac * tree_area - - if ( DEBUG ) write(iulog,*) 'EDPhoto 843 ', currentCohort%rd - - currentCohort%rd = currentCohort%rd + lmr_z(cl,ft,currentCohort%nv) * & - currentPatch%elai_profile(cl,ft,currentCohort%nv) * laifrac * tree_area - - !------------------------------------------------------------------------------ - ! Calculate Whole Plant Respiration (this doesn't really need to be in this iteration at all, surely?) - ! Leaf respn needs to be in the sub-layer loop to account for changing N through canopy. - ! - ! base rate for maintenance respiration is from: - ! M. Ryan, 1991. Effects of climate change on plant respiration. - ! Ecological Applications, 1(2), 157-167. - ! Original expression is br = 0.0106 molC/(molN h) - ! Conversion by molecular weights of C and N gives 2.525e-6 gC/(gN s) - !------------------------------------------------------------------------------ - - br = 2.525e-6_r8 - - leaf_frac = 1.0_r8/(currentCohort%canopy_trim + EDecophyscon%sapwood_ratio(currentCohort%pft) * & - currentCohort%hite + pftcon%froot_leaf(currentCohort%pft)) - currentCohort%bsw = EDecophyscon%sapwood_ratio(currentCohort%pft) * currentCohort%hite * & - (currentCohort%balive + currentCohort%laimemory)*leaf_frac - currentCohort%livestemn = currentCohort%bsw / pftcon%leafcn(currentCohort%pft) - - currentCohort%livestem_mr = 0._r8 - currentCohort%livecroot_mr = 0._r8 - - if ( DEBUG ) write(iulog,*) 'EDPhoto 874 ', currentCohort%livecroot_mr - if ( DEBUG ) write(iulog,*) 'EDPhoto 875 ', currentCohort%livecrootn - - if (woody(FT) == 1) then - tc = q10**((bc_in(s)%t_veg_pa(ifp)-tfrz - 20.0_r8)/10.0_r8) - currentCohort%livestem_mr = currentCohort%livestemn * br * tc !*currentPatch%btran_ft(currentCohort%pft) - currentCohort%livecroot_mr = currentCohort%livecrootn * br * tc !*currentPatch%btran_ft(currentCohort%pft) - - !convert from gC /indiv/s-1 to kgC/indiv/s-1 - ! TODO: CHANGE THAT 1000 to 1000.0_r8 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - currentCohort%livestem_mr = currentCohort%livestem_mr /1000 - currentCohort%livecroot_mr = currentCohort%livecroot_mr /1000 - else - tc = 1.0_r8 - currentCohort%livestem_mr = 0._r8 - currentCohort%livecroot_mr = 0._r8 - end if - - if (pftcon%woody(currentCohort%pft) == 1) then - coarse_wood_frac = 0.5_r8 - else - coarse_wood_frac = 0.0_r8 - end if - - ! Soil temperature. - currentCohort%froot_mr = 0._r8 - - do j = 1,nlevsoi - tcsoi = q10**((bc_in(s)%t_soisno_gl(j)-tfrz - 20.0_r8)/10.0_r8) - !fine root respn. - currentCohort%froot_mr = currentCohort%froot_mr + (1.0_r8 - coarse_wood_frac) * & - currentCohort%br*br*tcsoi * currentPatch%rootfr_ft(ft,j)/leafcn(currentCohort%pft) - ! convert from gC/indiv/s-1 to kgC/indiv/s-1 - currentCohort%froot_mr = currentCohort%froot_mr /1000.0_r8 - enddo - - ! convert gpp and resp from umol/indiv/s-1 to kgC/indiv/s-1 = X * 12 *10-6 * 10-3 - !currentCohort%resp_m = currentCohort%rd * 12.0E-9 - - if ( DEBUG ) write(iulog,*) 'EDPhoto 904 ', currentCohort%resp_m - if ( DEBUG ) write(iulog,*) 'EDPhoto 905 ', currentCohort%rd - if ( DEBUG ) write(iulog,*) 'EDPhoto 906 ', currentCohort%livestem_mr - if ( DEBUG ) write(iulog,*) 'EDPhoto 907 ', currentCohort%livecroot_mr - if ( DEBUG ) write(iulog,*) 'EDPhoto 908 ', currentCohort%froot_mr - - currentCohort%gpp_tstep = currentCohort%gpp_tstep * 12.0E-9 - ! add on whole plant respiration values in kgC/indiv/s-1 - currentCohort%resp_m = currentCohort%livestem_mr + currentCohort%livecroot_mr + currentCohort%froot_mr - ! no drought response * (1.0_r8 - currentPatch%btran_ft(currentCohort%pft)*pftcon%resp_drought_response(FT)) - currentCohort%resp_m = currentCohort%resp_m + currentCohort%rd * 12.0E-9 !this was already corrected fo BTRAN - - ! convert from kgC/indiv/s to kgC/indiv/timestep - currentCohort%resp_m = currentCohort%resp_m * dtime - currentCohort%gpp_tstep = currentCohort%gpp_tstep * dtime - - if ( DEBUG ) write(iulog,*) 'EDPhoto 911 ', currentCohort%gpp_tstep - if ( DEBUG ) write(iulog,*) 'EDPhoto 912 ', currentCohort%resp_tstep - if ( DEBUG ) write(iulog,*) 'EDPhoto 913 ', currentCohort%resp_m - - currentCohort%resp_g = ED_val_grperc(1) * (max(0._r8,currentCohort%gpp_tstep - currentCohort%resp_m)) - currentCohort%resp_tstep = currentCohort%resp_m + currentCohort%resp_g ! kgC/indiv/ts - currentCohort%npp_tstep = currentCohort%gpp_tstep - currentCohort%resp_tstep ! kgC/indiv/ts - - !------------------------------------------------------------------------------ - ! Remove whole plant respiration from net uptake. (kgC/indiv/ts) - if(currentCohort%treelai > 0._r8)then - ! do iv =1,currentCohort%NV - ! currentCohort%year_net_uptake(iv) = currentCohort%year_net_uptake(iv) - & - ! (timestep_secs*(currentCohort%livestem_mr + currentCohort%livecroot_mr & - ! minus contribution to whole plant respn. - ! + currentCohort%froot_mr))/(currentCohort%treelai*currentCohort%c_area/currentCohort%n) - ! enddo - else !lai<0 - currentCohort%gpp_tstep = 0._r8 - currentCohort%resp_m = 0._r8 - currentCohort%gscan = 0._r8 - end if - else !pft<0 n<0 - write(iulog,*) 'CF: pft 0 or n 0',currentCohort%pft,currentCohort%n,currentCohort%indexnumber - currentCohort%gpp_tstep = 0._r8 - currentCohort%resp_m = 0._r8 - currentCohort%gscan = 0._r8 - currentCohort%ts_net_uptake(1:currentCohort%nv) = 0._r8 - end if !pft<0 n<0 - - bc_out(s)%psncanopy_pa(ifp) = bc_out(s)%psncanopy_pa(ifp) + currentCohort%gpp_tstep - bc_out(s)%lmrcanopy_pa(ifp) = bc_out(s)%lmrcanopy_pa(ifp) + currentCohort%resp_m - ! accumulate cohort level canopy conductances over whole area before dividing by total area. - bc_out(s)%gccanopy_pa(ifp) = bc_out(s)%gccanopy_pa(ifp) + currentCohort%gscan * & - currentCohort%n /currentPatch%total_canopy_area - - currentCohort => currentCohort%shorter - - enddo ! end cohort loop. - end if !count_cohorts is more than zero. - - - elai = calc_areaindex(currentPatch,'elai') - - bc_out(s)%psncanopy_pa(ifp) = bc_out(s)%psncanopy_pa(ifp) / currentPatch%area - bc_out(s)%lmrcanopy_pa(ifp) = bc_out(s)%lmrcanopy_pa(ifp) / currentPatch%area - if(bc_out(s)%gccanopy_pa(ifp) > 1._r8/rsmax0 .and. elai > 0.0_r8)then - rscanopy = (1.0_r8/bc_out(s)%gccanopy_pa(ifp))-bc_in(s)%rb_pa(ifp)/elai ! this needs to be resistance per unit leaf area. - else - rscanopy = rsmax0 - end if - bc_out(s)%rssun_pa(ifp) = rscanopy - bc_out(s)%rssha_pa(ifp) = rscanopy - bc_out(s)%gccanopy_pa(ifp) = 1.0_r8/rscanopy*cf/1000 !convert into umol m02 s-1 then mmol m-2 s-1. - end if - - currentPatch => currentPatch%younger - - end do - - end do !site loop - - end associate - -end subroutine Photosynthesis_ED - -! ======================================================================================= - -function ft1_f(tl, ha) result(ans) - ! - !!DESCRIPTION: - ! photosynthesis temperature response - ! - ! !REVISION HISTORY - ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - !!USES - use clm_varcon , only : rgas, tfrz - ! - ! !ARGUMENTS: - real(r8), intent(in) :: tl ! leaf temperature in photosynthesis temperature function (K) - real(r8), intent(in) :: ha ! activation energy in photosynthesis temperature function (J/mol) - ! - ! !LOCAL VARIABLES: - real(r8) :: ans - !------------------------------------------------------------------------------- - - ans = exp( ha / (rgas*1.e-3_r8*(tfrz+25._r8)) * (1._r8 - (tfrz+25._r8)/tl) ) - - return - end function ft1_f - - ! ===================================================================================== - - function fth_f(tl,hd,se,scaleFactor) result(ans) - ! - !!DESCRIPTION: - !photosynthesis temperature inhibition - ! - ! !REVISION HISTORY - ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - use clm_varcon , only : rgas, tfrz - ! - ! !ARGUMENTS: - real(r8), intent(in) :: tl ! leaf temperature in photosynthesis temperature function (K) - real(r8), intent(in) :: hd ! deactivation energy in photosynthesis temperature function (J/mol) - real(r8), intent(in) :: se ! entropy term in photosynthesis temperature function (J/mol/K) - real(r8), intent(in) :: scaleFactor ! scaling factor for high temperature inhibition (25 C = 1.0) - ! - ! !LOCAL VARIABLES: - real(r8) :: ans - !------------------------------------------------------------------------------- - - ans = scaleFactor / ( 1._r8 + exp( (-hd+se*tl) / (rgas*1.e-3_r8*tl) ) ) - - return - end function fth_f - - ! ===================================================================================== - - function fth25_f(hd,se)result(ans) - ! - !!DESCRIPTION: - ! scaling factor for photosynthesis temperature inhibition - ! - ! !REVISION HISTORY: - ! Jinyun Tang separated it out from Photosynthesis, Feb. 07/2013 - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - !!USES - use clm_varcon , only : rgas, tfrz - ! - ! !ARGUMENTS: - real(r8), intent(in) :: hd ! deactivation energy in photosynthesis temperature function (J/mol) - real(r8), intent(in) :: se ! entropy term in photosynthesis temperature function (J/mol/K) - ! - ! !LOCAL VARIABLES: - real(r8) :: ans - !------------------------------------------------------------------------------- - - ans = 1._r8 + exp( (-hd+se*(tfrz+25._r8)) / (rgas*1.e-3_r8*(tfrz+25._r8)) ) - - return - end function fth25_f - - ! ===================================================================================== - - subroutine quadratic_f (a, b, c, r1, r2) - ! - ! !DESCRIPTION: - !==============================================================================! - !----------------- Solve quadratic equation for its two roots -----------------! - !==============================================================================! - ! Solution from Press et al (1986) Numerical Recipes: The Art of Scientific - ! Computing (Cambridge University Press, Cambridge), pp. 145. - ! - ! !REVISION HISTORY: - ! 4/5/10: Adapted from /home/bonan/ecm/psn/An_gs_iterative.f90 by Keith Oleson - ! 7/23/16: Copied over from CLM by Ryan Knox - ! - ! !USES: - implicit none - ! - ! !ARGUMENTS: - real(r8), intent(in) :: a,b,c ! Terms for quadratic equation - real(r8), intent(out) :: r1,r2 ! Roots of quadratic equation - ! - ! !LOCAL VARIABLES: - real(r8) :: q ! Temporary term for quadratic solution - !------------------------------------------------------------------------------ - - if (a == 0._r8) then - write (iulog,*) 'Quadratic solution error: a = ',a - call endrun(msg=errmsg(sourcefile, __LINE__)) - end if - - if (b >= 0._r8) then - q = -0.5_r8 * (b + sqrt(b*b - 4._r8*a*c)) - else - q = -0.5_r8 * (b - sqrt(b*b - 4._r8*a*c)) - end if - - r1 = q / a - if (q /= 0._r8) then - r2 = c / q - else - r2 = 1.e36_r8 - end if - - end subroutine quadratic_f - -end module EDPhotosynthesisMod diff --git a/src/ED/biogeophys/EDSurfaceAlbedoMod.F90 b/src/ED/biogeophys/EDSurfaceAlbedoMod.F90 deleted file mode 100644 index c4bdd45df6..0000000000 --- a/src/ED/biogeophys/EDSurfaceAlbedoMod.F90 +++ /dev/null @@ -1,1097 +0,0 @@ -module EDSurfaceRadiationMod - - !------------------------------------------------------------------------------------- - ! EDSurfaceRadiation - ! - ! This module contains function and type definitions for all things related - ! to radiative transfer in ED modules at the land surface. - ! - !------------------------------------------------------------------------------------- - -#include "shr_assert.h" - - use EDtypesMod , only : ed_patch_type, ed_site_type - use EDtypesMod , only : numpft_ed - use EDtypesMod , only : numPatchesPerCol - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use FatesInterfaceMod , only : bc_in_type, & - bc_out_type - use EDTypesMod , only : cp_numSWb, & ! Actual number of SW radiation bands - cp_maxSWb, & ! maximum number of SW bands (for scratch) - cp_nclmax ! control parameter, number of SW bands - use EDCanopyStructureMod, only: calc_areaindex - - - implicit none - - private - public :: ED_Norman_Radiation ! Surface albedo and two-stream fluxes - public :: ED_SunShadeFracs - - logical :: DEBUG = .false. ! for debugging this module - - real(r8), public :: albice(cp_maxSWb) = & ! albedo land ice by waveband (1=vis, 2=nir) - (/ 0.80_r8, 0.55_r8 /) - - ! INTERF-TODO: THIS NEEDS SOME CONSISTENCY AND SHOULD BE SET IN THE INTERFACE - ! WITH OTHER DIMENSIONS - integer, parameter :: ipar = 1 ! The band index for PAR - -contains - - subroutine ED_Norman_Radiation (nsites, sites, bc_in, bc_out ) - ! - - ! - ! !USES: - use clm_varctl , only : iulog - use pftconMod , only : pftcon - use EDtypesMod , only : ed_patch_type, numpft_ed, cp_nlevcan - use EDTypesMod , only : ed_site_type - - - ! !ARGUMENTS: - - integer, intent(in) :: nsites - type(ed_site_type), intent(inout), target :: sites(nsites) ! FATES site vector - type(bc_in_type), intent(in) :: bc_in(nsites) - type(bc_out_type), intent(inout) :: bc_out(nsites) - - - ! !LOCAL VARIABLES: - ! ============================================================================ - ! ED/NORMAN RADIATION DECS - ! ============================================================================ - type (ed_patch_type) , pointer :: currentPatch - integer :: radtype, L, ft, j, ifp - integer :: iter ! Iteration index - integer :: irep ! Flag to exit iteration loop - real(r8) :: sb - real(r8) :: error ! Error check - real(r8) :: down_rad, up_rad ! Iterative solution do Dif_dn and Dif_up - real(r8) :: ftweight(cp_nclmax,numpft_ed,cp_nlevcan) - real(r8) :: k_dir(numpft_ed) ! Direct beam extinction coefficient - real(r8) :: tr_dir_z(cp_nclmax,numpft_ed,cp_nlevcan) ! Exponential transmittance of direct beam radiation through a single layer - real(r8) :: tr_dif_z(cp_nclmax,numpft_ed,cp_nlevcan) ! Exponential transmittance of diffuse radiation through a single layer - real(r8) :: forc_dir(numPatchesPerCol,cp_maxSWb) - real(r8) :: forc_dif(numPatchesPerCol,cp_maxSWb) - real(r8) :: weighted_dir_tr(cp_nclmax) - real(r8) :: weighted_fsun(cp_nclmax) - real(r8) :: weighted_dif_ratio(cp_nclmax,cp_maxSWb) - real(r8) :: weighted_dif_down(cp_nclmax) - real(r8) :: weighted_dif_up(cp_nclmax) - real(r8) :: refl_dif(cp_nclmax,numpft_ed,cp_nlevcan,cp_maxSWb) ! Term for diffuse radiation reflected by laye - real(r8) :: tran_dif(cp_nclmax,numpft_ed,cp_nlevcan,cp_maxSWb) ! Term for diffuse radiation transmitted by layer - real(r8) :: dif_ratio(cp_nclmax,numpft_ed,cp_nlevcan,cp_maxSWb) ! Ratio of upward to forward diffuse fluxes - real(r8) :: Dif_dn(cp_nclmax,numpft_ed,cp_nlevcan) ! Forward diffuse flux onto canopy layer J (W/m**2 ground area) - real(r8) :: Dif_up(cp_nclmax,numpft_ed,cp_nlevcan) ! Upward diffuse flux above canopy layer J (W/m**2 ground area) - real(r8) :: lai_change(cp_nclmax,numpft_ed,cp_nlevcan) ! Forward diffuse flux onto canopy layer J (W/m**2 ground area) - real(r8) :: f_not_abs(numpft_ed,cp_maxSWb) ! Fraction reflected + transmitted. 1-absorbtion. - real(r8) :: Abs_dir_z(numpft_ed,cp_nlevcan) - real(r8) :: Abs_dif_z(numpft_ed,cp_nlevcan) - real(r8) :: abs_rad(cp_maxSWb) !radiation absorbed by soil - real(r8) :: tr_soili ! Radiation transmitted to the soil surface. - real(r8) :: tr_soild ! Radiation transmitted to the soil surface. - real(r8) :: phi1b(numPatchesPerCol,numpft_ed) ! Radiation transmitted to the soil surface. - real(r8) :: phi2b(numPatchesPerCol,numpft_ed) - real(r8) :: laisum ! cumulative lai+sai for canopy layer (at middle of layer) - real(r8) :: angle - - real(r8),parameter :: tolerance = 0.000000001_r8 - real(r8), parameter :: pi = 3.141592654 ! PI - - real(r8) :: denom - real(r8) :: lai_reduction(2) - - integer :: fp,iv,s ! array indices - integer :: ib ! waveband number - real(r8) :: cosz ! 0.001 <= coszen <= 1.000 - real(r8) :: chil(numPatchesPerCol) ! -0.4 <= xl <= 0.6 - real(r8) :: gdir(numPatchesPerCol) ! leaf projection in solar direction (0 to 1) - - !----------------------------------------------------------------------- - - associate(& - rhol => pftcon%rhol , & ! Input: [real(r8) (:) ] leaf reflectance: 1=vis, 2=nir - rhos => pftcon%rhos , & ! Input: [real(r8) (:) ] stem reflectance: 1=vis, 2=nir - taul => pftcon%taul , & ! Input: [real(r8) (:) ] leaf transmittance: 1=vis, 2=nir - taus => pftcon%taus , & ! Input: [real(r8) (:) ] stem transmittance: 1=vis, 2=nir - xl => pftcon%xl) ! Input: [real(r8) (:) ] ecophys const - leaf/stem orientation index - -! albd => surfalb_inst%albd_patch , & ! Output: [real(r8) (:,:) ] surface albedo (direct) (USED IN LND2ATM,BALANCE_CHECK) -! albi => surfalb_inst%albi_patch , & ! Output: [real(r8) (:,:) ] surface albedo (diffuse) (LND2ATM,BALANCE_CHECK) -! fabd => surfalb_inst%fabd_patch , & ! Output: [real(r8) (:,:) ] flux absorbed by canopy per unit direct flux (BALANCE_CHECK) -! fabi => surfalb_inst%fabi_patch , & ! Output: [real(r8) (:,:) ] flux absorbed by canopy per unit diffuse flux (BALANCE_CHECK) -! ftdd => surfalb_inst%ftdd_patch , & ! Output: [real(r8) (:,:) ] down direct flux below canopy per unit direct flx (BALANCE_CHECK) -! ftid => surfalb_inst%ftid_patch , & ! Output: [real(r8) (:,:) ] down diffuse flux below canopy per unit direct flx (BALANCE_CHECK) -! ftii => surfalb_inst%ftii_patch , & ! Output: [real(r8) (:,:) ] down diffuse flux below canopy per unit diffuse flx (BALANCE_CHECK) - - ! ------------------------------------------------------------------------------- - ! TODO (mv, 2014-10-29) the filter here is different than below - ! this is needed to have the VOC's be bfb - this needs to be - ! re-examined int he future - ! RGK,2016-08-06: FATES is still incompatible with VOC emission module - ! ------------------------------------------------------------------------------- - - - do s = 1, nsites - - ifp = 0 - currentpatch => sites(s)%oldest_patch - do while (associated(currentpatch)) - ifp = ifp+1 - - currentPatch%f_sun (:,:,:) = 0._r8 - currentPatch%fabd_sun_z (:,:,:) = 0._r8 - currentPatch%fabd_sha_z (:,:,:) = 0._r8 - currentPatch%fabi_sun_z (:,:,:) = 0._r8 - currentPatch%fabi_sha_z (:,:,:) = 0._r8 - currentPatch%fabd (:) = 0._r8 - currentPatch%fabi (:) = 0._r8 - - if(bc_in(s)%filter_vegzen_pa(ifp))then - - weighted_dir_tr(:) = 0._r8 - weighted_dif_down(:) = 0._r8 - weighted_dif_up(:) = 0._r8 - bc_out(s)%albd_parb(ifp,:) = 0._r8 ! output HLM - bc_out(s)%albi_parb(ifp,:) = 0._r8 ! output HLM - bc_out(s)%fabi_parb(ifp,:) = 0._r8 ! output HLM - bc_out(s)%fabd_parb(ifp,:) = 0._r8 ! output HLM - tr_dir_z(:,:,:) = 0._r8 - tr_dif_z(:,:,:) = 0._r8 - ftweight(:,:,:) = 0._r8 - lai_change(:,:,:) = 0._r8 - Dif_up(:,:,:) = 0._r8 - Dif_dn(:,:,:) = 0._r8 - refl_dif(:,:,:,:) = 0.0_r8 - tran_dif(:,:,:,:) = 0.0_r8 - dif_ratio(:,:,:,:) = 0.0_r8 - bc_out(s)%ftdd_parb(ifp,:) = 1._r8 ! output HLM - bc_out(s)%ftid_parb(ifp,:) = 1._r8 ! output HLM - bc_out(s)%ftii_parb(ifp,:) = 1._r8 ! output HLM - - if (maxval(currentPatch%nrad(1,:))==0)then - !there are no leaf layers in this patch. it is effectively bare ground. - ! no radiation is absorbed - bc_out(s)%fabd_parb(ifp,:) = 0.0_r8 - bc_out(s)%fabi_parb(ifp,:) = 0.0_r8 - do ib = 1,cp_numSWb - bc_out(s)%albd_parb(ifp,ib) = bc_in(s)%albgr_dir_rb(ib) - bc_out(s)%albd_parb(ifp,ib) = bc_in(s)%albgr_dif_rb(ib) - bc_out(s)%ftdd_parb(ifp,ib)= 1.0_r8 - bc_out(s)%ftid_parb(ifp,ib)= 1.0_r8 - bc_out(s)%ftii_parb(ifp,ib)= 1.0_r8 - enddo - else - - ! Is this pft/canopy layer combination present in this patch? - do L = 1,cp_nclmax - do ft = 1,numpft_ed - currentPatch%present(L,ft) = 0 - do iv = 1, currentPatch%nrad(L,ft) - if (currentPatch%canopy_area_profile(L,ft,iv) > 0._r8)then - currentPatch%present(L,ft) = 1 - !I think 'present' is only used here... - endif - end do !iv - end do !ft - end do !L - - do radtype = 1,2 !do this once for one unit of diffuse, and once for one unit of direct radiation - do ib = 1,cp_numSWb - if (radtype == 1) then - ! Set the hypothetical driving radiation. We do this once for a single unit of direct and - ! once for a single unit of diffuse radiation. - forc_dir(ifp,ib) = 1.00_r8 - forc_dif(ifp,ib) = 0.00_r8 - else !dif - forc_dir(ifp,ib) = 0.00_r8 - forc_dif(ifp,ib) = 1.00_r8 - end if - end do !ib - - !Extract information that needs to be provided by ED into local array. - ftweight(:,:,:) = 0._r8 - do L = 1,currentPatch%NCL_p - do ft = 1,numpft_ed - do iv = 1, currentPatch%nrad(L,ft) - !this is already corrected for area in CLAP - ftweight(L,ft,iv) = currentPatch%canopy_area_profile(L,ft,iv) - end do !iv - end do !ft1 - end do !L - if (sum(ftweight(1,:,1))<0.999_r8)then - write(iulog,*) 'canopy not full',ftweight(1,:,1) - endif - if (sum(ftweight(1,:,1))>1.0001_r8)then - write(iulog,*) 'canopy too full',ftweight(1,:,1) - endif - - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! Direct beam extinction coefficient, k_dir. PFT specific. - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - cosz = max(0.001_r8, bc_in(s)%coszen_pa(ifp)) !copied from previous radiation code... - do ft = 1,numpft_ed - sb = (90._r8 - (acos(cosz)*180/pi)) * (pi / 180._r8) - chil(ifp) = xl(ft) !min(max(xl(ft), -0.4_r8), 0.6_r8 ) - if (abs(chil(ifp)) <= 0.01_r8) then - chil(ifp) = 0.01_r8 - end if - phi1b(ifp,ft) = 0.5_r8 - 0.633_r8*chil(ifp) - 0.330_r8*chil(ifp)*chil(ifp) - phi2b(ifp,ft) = 0.877_r8 * (1._r8 - 2._r8*phi1b(ifp,ft)) !0 = horiz leaves, 1 - vert leaves. - gdir(ifp) = phi1b(ifp,ft) + phi2b(ifp,ft) * sin(sb) - !how much direct light penetrates a singleunit of lai? - k_dir(ft) = gdir(ifp) / sin(sb) - end do !FT - - do L = 1,currentPatch%NCL_p !start at the top canopy layer (1 is the top layer.) - weighted_dir_tr(L) = 0.0_r8 - weighted_fsun(L) = 0._r8 - weighted_dif_ratio(L,1:cp_numSWb) = 0._r8 - !Each canopy layer (canopy, understorey) has multiple 'parallel' pft's - do ft =1,numpft_ed - if (currentPatch%present(L,ft) == 1)then !only do calculation if there are the appropriate leaves. - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! Diffuse transmittance, tr_dif, do each layer with thickness elai_z. - ! Estimated do nine sky angles in increments of 10 degrees - ! PFT specific... - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - tr_dif_z(L,ft,:) = 0._r8 - do iv = 1,currentPatch%nrad(L,ft) - do j = 1,9 - angle = (5._r8 + (j - 1) * 10._r8) * 3.142 / 180._r8 - gdir(ifp) = phi1b(ifp,ft) + phi2b(ifp,ft) * sin(angle) !This line is redundant FIX(RF,032414). - tr_dif_z(L,ft,iv) = tr_dif_z(L,ft,iv) + exp(-gdir(ifp) / sin(angle) * & - (currentPatch%elai_profile(L,ft,iv)+currentPatch%esai_profile(L,ft,iv))) * & - sin(angle)*cos(angle) - end do - - tr_dif_z(L,ft,iv) = tr_dif_z(L,ft,iv) * 2._r8 * (10.00*pi/180._r8) - - end do - - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! Direct beam transmittance, tr_dir_z, uses cumulative LAI above layer J to give - ! unscattered direct beam onto layer J. do each PFT section. - ! This is just an decay curve based on k_dir. (leaf & sun angle) - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - if (L==1)then - tr_dir_z(L,ft,1) = 1._r8 - else - tr_dir_z(L,ft,1) = weighted_dir_tr(L-1) - endif - laisum = 0.00_r8 - !total direct beam getting to the bottom of the top canopy. - do iv = 1,currentPatch%nrad(L,ft) - laisum = laisum + currentPatch%elai_profile(L,ft,iv)+currentPatch%esai_profile(L,ft,iv) - lai_change(L,ft,iv) = 0.0_r8 - if (( ftweight(L,ft,iv+1) > 0.0_r8 ) .and. ( ftweight(L,ft,iv+1) < ftweight(L,ft,iv) ))then - !where there is a partly empty leaf layer, some fluxes go straight through. - lai_change(L,ft,iv) = ftweight(L,ft,iv)-ftweight(L,ft,iv+1) - endif - if (ftweight(L,ft,iv+1) - ftweight(L,ft,iv) > 1.e-10_r8)then - write(iulog,*) 'lower layer has more coverage. This is wrong' , & - ftweight(L,ft,iv),ftweight(L,ft,iv+1),ftweight(L,ft,iv+1)-ftweight(L,ft,iv) - endif - - !n.b. in theory lai_change could be calculated daily in the ED code. - !This is light coming striaght through the canopy. - if (L==1)then - tr_dir_z(L,ft,iv+1) = exp(-k_dir(ft) * laisum)* & - (ftweight(L,ft,iv)/ftweight(L,ft,1)) - else - tr_dir_z(L,ft,iv+1) = weighted_dir_tr(L-1)*exp(-k_dir(ft) * laisum)* & - (ftweight(L,ft,iv)/ftweight(L,ft,1)) - endif - - if (iv == 1)then - !this is the top layer. - tr_dir_z(L,ft,iv+1) = tr_dir_z(L,ft,iv+1) + tr_dir_z(L,ft,iv) * & - ((ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1)) - else - !the lai_change(iv) affects the light incident on layer iv+2 not iv+1 - ! light coming from the layer above (iv-1) goes through iv and onto iv+1. - if (lai_change(L,ft,iv-1) > 0.0_r8)then - tr_dir_z(L,ft,iv+1) = tr_dir_z(L,ft,iv+1) + tr_dir_z(L,ft,iv)* & - lai_change(L,ft,iv-1) / ftweight(L,ft,1) - tr_dir_z(L,ft,iv+1) = tr_dir_z(L,ft,iv+1) + tr_dir_z(L,ft,iv-1)* & - (ftweight(L,ft,1)-ftweight(L,ft,iv-1))/ftweight(L,ft,1) - else - !account fot the light that comes striaght down from unfilled layers above. - tr_dir_z(L,ft,iv+1) = tr_dir_z(L,ft,iv+1) + tr_dir_z(L,ft,iv) * & - ((ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1)) - endif - endif - end do - - !add up all the weighted contributions from the different PFT columns. - weighted_dir_tr(L) = weighted_dir_tr(L) + tr_dir_z(L,ft,currentPatch%nrad(L,ft)+1)*ftweight(L,ft,1) - - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! Sunlit and shaded fraction of leaf layer - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - - !laisum = 0._r8 - do iv = 1,currentPatch%nrad(L,ft) - ! Cumulative leaf area. Original code uses cumulative lai do layer. - ! Now use cumulative lai at center of layer. - ! Same as tr_dir_z calcualtions, but in the middle of the layer? FIX(RF,032414)-WHY? - if (iv == 1) then - laisum = 0.5_r8 * (currentPatch%elai_profile(L,ft,iv)+currentPatch%esai_profile(L,ft,iv)) - else - laisum = laisum + currentPatch%elai_profile(L,ft,iv)+currentPatch%esai_profile(L,ft,iv) - end if - - - if (L == 1)then !top canopy layer - currentPatch%f_sun(L,ft,iv) = exp(-k_dir(ft) * laisum)* & - (ftweight(L,ft,iv)/ftweight(L,ft,1)) - else - currentPatch%f_sun(L,ft,iv) = weighted_fsun(L-1)* exp(-k_dir(ft) * laisum)* & - (ftweight(L,ft,iv)/ftweight(L,ft,1)) - endif - - if ( iv > 1 ) then ! becasue we are looking at this layer (not the next) - ! we only ever add fluxes if iv>1 - if (lai_change(L,ft,iv-1) > 0.0_r8)then - currentPatch%f_sun(L,ft,iv) = currentPatch%f_sun(L,ft,iv) + & - currentPatch%f_sun(L,ft,iv) * & - lai_change(L,ft,iv-1)/ftweight(L,ft,1) - currentPatch%f_sun(L,ft,iv) = currentPatch%f_sun(L,ft,iv) + & - currentPatch%f_sun(L,ft,iv-1) * & - (ftweight(L,ft,1)-ftweight(L,ft,iv-1))/ftweight(L,ft,1) - else - currentPatch%f_sun(L,ft,iv) = currentPatch%f_sun(L,ft,iv) + & - currentPatch%f_sun(L,ft,iv-1) * & - (ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1) - endif - endif - - end do !iv - weighted_fsun(L) = weighted_fsun(L) + currentPatch%f_sun(L,ft,currentPatch%nrad(L,ft))* & - ftweight(L,ft,1) - - ! instance where the first layer ftweight is used a proxy for the whole column. FTWA - ! this is possibly a source of slight error. If we use the ftweight at the top of the PFT column, - ! then we willl underestimate fsun, but if we use ftweight at the bottom of the column, we will - ! underestimate it. Really, we should be tracking the release of direct light from the column as it tapers - ! towards the ground. Is that necessary to get energy closure? It would be quite hard... - endif !present. - end do!pft loop - end do !L - - do L = currentPatch%NCL_p,1, -1 !start at the bottom and work up. - do ft = 1,numpft_ed - if (currentPatch%present(L,ft) == 1)then - !==============================================================================! - ! Iterative solution do scattering - !==============================================================================! - - do ib = 1,cp_numSWb !vis, nir - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! Leaf scattering coefficient and terms do diffuse radiation reflected - ! and transmitted by a layer - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - f_not_abs(ft,ib) = rhol(ft,ib) + taul(ft,ib) !leaf level fraction NOT absorbed. - !tr_dif_z is a term that uses the LAI in each layer, whereas rhol and taul do not, - !because they are properties of leaf surfaces and not of the leaf matrix. - do iv = 1,currentPatch%nrad(L,ft) - !How much diffuse light is intercepted and then reflected? - refl_dif(L,ft,iv,ib) = (1._r8 - tr_dif_z(L,ft,iv)) * rhol(ft,ib) - !How much diffuse light in this layer is transmitted? - tran_dif(L,ft,iv,ib) = (1._r8 - tr_dif_z(L,ft,iv)) * taul(ft,ib) + tr_dif_z(L,ft,iv) - end do - - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! Ratio of upward to forward diffuse fluxes, dif_ratio - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! Soil diffuse reflectance (ratio of down to up radiation). - iv = currentPatch%nrad(L,ft) + 1 - if (L == currentPatch%NCL_p)then !nearest the soil - dif_ratio(L,ft,iv,ib) = bc_in(s)%albgr_dif_rb(ib) - else - dif_ratio(L,ft,iv,ib) = weighted_dif_ratio(L+1,ib) - end if - ! Canopy layers, working upwardfrom soil with dif_ratio(iv+1) known - ! FIX(RF,032414) ray tracing eqution - need to find derivation of this... - ! for each unit going down, there are x units going up. - do iv = currentPatch%nrad(L,ft),1, -1 - dif_ratio(L,ft,iv,ib) = dif_ratio(L,ft,iv+1,ib) * tran_dif(L,ft,iv,ib)*tran_dif(L,ft,iv,ib) / & - (1._r8 - dif_ratio(L,ft,iv+1,ib) * refl_dif(L,ft,iv,ib)) + refl_dif(L,ft,iv,ib) - dif_ratio(L,ft,iv,ib) = dif_ratio(L,ft,iv,ib) * ftweight(L,ft,iv)/ftweight(L,ft,1) - dif_ratio(L,ft,iv,ib) = dif_ratio(L,ft,iv,ib) + dif_ratio(L,ft,iv+1,ib)* & - (ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1) - end do - weighted_dif_ratio(L,ib) = weighted_dif_ratio(L,ib) + dif_ratio(L,ft,1,ib) * ftweight(L,ft,1) - !instance where the first layer ftweight is used a proxy for the whole column. FTWA - end do!cp_numSWb - endif ! currentPatch%present - end do!ft - end do!L - - do ib = 1,cp_numSWb - Dif_dn(:,:,:) = 0.00_r8 - Dif_up(:,:,:) = 0.00_r8 - do L = 1, currentPatch%NCL_p !work down from the top of the canopy. - weighted_dif_down(L) = 0._r8 - do ft = 1, numpft_ed - if (currentPatch%present(L,ft) == 1)then - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! First estimates do downward and upward diffuse flux - ! - ! Dif_dn = forward diffuse flux onto layer J - ! Dif_up = Upward diffuse flux above layer J - ! - ! Solved here without direct beam radiation and using dif_ratio = Dif_up / Dif_dn - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! downward diffuse flux onto the top surface of the canopy - - if (L == 1)then - Dif_dn(L,ft,1) = forc_dif(ifp,ib) - else - Dif_dn(L,ft,1) = weighted_dif_down(L-1) - end if - ! forward diffuse flux within the canopy and at soil, working forward through canopy - do iv = 1,currentPatch%nrad(L,ft) - denom = refl_dif(L,ft,iv,ib) * dif_ratio(L,ft,iv,ib) - denom = 1._r8 - denom - Dif_dn(L,ft,iv+1) = Dif_dn(L,ft,iv) * tran_dif(L,ft,iv,ib) / & - denom *ftweight(L,ft,iv)/ftweight(L,ft,1) - if (iv > 1)then - if (lai_change(L,ft,iv-1) > 0.0_r8)then - !here we are thinking about whether the layer above had an laichange, - !but calculating the flux onto the layer below. - Dif_dn(L,ft,iv+1) = Dif_dn(L,ft,iv+1)+ Dif_dn(L,ft,iv)* & - lai_change(L,ft,iv-1)/ftweight(L,ft,1) - Dif_dn(L,ft,iv+1) = Dif_dn(L,ft,iv+1)+ Dif_dn(L,ft,iv-1)* & - (ftweight(L,ft,1)-ftweight(L,ft,iv-1)/ftweight(L,ft,1)) - else - Dif_dn(L,ft,iv+1) = Dif_dn(L,ft,iv+1) + Dif_dn(L,ft,iv) * & - (ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1) - endif - else - Dif_dn(L,ft,iv+1) = Dif_dn(L,ft,iv+1) + Dif_dn(L,ft,iv) * & - (ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1) - endif - end do - - weighted_dif_down(L) = weighted_dif_down(L) + Dif_dn(L,ft,currentPatch%nrad(L,ft)+1) * & - ftweight(L,ft,1) - - !instance where the first layer ftweight is used a proxy for the whole column. FTWA - endif !present - end do !ft - if (L == currentPatch%NCL_p.and.currentPatch%NCL_p > 1)then !is the the (incomplete) understorey? - !Add on the radiation going through the canopy gaps. - weighted_dif_down(L) = weighted_dif_down(L) + weighted_dif_down(L-1)*(1.0-sum(ftweight(L,:,1))) - !instance where the first layer ftweight is used a proxy for the whole column. FTWA - endif - end do !L - - do L = currentPatch%NCL_p,1 ,-1 !work up from the bottom. - weighted_dif_up(L) = 0._r8 - do ft = 1, numpft_ed - if (currentPatch%present(L,ft) == 1)then - !Bounce diffuse radiation off soil surface. - iv = currentPatch%nrad(L,ft) + 1 - if (L==currentPatch%NCL_p)then !is this the bottom layer ? - Dif_up(L,ft,iv) =bc_in(s)%albgr_dif_rb(ib) * Dif_dn(L,ft,iv) - else - Dif_up(L,ft,iv) = weighted_dif_up(L+1) - end if - ! Upward diffuse flux within the canopy and above the canopy, working upward through canopy - - do iv = currentPatch%nrad(L,ft), 1, -1 - if (lai_change(L,ft,iv) > 0.0_r8)then - Dif_up(L,ft,iv) = dif_ratio(L,ft,iv,ib) * Dif_dn(L,ft,iv) * & - ftweight(L,ft,iv) / ftweight(L,ft,1) - Dif_up(L,ft,iv) = Dif_up(L,ft,iv) + Dif_up(L,ft,iv+1) * & - tran_dif(L,ft,iv,ib) * lai_change(L,ft,iv)/ftweight(L,ft,1) - Dif_up(L,ft,iv) = Dif_up(L,ft,iv) + Dif_up(L,ft,iv+1) * & - (ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1) - !nb is this the right constuction? - ! the radiation that hits the empty space is not reflected. - else - Dif_up(L,ft,iv) = dif_ratio(L,ft,iv,ib) * Dif_dn(L,ft,iv) * ftweight(L,ft,iv) - Dif_up(L,ft,iv) = Dif_up(L,ft,iv) + Dif_up(L,ft,iv+1) * (1.0_r8-ftweight(L,ft,iv)) - endif - end do - - weighted_dif_up(L) = weighted_dif_up(L) + Dif_up(L,ft,1) * ftweight(L,ft,1) - !instance where the first layer ftweight is used a proxy for the whole column. FTWA - endif !present - end do !ft - if (L == currentPatch%NCL_p.and.currentPatch%NCL_p > 1)then !is this the (incomplete) understorey? - !Add on the radiation coming up through the canopy gaps. - !diffuse to diffuse - weighted_dif_up(L) = weighted_dif_up(L) +(1.0-sum(ftweight(L,:,1))) * & - weighted_dif_down(L-1) * bc_in(s)%albgr_dif_rb(ib) - !direct to diffuse - weighted_dif_up(L) = weighted_dif_up(L) + forc_dir(ifp,ib) * & - weighted_dir_tr(L-1) * (1.0-sum(ftweight(L,:,1)))*bc_in(s)%albgr_dir_rb(ib) - endif - end do !L - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - ! 3. Iterative calculation of forward and upward diffuse fluxes, iNCL_puding - ! scattered direct beam - !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++! - - ! Flag to exit iteration loop: 0 = exit and 1 = iterate - irep = 1 - ! Iteration loop - iter = 0 - do while(irep ==1 .and. iter<50) - - iter = iter + 1 - irep = 0 - do L = 1,currentPatch%NCL_p !working from the top down - weighted_dif_down(L) = 0._r8 - do ft =1,numpft_ed - if (currentPatch%present(L,ft) == 1)then - ! forward diffuse flux within the canopy and at soil, working forward through canopy - ! with Dif_up -from previous iteration-. Dif_dn(1) is the forward diffuse flux onto the canopy. - ! Note: down = forward flux onto next layer - if (L == 1)then !is this the top layer? - Dif_dn(L,ft,1) = forc_dif(ifp,ib) - else - Dif_dn(L,ft,1) = weighted_dif_down(L-1) - end if - down_rad = 0._r8 - - do iv = 1, currentPatch%nrad(L,ft) - - down_rad = Dif_dn(L,ft,iv) * tran_dif(L,ft,iv,ib) + & - Dif_up(L,ft,iv+1) * refl_dif(L,ft,iv,ib) + & - forc_dir(ifp,ib) * tr_dir_z(L,ft,iv) * (1.00_r8 - & - exp(-k_dir(ft) * (currentPatch%elai_profile(L,ft,iv)+ & - currentPatch%esai_profile(L,ft,iv)))) * taul(ft,ib) - down_rad = down_rad *(ftweight(L,ft,iv)/ftweight(L,ft,1)) - - if (iv > 1)then - if (lai_change(L,ft,iv-1) > 0.0_r8)then - down_rad = down_rad + Dif_dn(L,ft,iv) * lai_change(L,ft,iv-1)/ftweight(L,ft,1) - down_rad = down_rad + Dif_dn(L,ft,iv-1) * (ftweight(L,ft,1)-ftweight(L,ft,iv-1))/ & - ftweight(L,ft,1) - else - down_rad = down_rad + Dif_dn(L,ft,iv) * (ftweight(L,ft,1)-ftweight(L,ft,iv))/ & - ftweight(L,ft,1) - endif - else - down_rad = down_rad + Dif_dn(L,ft,iv) * (ftweight(L,ft,1)-ftweight(L,ft,iv))/ & - ftweight(L,ft,1) - endif - - !this is just Dif down, plus refl up, plus dir intercepted and turned into dif... , - if (abs(down_rad - Dif_dn(L,ft,iv+1)) > tolerance)then - irep = 1 - end if - Dif_dn(L,ft,iv+1) = down_rad - - end do !iv - - weighted_dif_down(L) = weighted_dif_down(L) + Dif_dn(L,ft,currentPatch%nrad(L,ft)+1) * & - ftweight(L,ft,1) - - endif !present - end do!ft - if (L == currentPatch%NCL_p.and.currentPatch%NCL_p > 1)then !is this the (incomplete) understorey? - weighted_dif_down(L) = weighted_dif_down(L) + weighted_dif_down(L-1)*(1.0-sum(ftweight(L,:,1))) - end if - end do ! do L loop - - do L = 1, currentPatch%NCL_p ! working from the top down. - weighted_dif_up(L) = 0._r8 - do ft =1,numpft_ed - if (currentPatch%present(L,ft) == 1)then - ! Upward diffuse flux at soil or from lower canopy (forward diffuse and unscattered direct beam) - iv = currentPatch%nrad(L,ft) + 1 - if (L==currentPatch%NCL_p)then !In the bottom canopy layer, reflect off the soil - Dif_up(L,ft,iv) = Dif_dn(L,ft,iv) *bc_in(s)%albgr_dif_rb(ib) + & - forc_dir(ifp,ib) * tr_dir_z(L,ft,iv) *bc_in(s)%albgr_dir_rb(ib) - else !In the other canopy layers, reflect off the underlying vegetation. - Dif_up(L,ft,iv) = weighted_dif_up(L+1) - end if - - ! Upward diffuse flux within and above the canopy, working upward through canopy - ! with Dif_dn from previous interation. Note: up = upward flux above current layer - do iv = currentPatch%nrad(L,ft),1,-1 - !this is radiation up, by layer transmittance, by - - !reflection of the lower layer, - up_rad = Dif_dn(L,ft,iv) * refl_dif(L,ft,iv,ib) - up_rad = up_rad + forc_dir(ifp,ib) * tr_dir_z(L,ft,iv) * (1.00_r8 - exp(-k_dir(ft) * & - (currentPatch%elai_profile(L,ft,iv) + currentPatch%esai_profile(L,ft,iv)))) * & - rhol(ft,ib) - up_rad = up_rad + Dif_up(L,ft,iv+1) * tran_dif(L,ft,iv,ib) - up_rad = up_rad * ftweight(L,ft,iv)/ftweight(L,ft,1) - up_rad = up_rad + Dif_up(L,ft,iv+1) *(ftweight(L,ft,1)-ftweight(L,ft,iv))/ftweight(L,ft,1) - ! THE LOWER LAYER FLUX IS HOMOGENIZED, SO WE DON"T CONSIDER THE LAI_CHANGE HERE... - - if (abs(up_rad - Dif_up(L,ft,iv)) > tolerance) then !are we close to the tolerance level? - irep = 1 - end if - Dif_up(L,ft,iv) = up_rad - - end do !iv - weighted_dif_up(L) = weighted_dif_up(L) + Dif_up(L,ft,1) * ftweight(L,ft,1) - end if !present - end do!ft - - if (L == currentPatch%NCL_p.and.currentPatch%NCL_p > 1)then !is this the (incomplete) understorey? - !Add on the radiation coming up through the canopy gaps. - weighted_dif_up(L) = weighted_dif_up(L) +(1.0_r8-sum(ftweight(L,:,1))) * & - weighted_dif_down(L-1) * bc_in(s)%albgr_dif_rb(ib) - weighted_dif_up(L) = weighted_dif_up(L) + forc_dir(ifp,ib) * & - weighted_dir_tr(L-1) * (1.0_r8-sum(ftweight(L,:,1)))*bc_in(s)%albgr_dir_rb(ib) - end if - end do!L - end do ! do while over iter - - abs_rad(ib) = 0._r8 - tr_soili = 0._r8 - tr_soild = 0._r8 - do L = 1, currentPatch%NCL_p !working from the top down. - abs_dir_z(:,:) = 0._r8 - abs_dif_z(:,:) = 0._r8 - do ft =1,numpft_ed - if (currentPatch%present(L,ft) == 1)then - !==============================================================================! - ! Compute absorbed flux densities - !==============================================================================! - - ! Absorbed direct beam and diffuse do leaf layers - do iv = 1, currentPatch%nrad(L,ft) - Abs_dir_z(ft,iv) = ftweight(L,ft,iv)* forc_dir(ifp,ib) * tr_dir_z(L,ft,iv) * & - (1.00_r8 - exp(-k_dir(ft) * (currentPatch%elai_profile(L,ft,iv)+ & - currentPatch%esai_profile(L,ft,iv)))) * (1.00_r8 - f_not_abs(ft,ib)) - Abs_dif_z(ft,iv) = ftweight(L,ft,iv)* ((Dif_dn(L,ft,iv) + & - Dif_up(L,ft,iv+1)) * (1.00_r8 - tr_dif_z(L,ft,iv)) * & - (1.00_r8 - f_not_abs(ft,ib))) - end do - - ! Absorbed direct beam and diffuse do soil - if (L == currentPatch%NCL_p)then - iv = currentPatch%nrad(L,ft) + 1 - Abs_dif_z(ft,iv) = ftweight(L,ft,1)*Dif_dn(L,ft,iv) * (1.0_r8 -bc_in(s)%albgr_dif_rb(ib)) - Abs_dir_z(ft,iv) = ftweight(L,ft,1)*forc_dir(ifp,ib) * & - tr_dir_z(L,ft,iv) * (1.0_r8 -bc_in(s)%albgr_dir_rb(ib)) - tr_soild = tr_soild + ftweight(L,ft,1)*forc_dir(ifp,ib) * tr_dir_z(L,ft,iv) - tr_soili = tr_soili + ftweight(L,ft,1)*Dif_dn(L,ft,iv) - end if - ! Absorbed radiation, shaded and sunlit portions of leaf layers - !here we get one unit of diffuse radiation... how much of - !it is absorbed? - if (ib == 1) then ! only set the absorbed PAR for the visible light band. - do iv = 1, currentPatch%nrad(L,ft) - if (radtype==1) then - if ( DEBUG ) then - write(iulog,*) 'EDsurfAlb 730 ',Abs_dif_z(ft,iv),currentPatch%f_sun(L,ft,iv) - write(iulog,*) 'EDsurfAlb 731 ', currentPatch%fabd_sha_z(L,ft,iv), & - currentPatch%fabd_sun_z(L,ft,iv) - endif - currentPatch%fabd_sha_z(L,ft,iv) = Abs_dif_z(ft,iv) * & - (1._r8 - currentPatch%f_sun(L,ft,iv)) - currentPatch%fabd_sun_z(L,ft,iv) = Abs_dif_z(ft,iv) * & - currentPatch%f_sun(L,ft,iv) + & - Abs_dir_z(ft,iv) - else - currentPatch%fabi_sha_z(L,ft,iv) = Abs_dif_z(ft,iv) * & - (1._r8 - currentPatch%f_sun(L,ft,iv)) - currentPatch%fabi_sun_z(L,ft,iv) = Abs_dif_z(ft,iv) * & - currentPatch%f_sun(L,ft,iv) - endif - if ( DEBUG ) then - write(iulog,*) 'EDsurfAlb 740 ', currentPatch%fabd_sha_z(L,ft,iv), & - currentPatch%fabd_sun_z(L,ft,iv) - endif - end do - endif ! ib - - !==============================================================================! - ! Sum fluxes - !==============================================================================! - ! Solar radiation absorbed by ground - iv = currentPatch%nrad(L,ft) + 1 - if (L==currentPatch%NCL_p)then - abs_rad(ib) = abs_rad(ib) + (Abs_dir_z(ft,iv) + Abs_dif_z(ft,iv)) - end if - ! Solar radiation absorbed by vegetation and sunlit/shaded leaves - do iv = 1,currentPatch%nrad(L,ft) - if (radtype == 1)then - currentPatch%fabd(ib) = currentPatch%fabd(ib) + Abs_dir_z(ft,iv)+Abs_dif_z(ft,iv) - ! bc_out(s)%fabd_parb(ifp,ib) = currentPatch%fabd(ib) - else - currentPatch%fabi(ib) = currentPatch%fabi(ib) + Abs_dif_z(ft,iv) - ! bc_out(s)%fabi_parb(ifp,ib) = currentPatch%fabi(ib) - endif - end do - ! Albefor - if (L==1)then !top canopy layer. - if (radtype == 1)then - bc_out(s)%albd_parb(ifp,ib) = bc_out(s)%albd_parb(ifp,ib) + & - Dif_up(L,ft,1) * ftweight(L,ft,1) - else - bc_out(s)%albi_parb(ifp,ib) = bc_out(s)%albi_parb(ifp,ib) + & - Dif_up(L,ft,1) * ftweight(L,ft,1) - end if - end if - end if ! present - end do !ft - if (radtype == 1)then - bc_out(s)%fabd_parb(ifp,ib) = currentPatch%fabd(ib) - else - bc_out(s)%fabi_parb(ifp,ib) = currentPatch%fabi(ib) - endif - - - !radiation absorbed from fluxes through unfilled part of lower canopy. - if (currentPatch%NCL_p > 1.and.L == currentPatch%NCL_p)then - abs_rad(ib) = abs_rad(ib) + weighted_dif_down(L-1) * & - (1.0_r8-sum(ftweight(L,:,1)))*(1.0_r8-bc_in(s)%albgr_dif_rb(ib)) - abs_rad(ib) = abs_rad(ib) + forc_dir(ifp,ib) * weighted_dir_tr(L-1) * & - (1.0_r8-sum(ftweight(L,:,1)))*(1.0_r8-bc_in(s)%albgr_dir_rb(ib)) - tr_soili = tr_soili + weighted_dif_down(L-1) * (1.0_r8-sum(ftweight(L,:,1))) - tr_soild = tr_soild + forc_dir(ifp,ib) * weighted_dir_tr(L-1) * (1.0_r8-sum(ftweight(L,:,1))) - endif - - if (radtype == 1)then - currentPatch%tr_soil_dir(ib) = tr_soild - currentPatch%tr_soil_dir_dif(ib) = tr_soili - currentPatch%sabs_dir(ib) = abs_rad(ib) - bc_out(s)%ftdd_parb(ifp,ib) = tr_soild - bc_out(s)%ftid_parb(ifp,ib) = tr_soili - else - currentPatch%tr_soil_dif(ib) = tr_soili - currentPatch%sabs_dif(ib) = abs_rad(ib) - bc_out(s)%ftii_parb(ifp,ib) = tr_soili - end if - - end do!l - - - !==============================================================================! - ! Conservation check - !==============================================================================! - ! Total radiation balance: absorbed = incoming - outgoing - - if (radtype == 1)then - error = abs(currentPatch%sabs_dir(ib) - (currentPatch%tr_soil_dir(ib) * & - (1.0_r8-bc_in(s)%albgr_dir_rb(ib)) + & - currentPatch%tr_soil_dir_dif(ib) * (1.0_r8-bc_in(s)%albgr_dif_rb(ib)))) - if ( abs(error) > 0.0001)then - write(iulog,*)'dir ground absorption error',ifp,s,error,currentPatch%sabs_dir(ib), & - currentPatch%tr_soil_dir(ib)* & - (1.0_r8-bc_in(s)%albgr_dir_rb(ib)),currentPatch%NCL_p,ib,sum(ftweight(1,:,1)) - write(iulog,*) 'albedos',currentPatch%sabs_dir(ib) ,currentPatch%tr_soil_dir(ib), & - (1.0_r8-bc_in(s)%albgr_dir_rb(ib)),currentPatch%lai - - do ft =1,3 - iv = currentPatch%nrad(1,ft) + 1 - write(iulog,*) 'abs soil fluxes', Abs_dir_z(ft,iv),Abs_dif_z(ft,iv) - end do - - end if - else - if ( abs(currentPatch%sabs_dif(ib)-(currentPatch%tr_soil_dif(ib) * & - (1.0_r8-bc_in(s)%albgr_dif_rb(ib)))) > 0.0001)then - write(iulog,*)'dif ground absorption error',ifp,s,currentPatch%sabs_dif(ib) , & - (currentPatch%tr_soil_dif(ib)* & - (1.0_r8-bc_in(s)%albgr_dif_rb(ib))),currentPatch%NCL_p,ib,sum(ftweight(1,:,1)) - endif - endif - - if (radtype == 1)then - error = (forc_dir(ifp,ib) + forc_dif(ifp,ib)) - & - (bc_out(s)%fabd_parb(ifp,ib) + bc_out(s)%albd_parb(ifp,ib) + currentPatch%sabs_dir(ib)) - else - error = (forc_dir(ifp,ib) + forc_dif(ifp,ib)) - & - (bc_out(s)%fabi_parb(ifp,ib) + bc_out(s)%albi_parb(ifp,ib) + currentPatch%sabs_dif(ib)) - endif - lai_reduction(:) = 0.0_r8 - do L = 1, currentPatch%NCL_p - do ft =1,numpft_ed - if (currentPatch%present(L,ft) == 1)then - do iv = 1, currentPatch%nrad(L,ft) - if (lai_change(L,ft,iv) > 0.0_r8)then - lai_reduction(L) = max(lai_reduction(L),lai_change(L,ft,iv)) - endif - enddo - endif - enddo - enddo - if (lai_change(1,2,1).gt.0.0.and.lai_change(1,2,2).gt.0.0)then - ! write(iulog,*) 'lai_change(1,2,12)',lai_change(1,2,1:4) - endif - if (lai_change(1,2,2).gt.0.0.and.lai_change(1,2,3).gt.0.0)then - ! write(iulog,*) ' lai_change (1,2,23)',lai_change(1,2,1:4) - endif - if (lai_change(1,1,3).gt.0.0.and.lai_change(1,1,2).gt.0.0)then - ! NO-OP - ! write(iulog,*) 'first layer of lai_change 2 3',lai_change(1,1,1:3) - endif - if (lai_change(1,1,3).gt.0.0.and.lai_change(1,1,4).gt.0.0)then - ! NO-OP - ! write(iulog,*) 'first layer of lai_change 3 4',lai_change(1,1,1:4) - endif - if (lai_change(1,1,4).gt.0.0.and.lai_change(1,1,5).gt.0.0)then - ! NO-OP - ! write(iulog,*) 'first layer of lai_change 4 5',lai_change(1,1,1:5) - endif - - if (radtype == 1)then - !here we are adding a within-ED radiation scheme tolerance, and then adding the diffrence onto the albedo - !it is important that the lower boundary for this is ~1000 times smaller than the tolerance in surface albedo. - if (abs(error) > 1.e-9_r8 .and. abs(error) < 0.15_r8)then - bc_out(s)%albd_parb(ifp,ib) = bc_out(s)%albd_parb(ifp,ib) + error - !this terms adds the error back on to the albedo. While this is partly inexcusable, it is - ! in the medium term a solution that - ! prevents the model from crashing with small and occasional energy balances issues. - ! These are extremely difficult to debug, many have been solved already, leading - ! to the complexity of this code, but where the system generates occasional errors, we - ! will deal with them for now. - end if - if (abs(error) > 0.15_r8)then - write(iulog,*) 'Large Dir Radn consvn error',error ,ifp,ib - write(iulog,*) 'diags', bc_out(s)%albd_parb(ifp,ib), bc_out(s)%ftdd_parb(ifp,ib), & - bc_out(s)%ftid_parb(ifp,ib), bc_out(s)%fabd_parb(ifp,ib) - write(iulog,*) 'lai_change',lai_change(currentpatch%ncl_p,1:2,1:4) - write(iulog,*) 'elai',currentpatch%elai_profile(currentpatch%ncl_p,1:2,1:4) - write(iulog,*) 'esai',currentpatch%esai_profile(currentpatch%ncl_p,1:2,1:4) - write(iulog,*) 'ftweight',ftweight(1,1:2,1:4) - write(iulog,*) 'cp',currentPatch%area, currentPatch%patchno - write(iulog,*) 'bc_in(s)%albgr_dir_rb(ib)',bc_in(s)%albgr_dir_rb(ib) - - bc_out(s)%albd_parb(ifp,ib) = bc_out(s)%albd_parb(ifp,ib) + error - end if - else - - if (abs(error) > 1.e-9_r8 .and. abs(error) < 0.15_r8)then - bc_out(s)%albi_parb(ifp,ib) = bc_out(s)%albi_parb(ifp,ib) + error - end if - - if (abs(error) > 0.15_r8)then - write(iulog,*) '>5% Dif Radn consvn error',error ,ifp,ib - write(iulog,*) 'diags', bc_out(s)%albi_parb(ifp,ib), bc_out(s)%ftii_parb(ifp,ib), & - bc_out(s)%fabi_parb(ifp,ib) - write(iulog,*) 'lai_change',lai_change(currentpatch%ncl_p,1:2,1:4) - write(iulog,*) 'elai',currentpatch%elai_profile(currentpatch%ncl_p,1:2,1:4) - write(iulog,*) 'esai',currentpatch%esai_profile(currentpatch%ncl_p,1:2,1:4) - write(iulog,*) 'ftweight',ftweight(currentpatch%ncl_p,1:2,1:4) - write(iulog,*) 'cp',currentPatch%area, currentPatch%patchno - write(iulog,*) 'bc_in(s)%albgr_dif_rb(ib)',bc_in(s)%albgr_dif_rb(ib) - write(iulog,*) 'rhol',rhol(1:2,:) - write(iulog,*) 'ftw',sum(ftweight(1,:,1)),ftweight(1,1:2,1) - write(iulog,*) 'present',currentPatch%present(1,1:2) - write(iulog,*) 'CAP',currentPatch%canopy_area_profile(1,1:2,1) - - bc_out(s)%albi_parb(ifp,ib) = bc_out(s)%albi_parb(ifp,ib) + error - end if - - if (radtype == 1)then - error = (forc_dir(ifp,ib) + forc_dif(ifp,ib)) - & - (bc_out(s)%fabd_parb(ifp,ib) + bc_out(s)%albd_parb(ifp,ib) + currentPatch%sabs_dir(ib)) - else - error = (forc_dir(ifp,ib) + forc_dif(ifp,ib)) - & - (bc_out(s)%fabi_parb(ifp,ib) + bc_out(s)%albi_parb(ifp,ib) + currentPatch%sabs_dif(ib)) - endif - - if (abs(error) > 0.00000001_r8)then - write(iulog,*) 'there is still error after correction',error ,ifp,ib - end if - - end if - - end do !cp_numSWb - - enddo ! rad-type - endif ! is there vegetation? - - end if ! if the vegetation and zenith filter is active - currentPatch => currentPatch%younger - end do ! Loop linked-list patches - enddo ! Loop Sites - - end associate - return - end subroutine ED_Norman_Radiation - - ! ====================================================================================== - - subroutine ED_SunShadeFracs(nsites, sites,bc_in,bc_out) - - use clm_varctl , only : iulog - - implicit none - - ! Arguments - integer,intent(in) :: nsites - type(ed_site_type),intent(inout),target :: sites(nsites) - type(bc_in_type),intent(in) :: bc_in(nsites) - type(bc_out_type),intent(inout) :: bc_out(nsites) - - - ! locals - type (ed_patch_type),pointer :: cpatch ! c"urrent" patch - real(r8) :: sunlai - real(r8) :: shalai - real(r8) :: elai - integer :: CL - integer :: FT - integer :: iv - integer :: s - integer :: ifp - - - do s = 1,nsites - - ifp = 0 - cpatch => sites(s)%oldest_patch - - do while (associated(cpatch)) - - ifp=ifp+1 - - if( DEBUG ) write(iulog,*) 'edsurfRad_5600',ifp,s,cpatch%NCL_p,numpft_ed - - ! zero out various datas - cpatch%ed_parsun_z(:,:,:) = 0._r8 - cpatch%ed_parsha_z(:,:,:) = 0._r8 - cpatch%ed_laisun_z(:,:,:) = 0._r8 - cpatch%ed_laisha_z(:,:,:) = 0._r8 - - bc_out(s)%fsun_pa(ifp) = 0._r8 - - sunlai = 0._r8 - shalai = 0._r8 - - ! Loop over patches to calculate laisun_z and laisha_z for each layer. - ! Derive canopy laisun, laisha, and fsun from layer sums. - ! If sun/shade big leaf code, nrad=1 and fsun_z(p,1) and tlai_z(p,1) from - ! SurfaceAlbedo is canopy integrated so that layer value equals canopy value. - - ! cpatch%f_sun is calculated in the surface_albedo routine... - - do CL = 1, cpatch%NCL_p - do FT = 1,numpft_ed - - if( DEBUG ) write(iulog,*) 'edsurfRad_5601',CL,FT,cpatch%nrad(CL,ft) - - do iv = 1, cpatch%nrad(CL,ft) !NORMAL CASE. - - ! FIX(SPM,040114) - existing comment - ! ** Should this be elai or tlai? Surely we only do radiation for elai? - - cpatch%ed_laisun_z(CL,ft,iv) = cpatch%elai_profile(CL,ft,iv) * & - cpatch%f_sun(CL,ft,iv) - - if ( DEBUG ) write(iulog,*) 'edsurfRad 570 ',cpatch%elai_profile(CL,ft,iv) - if ( DEBUG ) write(iulog,*) 'edsurfRad 571 ',cpatch%f_sun(CL,ft,iv) - - cpatch%ed_laisha_z(CL,ft,iv) = cpatch%elai_profile(CL,ft,iv) * & - (1._r8 - cpatch%f_sun(CL,ft,iv)) - - end do - - !needed for the VOC emissions, etc. - sunlai = sunlai + sum(cpatch%ed_laisun_z(CL,ft,1:cpatch%nrad(CL,ft))) - shalai = shalai + sum(cpatch%ed_laisha_z(CL,ft,1:cpatch%nrad(CL,ft))) - - end do - end do - - if(sunlai+shalai > 0._r8)then - bc_out(s)%fsun_pa(ifp) = sunlai / (sunlai+shalai) - else - bc_out(s)%fsun_pa(ifp) = 0._r8 - endif - - if(bc_out(s)%fsun_pa(ifp) > 1._r8)then - write(iulog,*) 'too much leaf area in profile', bc_out(s)%fsun_pa(ifp), & - cpatch%lai,sunlai,shalai - endif - - elai = calc_areaindex(cpatch,'elai') - - bc_out(s)%laisun_pa(ifp) = elai*bc_out(s)%fsun_pa(ifp) - bc_out(s)%laisha_pa(ifp) = elai*(1.0_r8-bc_out(s)%fsun_pa(ifp)) - - ! Absorbed PAR profile through canopy - ! If sun/shade big leaf code, nrad=1 and fluxes from SurfaceAlbedo - ! are canopy integrated so that layer values equal big leaf values. - - if ( DEBUG ) write(iulog,*) 'edsurfRad 645 ',cpatch%NCL_p,numpft_ed - - do CL = 1, cpatch%NCL_p - do FT = 1,numpft_ed - - if ( DEBUG ) write(iulog,*) 'edsurfRad 649 ',cpatch%nrad(CL,ft) - - do iv = 1, cpatch%nrad(CL,ft) - - if ( DEBUG ) then - write(iulog,*) 'edsurfRad 653 ', cpatch%ed_parsun_z(CL,ft,iv) - write(iulog,*) 'edsurfRad 654 ', bc_in(s)%solad_parb(ifp,ipar) - write(iulog,*) 'edsurfRad 655 ', bc_in(s)%solai_parb(ifp,ipar) - write(iulog,*) 'edsurfRad 656 ', cpatch%fabd_sun_z(CL,ft,iv) - write(iulog,*) 'edsurfRad 657 ', cpatch%fabi_sun_z(CL,ft,iv) - endif - - cpatch%ed_parsun_z(CL,ft,iv) = & - bc_in(s)%solad_parb(ifp,ipar)*cpatch%fabd_sun_z(CL,ft,iv) + & - bc_in(s)%solai_parb(ifp,ipar)*cpatch%fabi_sun_z(CL,ft,iv) - - if ( DEBUG )write(iulog,*) 'edsurfRad 663 ', cpatch%ed_parsun_z(CL,ft,iv) - - cpatch%ed_parsha_z(CL,ft,iv) = & - bc_in(s)%solad_parb(ifp,ipar)*cpatch%fabd_sha_z(CL,ft,iv) + & - bc_in(s)%solai_parb(ifp,ipar)*cpatch%fabi_sha_z(CL,ft,iv) - - if ( DEBUG ) write(iulog,*) 'edsurfRad 669 ', cpatch%ed_parsha_z(CL,ft,iv) - - end do !iv - end do !FT - end do !CL - - cpatch => cpatch%younger - enddo - - - enddo - return - -end subroutine ED_SunShadeFracs - - -! ! MOVE TO THE INTERFACE -! subroutine ED_CheckSolarBalance(g,filter_nourbanp,num_nourbanp,fsa,fsr,forc_solad,forc_solai) - - -! implicit none -! integer,intent(in),dimension(:) :: gridcell ! => gridcell index -! integer,intent(in),dimension(:) :: filter_nourbanp ! => patch filter for non-urban points -! integer, intent(in) :: num_nourbanp ! number of patches in non-urban points in patch filter -! real(r8),intent(in),dimension(:,:) :: forc_solad ! => atm2lnd_inst%forc_solad_grc, direct radiation (W/m**2 -! real(r8),intent(in),dimension(:,:) :: forc_solai ! => atm2lnd_inst%forc_solai_grc, diffuse radiation (W/m**2) -! real(r8),intent(in),dimension(:,:) :: fsa ! => solarabs_inst%fsa_patch, solar radiation absorbed (total) (W/m**2) -! real(r8),intent(in),dimension(:,:) :: fsr ! => solarabs_inst%fsr_patch, solar radiation reflected (W/m**2) - -! integer :: p -! integer :: fp -! integer :: g -! real(r8) :: errsol - -! do fp = 1,num_nourbanp -! p = filter_nourbanp(fp) -! g = gridcell(p) -! errsol = (fsa(p) + fsr(p) - (forc_solad(g,1) + forc_solad(g,2) + forc_solai(g,1) + forc_solai(g,2))) -! if(abs(errsol) > 0.1_r8)then -! write(iulog,*) 'sol error in surf rad',p,g, errsol -! endif -! end do -! return -! end subroutine ED_CheckSolarBalance - - -end module EDSurfaceRadiationMod diff --git a/src/ED/fire/SFMainMod.F90 b/src/ED/fire/SFMainMod.F90 deleted file mode 100755 index 075f797b5c..0000000000 --- a/src/ED/fire/SFMainMod.F90 +++ /dev/null @@ -1,947 +0,0 @@ -module SFMainMod - - ! ============================================================================ - ! All subroutines realted to the SPITFIRE fire routine. - ! Code originally developed by Allan Spessa & Rosie Fisher as part of the NERC-QUEST project. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8; - use spmdMod , only : masterproc - use clm_varctl , only : iulog - use atm2lndType , only : atm2lnd_type - use TemperatureType , only : temperature_type - use pftconMod , only : pftcon - use EDEcophysconType , only : EDecophyscon - use EDtypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type, AREA, DG_SF, FIRE_THRESHOLD - use EDtypesMod , only : LB_SF, LG_SF, NCWD, TR_SF - - implicit none - private - - public :: fire_model - public :: fire_danger_index - public :: charecteristics_of_fuel - public :: rate_of_spread - public :: ground_fuel_consumption - public :: fire_intensity - public :: wind_effect - public :: area_burnt - public :: crown_scorching - public :: crown_damage - public :: cambial_damage_kill - public :: post_fire_mortality - - integer :: write_SF = 0 ! for debugging - logical :: DEBUG = .false. ! for debugging - - ! ============================================================================ - ! ============================================================================ - -contains - - ! ============================================================================ - ! Area of site burned by fire - ! ============================================================================ - subroutine fire_model( currentSite, atm2lnd_inst, temperature_inst) - - use clm_varctl, only : use_ed_spit_fire - - type(ed_site_type) , intent(inout), target :: currentSite - type(atm2lnd_type) , intent(in) :: atm2lnd_inst - type(temperature_type) , intent(in) :: temperature_inst - - type (ed_patch_type), pointer :: currentPatch - - integer temporary_SF_switch - - !zero fire things - currentPatch => currentSite%youngest_patch - temporary_SF_switch = 0 - do while(associated(currentPatch)) - currentPatch%frac_burnt = 0.0_r8 - currentPatch%AB = 0.0_r8 - currentPatch%fire = 0 - currentPatch => currentPatch%older - enddo - - if(write_SF==1)then - write(iulog,*) 'use_ed_spit_fire',use_ed_spit_fire - endif - - if(use_ed_spit_fire.and.temporary_SF_switch==1)then - call fire_danger_index(currentSite, temperature_inst, atm2lnd_inst) - call wind_effect(currentSite, atm2lnd_inst) - call charecteristics_of_fuel(currentSite) - call rate_of_spread(currentSite) - call ground_fuel_consumption(currentSite) - call fire_intensity(currentSite) - call area_burnt(currentSite) - call crown_scorching(currentSite) - call crown_damage(currentSite) - call cambial_damage_kill(currentSite) - call post_fire_mortality(currentSite) - end if - - end subroutine fire_model - - !***************************************************************** - subroutine fire_danger_index ( currentSite, temperature_inst, atm2lnd_inst) - - !***************************************************************** - ! currentSite%acc_NI is the accumulated Nesterov fire danger index - - use clm_varcon , only : tfrz - - use SFParamsMod, only : SF_val_fdi_a, SF_val_fdi_b - - type(ed_site_type) , intent(inout), target :: currentSite - type(temperature_type) , intent(in) :: temperature_inst - type(atm2lnd_type) , intent(in) :: atm2lnd_inst - - real(r8) :: temp_in_C ! daily averaged temperature in celcius - real(r8) :: rainfall ! daily precip - real(r8) :: rh ! daily rh - - real yipsolon; !intermediate varable for dewpoint calculation - real dewpoint; !dewpoint in K - real d_NI; !daily change in Nesterov Index. C^2 - - associate( & - t_veg24 => temperature_inst%t_veg24_patch , & ! Input: [real(r8) (:)] avg pft vegetation temperature for last 24 hrs - - prec24 => atm2lnd_inst%prec24_patch , & ! Input: [real(r8) (:)] avg pft rainfall for last 24 hrs - rh24 => atm2lnd_inst%rh24_patch & ! Input: [real(r8) (:)] avg pft relative humidity for last 24 hrs - ) - - ! NOTE: t_veg24(:), prec24(:) and rh24(:) are p level temperatures, precipitation and RH, - ! which probably won't have much inpact, unless we decide to ever calculated the NI for each patch. - - temp_in_C = t_veg24(currentSite%oldest_patch%clm_pno) - tfrz - rainfall = prec24(currentSite%oldest_patch%clm_pno) *24.0_r8*3600._r8 - rh = rh24(currentSite%oldest_patch%clm_pno) - - if (rainfall > 3.0_r8) then !rezero NI if it rains... - d_NI = 0.0_r8 - currentSite%acc_NI = 0.0_r8 - else - yipsolon = (SF_val_fdi_a* temp_in_C)/(SF_val_fdi_b+ temp_in_C)+log(rh/100.0_r8) - dewpoint = (SF_val_fdi_b*yipsolon)/(SF_val_fdi_a-yipsolon) !Standard met. formula - d_NI = ( temp_in_C-dewpoint)* temp_in_C !follows Nesterov 1968. Equation 5. Thonicke et al. 2010. - if (d_NI < 0.0_r8) then !Change in NI cannot be negative. - d_NI = 0.0_r8 !check - endif - endif - currentSite%acc_NI = currentSite%acc_NI + d_NI !Accumulate Nesterov index over the fire season. - - end associate - - end subroutine fire_danger_index - - - !***************************************************************** - subroutine charecteristics_of_fuel ( currentSite ) - !***************************************************************** - - use SFParamsMod, only : SF_val_alpha_FMC, SF_val_SAV, SF_val_FBD - - type(ed_site_type), intent(in), target :: currentSite - - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - real(r8) timeav_swc - real(r8) fuel_moisture(ncwd+2) ! Scaled moisture content of small litter fuels. - real(r8) MEF(ncwd+2) ! Moisture extinction factor of fuels integer n - - fuel_moisture(:) = 0.0_r8 - - currentPatch => currentSite%oldest_patch; - do while(associated(currentPatch)) - ! How much live grass is there? - currentPatch%livegrass = 0.0_r8 - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - if(pftcon%woody(currentCohort%pft) == 0)then - currentPatch%livegrass = currentPatch%livegrass + currentCohort%bl*currentCohort%n/currentPatch%area - endif - currentCohort => currentCohort%shorter - enddo - - ! There are SIX fuel classes - ! 1) Leaf litter, 2:5) four CWD_AG pools (twig, s branch, l branch, trunk) and 6) live grass - ! NCWD =4 - ! dg_sf = 1, lb_sf, = 4, tr_sf = 5, lg_sf = 6, - - ! zero fire arrays. - currentPatch%fuel_eff_moist = 0.0_r8 - currentPatch%fuel_bulkd = 0.0_r8 - currentPatch%fuel_sav = 0.0_r8 - currentPatch%fuel_frac(:) = 0.0_r8 - currentPatch%fuel_mef = 0.0_r8 - currentPatch%sum_fuel = 0.0_r8 - currentPatch%fuel_frac = 0.0_r8 - - if(write_sf == 1)then - if (masterproc) write(iulog,*) ' leaf_litter1 ',currentPatch%leaf_litter - if (masterproc) write(iulog,*) ' leaf_litter2 ',sum(currentPatch%CWD_AG) - if (masterproc) write(iulog,*) ' leaf_litter3 ',currentPatch%livegrass - if (masterproc) write(iulog,*) ' sum fuel', currentPatch%sum_fuel - endif - - currentPatch%sum_fuel = sum(currentPatch%leaf_litter) + sum(currentPatch%CWD_AG) + currentPatch%livegrass - if(write_SF == 1)then - if (masterproc) write(iulog,*) 'sum fuel', currentPatch%sum_fuel,currentPatch%area - endif - ! =============================================== - ! Average moisture, bulk density, surface area-volume and moisture extinction of fuel - ! ================================================ - - if (currentPatch%sum_fuel > 0.0) then - ! Fraction of fuel in litter classes - currentPatch%fuel_frac(dg_sf) = sum(currentPatch%leaf_litter)/ currentPatch%sum_fuel - currentPatch%fuel_frac(dg_sf+1:tr_sf) = currentPatch%CWD_AG / currentPatch%sum_fuel - - if(write_sf == 1)then - if (masterproc) write(iulog,*) 'ff1 ',currentPatch%fuel_frac - if (masterproc) write(iulog,*) 'ff2 ',currentPatch%fuel_frac - if (masterproc) write(iulog,*) 'ff2a ',lg_sf,currentPatch%livegrass,currentPatch%sum_fuel - endif - - currentPatch%fuel_frac(lg_sf) = currentPatch%livegrass / currentPatch%sum_fuel - MEF(1:ncwd+2) = 0.524_r8 - 0.066_r8 * log10(SF_val_SAV(1:ncwd+2)) - - !Equation 6 in Thonicke et al. 2010. - fuel_moisture(dg_sf+1:tr_sf) = exp(-1.0_r8 * SF_val_alpha_FMC(dg_sf+1:tr_sf) * currentSite%acc_NI) - if(write_SF == 1)then - if (masterproc) write(iulog,*) 'ff3 ',currentPatch%fuel_frac - if (masterproc) write(iulog,*) 'fm ',fuel_moisture - if (masterproc) write(iulog,*) 'csa ',currentSite%acc_NI - if (masterproc) write(iulog,*) 'sfv ',SF_val_alpha_FMC - endif - ! FIX(RF,032414): needs refactoring. - ! average water content !is this the correct metric? - timeav_swc = sum(currentSite%water_memory(1:10)) / 10._r8 - ! Equation B2 in Thonicke et al. 2010 - fuel_moisture(dg_sf) = max(0.0_r8, 10.0_r8/9._r8 * timeav_swc - 1.0_r8/9.0_r8) - - ! Average properties over the first four litter pools (dead leaves, twigs, s branches, l branches) - currentPatch%fuel_bulkd = sum(currentPatch%fuel_frac(dg_sf:lb_sf) * SF_val_FBD(dg_sf:lb_sf)) - currentPatch%fuel_sav = sum(currentPatch%fuel_frac(dg_sf:lb_sf) * SF_val_SAV(dg_sf:lb_sf)) - currentPatch%fuel_mef = sum(currentPatch%fuel_frac(dg_sf:lb_sf) * MEF(dg_sf:lb_sf)) - currentPatch%fuel_eff_moist = sum(currentPatch%fuel_frac(dg_sf:lb_sf) * fuel_moisture(dg_sf:lb_sf)) - if(write_sf == 1)then - if (masterproc) write(iulog,*) 'ff4 ',currentPatch%fuel_eff_moist - endif - ! Add on properties of live grass multiplied by grass fraction. (6) - currentPatch%fuel_bulkd = currentPatch%fuel_bulkd + currentPatch%fuel_frac(lg_sf) * SF_val_FBD(lg_sf) - currentPatch%fuel_sav = currentPatch%fuel_sav + currentPatch%fuel_frac(lg_sf) * SF_val_SAV(lg_sf) - currentPatch%fuel_mef = currentPatch%fuel_mef + currentPatch%fuel_frac(lg_sf) * MEF(lg_sf) - currentPatch%fuel_eff_moist = currentPatch%fuel_eff_moist + currentPatch%fuel_frac(lg_sf) * fuel_moisture(lg_sf) - - ! Correct averaging for the fact that we are not using the trunks pool (5) - currentPatch%fuel_bulkd = currentPatch%fuel_bulkd * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - currentPatch%fuel_sav = currentPatch%fuel_sav * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - currentPatch%fuel_mef = currentPatch%fuel_mef * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - currentPatch%fuel_eff_moist = currentPatch%fuel_eff_moist * (1.0_r8/(1.0_r8-currentPatch%fuel_frac(tr_sf))) - - ! Convert from biomass to carbon. Which variables is this needed for? - currentPatch%fuel_bulkd = currentPatch%fuel_bulkd * 0.45_r8 - - ! Pass litter moisture into the fuel burning routine - ! (wo/me term in Thonicke et al. 2010) - currentPatch%litter_moisture(dg_sf:lb_sf) = fuel_moisture(dg_sf:lb_sf)/MEF(dg_sf:lb_sf) - currentPatch%litter_moisture(tr_sf) = 0.0_r8 - currentPatch%litter_moisture(lg_sf) = fuel_moisture(lg_sf)/MEF(lg_sf) - - else - - if(write_SF == 1)then - - if (masterproc) write(iulog,*) 'no litter fuel at all',currentPatch%patchno, & - currentPatch%sum_fuel,sum(currentPatch%cwd_ag), & - sum(currentPatch%cwd_bg),sum(currentPatch%leaf_litter) - - endif - currentPatch%fuel_sav = sum(SF_val_SAV(1:ncwd+2))/(ncwd+2) ! make average sav to avoid crashing code. - - if (masterproc) write(iulog,*) 'problem with spitfire fuel averaging' - - ! FIX(SPM,032414) refactor...should not have 0 fuel unless everything is burnt - ! off. - currentPatch%fuel_eff_moist = 0.0000000001_r8 - currentPatch%fuel_bulkd = 0.0000000001_r8 - currentPatch%fuel_frac(:) = 0.0000000001_r8 - currentPatch%fuel_mef = 0.0000000001_r8 - currentPatch%sum_fuel = 0.0000000001_r8 - currentPatch%fuel_frac = 0.0000000001_r8 - - endif - ! check values. - ! FIX(SPM,032414) refactor... - if(write_SF == 1.and.currentPatch%fuel_sav <= 0.0_r8.or.currentPatch%fuel_bulkd <= & - 0.0_r8.or.currentPatch%fuel_mef <= 0.0_r8.or.currentPatch%fuel_eff_moist <= 0.0_r8)then - if (masterproc) write(iulog,*) 'problem with spitfire fuel averaging' - endif - - currentPatch => currentPatch%younger - - enddo !end patch loop - - end subroutine charecteristics_of_fuel - - - !***************************************************************** - subroutine wind_effect ( currentSite, atm2lnd_inst) - !*****************************************************************. - - ! Routine called daily from within ED within a site loop. - ! Calculates the effective windspeed based on vegetation charecteristics. - - type(ed_site_type) , intent(inout), target :: currentSite - type(atm2lnd_type) , intent(in) :: atm2lnd_inst - - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - ! note - this is a p level temperature, which probably won't have much inpact, - ! unless we decide to ever calculated the NI for each patch. - real(r8), pointer :: wind24(:) - - real(r8) :: wind ! daily wind - real(r8) :: total_grass_area ! per patch,in m2 - real(r8) :: tree_fraction ! site level. no units - real(r8) :: grass_fraction ! site level. no units - real(r8) :: bare_fraction ! site level. no units - - wind24 => atm2lnd_inst%wind24_patch ! Input: [real(r8) (:)] avg pft windspeed (m/s) - - wind = wind24(currentSite%oldest_patch%clm_pno) * 60._r8 ! Convert to m/min for SPITFIRE units. - if(write_SF == 1)then - if (masterproc) write(iulog,*) 'wind24', wind24(currentSite%oldest_patch%clm_pno) - endif - ! --- influence of wind speed, corrected for surface roughness---- - ! --- averaged over the whole grid cell to prevent extreme divergence - ! average_wspeed = 0.0_r8 - tree_fraction = 0.0_r8 - grass_fraction = 0.0_r8 - currentPatch=>currentSite%oldest_patch; - do while(associated(currentPatch)) - currentPatch%total_tree_area = 0.0_r8 - total_grass_area = 0.0_r8 - currentCohort => currentPatch%tallest - - do while(associated(currentCohort)) - write(iulog,*) 'SF currentCohort%c_area ',currentCohort%c_area - if(pftcon%woody(currentCohort%pft) == 1)then - currentPatch%total_tree_area = currentPatch%total_tree_area + currentCohort%c_area - else - total_grass_area = total_grass_area + currentCohort%c_area - endif - currentCohort => currentCohort%shorter - enddo - tree_fraction = tree_fraction + min(currentPatch%area,currentPatch%total_tree_area)/AREA - grass_fraction = grass_fraction + min(currentPatch%area,total_grass_area)/AREA - - if(DEBUG)then - !write(iulog,*) 'SF currentPatch%area ',currentPatch%area - !write(iulog,*) 'SF currentPatch%total_area ',currentPatch%total_tree_area - !write(iulog,*) 'SF total_grass_area ',tree_fraction,grass_fraction - !write(iulog,*) 'SF AREA ',AREA - endif - - currentPatch => currentPatch%younger - enddo !currentPatch loop - - !if there is a cover of more than one, then the grasses are under the trees - grass_fraction = min(grass_fraction,1.0_r8-tree_fraction) - bare_fraction = 1.0 - tree_fraction - grass_fraction - if(write_sf == 1)then - if (masterproc) write(iulog,*) 'grass, trees, bare',grass_fraction, tree_fraction, bare_fraction - endif - - currentPatch=>currentSite%oldest_patch; - - do while(associated(currentPatch)) - currentPatch%total_tree_area = min(currentPatch%total_tree_area,currentPatch%area) - currentPatch%effect_wspeed = wind * (tree_fraction*0.6+grass_fraction*0.4+bare_fraction*1.0) - - currentPatch => currentPatch%younger - enddo !end patch loop - - end subroutine wind_effect - - !***************************************************************** - subroutine rate_of_spread ( currentSite ) - !*****************************************************************. - !Routine called daily from within ED within a site loop. - !Returns the updated currentPatch%ROS_front value for each patch. - - use SFParamsMod, only : SF_val_miner_total, SF_val_part_dens, & - SF_val_miner_damp, SF_val_fuel_energy - - type(ed_site_type), intent(in), target :: currentSite - - type(ed_patch_type), pointer :: currentPatch - - real(r8) dummy - - ! Rothermal fire spread model parameters. - real(r8) beta - real(r8) ir !reaction intensity - real(r8) xi,eps,q_ig,phi_wind - real(r8) gamma_aptr,gamma_max - real(r8) moist_damp,mw_weight - real(r8) bet,beta_op - real(r8) a,b,c,e - - currentPatch=>currentSite%oldest_patch; - - do while(associated(currentPatch)) - - ! ---initialise parameters to zero.--- - bet = 0.0_r8; q_ig = 0.0_r8; eps = 0.0_r8; a = 0.0_r8; b = 0.0_r8; c = 0.0_r8; e = 0.0_r8 - phi_wind = 0.0_r8; xi = 0.0_r8; gamma_max = 0.0_r8; gamma_aptr = 0.0_r8; mw_weight = 0.0_r8 - moist_damp = 0.0_r8; ir = 0.0_r8; dummy = 0.0_r8; - currentPatch%ROS_front = 0.0_r8 - currentPatch%sum_fuel = currentPatch%sum_fuel * (1.0_r8 - SF_val_miner_total) !net of minerals - - ! ----start spreading--- - if (masterproc.and.DEBUG) write(iulog,*) 'SF - currentPatch%fuel_bulkd ',currentPatch%fuel_bulkd - if (masterproc.and.DEBUG) write(iulog,*) 'SF - SF_val_part_dens ',SF_val_part_dens - - beta = (currentPatch%fuel_bulkd / 0.45_r8) / SF_val_part_dens - - ! Equation A6 in Thonicke et al. 2010 - beta_op = 0.200395_r8 *(currentPatch%fuel_sav**(-0.8189_r8)) - if (masterproc.and.DEBUG) write(iulog,*) 'SF - beta ',beta - if (masterproc.and.DEBUG) write(iulog,*) 'SF - beta_op ',beta_op - bet = beta/beta_op - if(write_sf == 1)then - if (masterproc) write(iulog,*) 'esf ',currentPatch%fuel_eff_moist - endif - ! ---heat of pre-ignition--- - ! Equation A4 in Thonicke et al. 2010 - q_ig = 581.0_r8 +2594.0_r8 * currentPatch%fuel_eff_moist - - ! ---effective heating number--- - ! Equation A3 in Thonicke et al. 2010. - eps = exp(-4.528_r8 / currentPatch%fuel_sav) - ! Equation A7 in Thonicke et al. 2010 - b = 0.15988_r8 * (currentPatch%fuel_sav**0.54_r8) - ! Equation A8 in Thonicke et al. 2010 - c = 7.47_r8 * (exp(-0.8711_r8 * (currentPatch%fuel_sav**0.55_r8))) - ! Equation A9 in Thonicke et al. 2010. - e = 0.715_r8 * (exp(-0.01094_r8 * currentPatch%fuel_sav)) - ! Equation A5 in Thonicke et al. 2010 - - if (DEBUG) then - if (masterproc.and.DEBUG) write(iulog,*) 'SF - c ',c - if (masterproc.and.DEBUG) write(iulog,*) 'SF - currentPatch%effect_wspeed ',currentPatch%effect_wspeed - if (masterproc.and.DEBUG) write(iulog,*) 'SF - b ',b - if (masterproc.and.DEBUG) write(iulog,*) 'SF - bet ',bet - if (masterproc.and.DEBUG) write(iulog,*) 'SF - e ',e - endif - - ! convert from m/min to ft/min for Rothermel ROS eqn - phi_wind = c * ((3.281_r8*currentPatch%effect_wspeed)**b)*(bet**(-e)) - - ! ---propagating flux---- - ! Equation A2 in Thonicke et al. - - xi = (exp((0.792_r8 + 3.7597_r8 * (currentPatch%fuel_sav**0.5_r8)) * (beta+0.1_r8))) / & - (192_r8+7.9095_r8 * currentPatch%fuel_sav) - - ! ---reaction intensity---- - ! Equation in table A1 Thonicke et al. 2010. - a = 8.9033_r8 * (currentPatch%fuel_sav**(-0.7913_r8)) - dummy = exp(a*(1-bet)) - ! Equation in table A1 Thonicke et al. 2010. - gamma_max = 1.0_r8 / (0.0591_r8 + 2.926_r8* (currentPatch%fuel_sav**(-1.5_r8))) - gamma_aptr = gamma_max*(bet**a)*dummy - - mw_weight = currentPatch%fuel_eff_moist/currentPatch%fuel_mef - - ! Equation in table A1 Thonicke et al. 2010. - moist_damp = max(0.0_r8,(1.0_r8 - (2.59_r8 * mw_weight) + (5.11_r8 * (mw_weight**2.0_r8)) - & - (3.52_r8*(mw_weight**3.0_r8)))) - - ! FIX(SPM, 040114) ask RF if this should be an endrun - ! if(write_SF == 1)then - ! write(iulog,*) 'moist_damp' ,moist_damp,mw_weight,currentPatch%fuel_eff_moist,currentPatch%fuel_mef - ! endif - - ir = gamma_aptr*(currentPatch%sum_fuel/0.45_r8)*SF_val_fuel_energy*moist_damp*SF_val_miner_damp - ! currentPatch%sum_fuel needs to be converted from kgC/m2 to kgBiomass/m2 - ! write(iulog,*) 'ir',gamma_aptr,moist_damp,SF_val_fuel_energy,SF_val_miner_damp - if (((currentPatch%fuel_bulkd/0.45_r8) <= 0.0_r8).or.(eps <= 0.0_r8).or.(q_ig <= 0.0_r8)) then - currentPatch%ROS_front = 0.0_r8 - else ! Equation 9. Thonicke et al. 2010. - currentPatch%ROS_front = (ir*xi*(1.0_r8+phi_wind)) / (currentPatch%fuel_bulkd/0.45_r8*eps*q_ig) - ! write(iulog,*) 'ROS',currentPatch%ROS_front,phi_wind,currentPatch%effect_wspeed - ! write(iulog,*) 'ros calcs',currentPatch%fuel_bulkd,ir,xi,eps,q_ig - endif - ! Equation 10 in Thonicke et al. 2010 - ! Can FBP System in m/min - currentPatch%ROS_back = currentPatch%ROS_front*exp(-0.012_r8*currentPatch%effect_wspeed) - - currentPatch => currentPatch%younger - - enddo !end patch loop - - end subroutine rate_of_spread - - !***************************************************************** - subroutine ground_fuel_consumption ( currentSite ) - !***************************************************************** - !returns the the hypothetic fuel consumed by the fire - - use SFParamsMod, only : SF_val_miner_total, SF_val_min_moisture, & - SF_val_mid_moisture, SF_val_low_moisture_C, SF_val_low_moisture_S, & - SF_val_mid_moisture_C, SF_val_mid_moisture_S - - type(ed_site_type) , intent(in), target :: currentSite - - type(ed_patch_type), pointer :: currentPatch - - real(r8) :: moist !effective fuel moisture - real(r8) :: tau_b(ncwd+2) !lethal heating rates for each fuel class (min) - real(r8) :: fc_ground(ncwd+2) !propn of fuel consumed - - integer :: c - - currentPatch => currentSite%oldest_patch; - - do while(associated(currentPatch)) - currentPatch%burnt_frac_litter = 1.0_r8 - ! Calculate fraction of litter is burnt for all classes. - ! Equation B1 in Thonicke et al. 2010--- - do c = 1, ncwd+2 !work out the burnt fraction for all pools, even if those pools dont exist. - moist = currentPatch%litter_moisture(c) - ! 1. Very dry litter - if (moist <= SF_val_min_moisture(c)) then - currentPatch%burnt_frac_litter(c) = 1.0_r8 - endif - ! 2. Low to medium moistures - if (moist > SF_val_min_moisture(c).and.moist <= SF_val_mid_moisture(c)) then - currentPatch%burnt_frac_litter(c) = max(0.0_r8,min(1.0_r8,SF_val_low_moisture_C(c)- & - SF_val_low_moisture_S(c)*moist)) - else - ! For medium to high moistures. - if (moist > SF_val_mid_moisture(c).and.moist <= 1.0_r8) then - currentPatch%burnt_frac_litter(c) = max(0.0_r8,min(1.0_r8,SF_val_mid_moisture_C(c)- & - SF_val_mid_moisture_S(c)*moist)) - endif - - endif - ! Very wet litter - if (moist >= 1.0_r8) then !this shouldn't happen? - currentPatch%burnt_frac_litter(c) = 0.0_r8 - endif - enddo !c - - ! we can't ever kill -all- of the grass. - currentPatch%burnt_frac_litter(lg_sf) = min(0.8_r8,currentPatch%burnt_frac_litter(lg_sf )) - ! reduce burnt amount for mineral content. - currentPatch%burnt_frac_litter = currentPatch%burnt_frac_litter * (1.0_r8-SF_val_miner_total) - - !---Calculate amount of fuel burnt.--- - FC_ground(dg_sf) = currentPatch%burnt_frac_litter(dg_sf) * sum(currentPatch%leaf_litter) - FC_ground(2:tr_sf) = currentPatch%burnt_frac_litter(2:tr_sf) * currentPatch%CWD_AG - FC_ground(lg_sf) = currentPatch%burnt_frac_litter(lg_sf) * currentPatch%livegrass - - ! Following used for determination of cambial kill follows from Peterson & Ryan (1986) scheme - ! less empirical cf current scheme used in SPITFIRE which attempts to mesh Rothermel - ! and P&R, and while solving potential inconsistencies, actually results in BIG values for - ! fire residence time, thus lots of vegetation death! - ! taul is the duration of the lethal heating. - ! The /10 is to convert from kgC/m2 into gC/cm2, as in the Peterson and Ryan paper #Rosie,Jun 2013 - - do c = 1,ncwd+2 - tau_b(c) = 39.4_r8 *(currentPatch%fuel_frac(c)*currentPatch%sum_fuel/0.45_r8/10._r8)* & - (1.0_r8-((1.0_r8-currentPatch%burnt_frac_litter(c))**0.5_r8)) - enddo - tau_b(tr_sf) = 0.0_r8 - ! Cap the residence time to 8mins, as suggested by literature survey by P&R (1986). - currentPatch%tau_l = min(8.0_r8,sum(tau_b)) - - !---calculate overall fuel consumed by spreading fire --- - ! ignore 1000hr fuels. Just interested in fuels affecting ROS - currentPatch%TFC_ROS = sum(FC_ground)-FC_ground(tr_sf) - - currentPatch=>currentPatch%younger; - enddo !end patch loop - - end subroutine ground_fuel_consumption - - !***************************************************************** - subroutine fire_intensity ( currentSite ) - !***************************************************************** - !returns the updated currentPatch%FI value for each patch. - - !currentPatch%FI average fire intensity of flaming front during day. Backward ROS plays no role here. kJ/m/s or kW/m. - !currentPatch%ROS_front forward ROS (m/min) - !currentPatch%TFC_ROS total fuel consumed by flaming front (kgC/m2) - - use clm_varctl, only : use_ed_spit_fire - use SFParamsMod, only : SF_val_fdi_alpha,SF_val_fuel_energy, & - SF_val_max_durat, SF_val_durat_slope - - type(ed_site_type), intent(in), target :: currentSite - - type(ed_patch_type), pointer :: currentPatch - - real(r8) ROS !m/s - real(r8) W ! kgBiomass/m2 - real(r8) :: d_fdi !change in the NI on this day to give fire duration. - - currentPatch => currentSite%oldest_patch; - - do while(associated(currentPatch)) - ROS = currentPatch%ROS_front / 60.0_r8 !m/min to m/sec - W = currentPatch%TFC_ROS / 0.45_r8 !kgC/m2 to kgbiomass/m2 - currentPatch%FI = SF_val_fuel_energy * W * ROS !kj/m/s, or kW/m - if(write_sf == 1)then - if(masterproc) write(iulog,*) 'fire_intensity',currentPatch%fi,W,currentPatch%ROS_front - endif - !'decide_fire' subroutine shortened and put in here... - if (currentPatch%FI >= fire_threshold) then ! 50kW/m is the threshold for a self-sustaining fire - currentPatch%fire = 1 ! Fire... :D - - ! This is like but not identical to equation 7 in Thonicke et al. 2010. WHY? - d_FDI = 1.0_r8 - exp(-SF_val_fdi_alpha*currentSite%acc_NI) !follows Venevsky et al GCB 2002 - ! Equation 14 in Thonicke et al. 2010 - currentPatch%FD = SF_val_max_durat / (1.0_r8 + SF_val_max_durat * exp(SF_val_durat_slope*d_FDI)) - if(write_SF == 1)then - if (masterproc) write(iulog,*) 'fire duration minutes',currentPatch%fd - endif - !equation 15 in Arora and Boer CTEM model.Average fire is 1 day long. - !currentPatch%FD = 60.0_r8 * 24.0_r8 !no minutes in a day - else - currentPatch%fire = 0 ! No fire... :-/ - currentPatch%FD = 0.0_r8 - endif - ! FIX(SPM,032414) needs a refactor - ! FIX(RF,032414) : should happen outside of SF loop - doing all spitfire code is inefficient otherwise. - if(.not. use_ed_spit_fire)then - currentPatch%fire = 0 !fudge to turn fire off - endif - - currentPatch => currentPatch%younger; - enddo !end patch loop - - end subroutine fire_intensity - - - !***************************************************************** - subroutine area_burnt ( currentSite ) - !***************************************************************** - !currentPatch%AB daily area burnt (m2) - !currentPatch%NF !Daily number of ignitions (lightning and human-caused), adjusted for size of patch. - - use domainMod, only : ldomain - use EDParamsMod, only : ED_val_nfires - use PatchType, only : patch - - type(ed_site_type), intent(inout), target :: currentSite - - type(ed_patch_type), pointer :: currentPatch - - real lb !length to breadth ratio of fire ellipse - real df !distance fire has travelled forward - real db !distance fire has travelled backward - real(r8) gridarea - real(r8) size_of_fire - integer g, p - - currentSite%frac_burnt = 0.0_r8 - - currentPatch => currentSite%oldest_patch; - do while(associated(currentPatch)) - currentPatch%AB = 0.0_r8 - currentPatch%frac_burnt = 0.0_r8 - lb = 0.0_r8; db = 0.0_r8; df = 0.0_r8 - - if (currentPatch%fire == 1) then - ! The feedback between vegetation structure and ellipse size if turned off for now, - ! to reduce the positive feedback in the syste, - ! This will also be investigated by William Hoffmans proposal. - ! if (currentPatch%effect_wspeed < 16.67_r8) then !16.67m/min = 1km/hr - lb = 1.0_r8 - ! else - !FIX(RF,032414) FOR NO GRASS - ! lb = currentPatch%total_canopy_area/currentPatch%area*(1.0_r8)+(8.729_r8 * & - ! ((1.0_r8 -(exp(-0.03_r8 * 0.06_r8 * currentPatch%effect_wspeed)))**2.155_r8)) !& - !& +currentPatch%fpc_grass*(1.1_r8+((0.06_r8*currentPatch%effect_wspeed)**0.0464)) - - ! endif - - ! if (lb > 8.0_r8)then - ! lb = 8.0_r8 !Constraint Canadian Fire Behaviour System - ! endif - ! ---- calculate length of major axis--- - db = currentPatch%ROS_back * currentPatch%FD !m - df = currentPatch%ROS_front * currentPatch%FD !m - - ! --- calculate area burnt--- - if(lb > 0.0_r8) then - - p = currentPatch%clm_pno - g = patch%gridcell(p) - ! g = currentSite%clmgcell (DEPRECATED VARIABLE) - - ! INTERF-TODO: - ! THIS SHOULD HAVE THE COLUMN AND LU AREA WEIGHT ALSO, NO? - - gridarea = ldomain%area(g) *1000000.0_r8 !convert from km2 into m2 - currentPatch%NF = ldomain%area(g) * ED_val_nfires * currentPatch%area/area /365 - - ! If there are 15 lightening strickes per year, per km2. (approx from NASA product) - ! then there are 15/365 s/km2 each day. - - ! Equation 1 in Thonicke et al. 2010 - ! To Do: Connect here with the Li & Levis GDP fire suppression algorithm. - ! Equation 16 in arora and boer model. - !currentPatch%ab = currentPatch%ab *3.0_r8 - size_of_fire = ((3.1416_r8/(4.0_r8*lb))*((df+db)**2.0_r8)) - currentPatch%AB = size_of_fire * currentPatch%nf - if (currentPatch%AB > gridarea*currentPatch%area/area) then !all of patch burnt. - - if (masterproc) write(iulog,*) 'burnt all of patch',currentPatch%patchno, & - currentPatch%area/area,currentPatch%ab,currentPatch%area/area*gridarea - if (masterproc) write(iulog,*) 'ros',currentPatch%ROS_front,currentPatch%FD, & - currentPatch%NF,currentPatch%FI,size_of_fire - - if (masterproc) write(iulog,*) 'litter',currentPatch%sum_fuel,currentPatch%CWD_AG,currentPatch%leaf_litter - ! turn km2 into m2. work out total area burnt. - currentPatch%AB = currentPatch%area * gridarea/AREA - endif - currentPatch%frac_burnt = currentPatch%AB / (gridarea*currentPatch%area/area) - if(write_SF == 1)then - if (masterproc) write(iulog,*) 'frac_burnt',currentPatch%frac_burnt - endif - endif - endif! fire - currentSite%frac_burnt = currentSite%frac_burnt + currentPatch%frac_burnt - - currentPatch => currentPatch%younger; - - enddo !end patch loop - - end subroutine area_burnt - - !***************************************************************** - subroutine crown_scorching ( currentSite ) - !***************************************************************** - !currentPatch%SH !average scorch height for the patch(m) - !currentPatch%FI average fire intensity of flaming front during day. kW/m. - - use SFParamsMod, only : SF_val_alpha_SH - use EDParamsMod, only : ED_val_ag_biomass - - type(ed_site_type), intent(in), target :: currentSite - - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - real f_ag_bmass !fraction of a tree cohort's above-ground biomass as a proportion of total patch ag tree biomass. - real tree_ag_biomass !total amount of above-ground tree biomass in patch. kgC/m2 - - currentPatch => currentSite%oldest_patch; - do while(associated(currentPatch)) - - tree_ag_biomass = 0.0_r8 - f_ag_bmass = 0.0_r8 - if (currentPatch%fire == 1) then - currentCohort => currentPatch%tallest; - do while(associated(currentCohort)) - if (pftcon%woody(currentCohort%pft) == 1) then !trees only - tree_ag_biomass = tree_ag_biomass+(currentCohort%bl+ED_val_ag_biomass* & - (currentCohort%bsw + currentCohort%bdead))*currentCohort%n - endif !trees only - - currentCohort=>currentCohort%shorter; - - enddo !end cohort loop - - !This loop weights the scorch height for the contribution of each cohort to the overall biomass. - - ! does this do anything? I think it might be redundant? RF. - currentPatch%SH = 0.0_r8 - currentCohort => currentPatch%tallest; - do while(associated(currentCohort)) - if (pftcon%woody(currentCohort%pft) == 1.and.(tree_ag_biomass > 0.0_r8)) then !trees only - f_ag_bmass = ((currentCohort%bl+ED_val_ag_biomass*(currentCohort%bsw + & - currentCohort%bdead))*currentCohort%n)/tree_ag_biomass - !equation 16 in Thonicke et al. 2010 - if(write_SF == 1)then - if (masterproc) write(iulog,*) 'currentPatch%SH',currentPatch%SH,f_ag_bmass - endif - !2/3 Byram (1959) - currentPatch%SH = currentPatch%SH + f_ag_bmass * SF_val_alpha_SH * (currentPatch%FI**0.667_r8) - endif !trees only - currentCohort=>currentCohort%shorter; - enddo !end cohort loop - endif !fire - - currentPatch => currentPatch%younger; - enddo !end patch loop - - end subroutine crown_scorching - - !***************************************************************** - subroutine crown_damage ( currentSite ) - !***************************************************************** - - !returns the updated currentCohort%cfa value for each tree cohort within each patch. - !currentCohort%cfa proportion of crown affected by fire - - type(ed_site_type), intent(in), target :: currentSite - - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - currentPatch => currentSite%oldest_patch - - do while(associated(currentPatch)) - if (currentPatch%fire == 1) then - - currentCohort=>currentPatch%tallest - - do while(associated(currentCohort)) - currentCohort%cfa = 0.0_r8 - if (pftcon%woody(currentCohort%pft) == 1) then !trees only - ! Flames lower than bottom of canopy. - ! c%hite is height of cohort - if (currentPatch%SH < (currentCohort%hite-currentCohort%hite*EDecophyscon%crown(currentCohort%pft))) then - currentCohort%cfa = 0.0_r8 - else - ! Flames part of way up canopy. - ! Equation 17 in Thonicke et al. 2010. - ! flames over bottom of canopy but not over top. - if ((currentCohort%hite > 0.0_r8).and.(currentPatch%SH >= & - (currentCohort%hite-currentCohort%hite*EDecophyscon%crown(currentCohort%pft)))) then - - currentCohort%cfa = (currentPatch%SH-currentCohort%hite* & - EDecophyscon%crown(currentCohort%pft))/(currentCohort%hite-currentCohort%hite* & - EDecophyscon%crown(currentCohort%pft)) - - else - ! Flames over top of canopy. - currentCohort%cfa = 1.0_r8 - endif - - endif - ! Check for strange values. - currentCohort%cfa = min(1.0_r8, max(0.0_r8,currentCohort%cfa)) - endif !trees only - !shrink canopy to account for burnt section. - !currentCohort%canopy_trim = min(currentCohort%canopy_trim,(1.0_r8-currentCohort%cfa)) - - currentCohort => currentCohort%shorter; - - enddo !end cohort loop - endif !fire? - - currentPatch => currentPatch%younger; - - enddo !end patch loop - - end subroutine crown_damage - - !***************************************************************** - subroutine cambial_damage_kill ( currentSite ) - !***************************************************************** - ! routine description. - ! returns the probability that trees dies due to cambial char - ! currentPatch%tau_l = duration of lethal stem heating (min). Calculated at patch level. - - type(ed_site_type), intent(in), target :: currentSite - - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - real(r8) :: tau_c !critical time taken to kill cambium (minutes) - real(r8) :: bt !bark thickness in cm. - - currentPatch => currentSite%oldest_patch; - - do while(associated(currentPatch)) - - if (currentPatch%fire == 1) then - currentCohort => currentPatch%tallest; - do while(associated(currentCohort)) - if (pftcon%woody(currentCohort%pft) == 1) then !trees only - ! Equation 21 in Thonicke et al 2010 - bt = EDecophyscon%bark_scaler(currentCohort%pft)*currentCohort%dbh ! bark thickness. - ! Equation 20 in Thonicke et al. 2010. - tau_c = 2.9_r8*bt**2.0_r8 !calculate time it takes to kill cambium (min) - ! Equation 19 in Thonicke et al. 2010 - if ((currentPatch%tau_l/tau_c) >= 2.0_r8) then - currentCohort%cambial_mort = 1.0_r8 - else - if ((currentPatch%tau_l/tau_c) > 0.22_r8) then - currentCohort%cambial_mort = (0.563_r8*(currentPatch%tau_l/tau_c)) - 0.125_r8 - else - currentCohort%cambial_mort = 0.0_r8 - endif - endif - endif !trees - - currentCohort => currentCohort%shorter; - - enddo !end cohort loop - endif !fire? - - currentPatch=>currentPatch%younger; - - enddo !end patch loop - - end subroutine cambial_damage_kill - - !***************************************************************** - subroutine post_fire_mortality ( currentSite ) - !***************************************************************** - - ! returns the updated currentCohort%fire_mort value for each tree cohort within each patch. - ! currentCohort%cfa proportion of crown affected by fire - ! currentCohort%crownfire_mort probability of tree post-fire mortality due to crown scorch - ! currentCohort%cambial_mort probability of tree post-fire mortality due to cambial char - ! currentCohort%fire_mort post-fire mortality from cambial and crown damage assuming two are independent. - - type(ed_site_type), intent(in), target :: currentSite - - type(ed_patch_type), pointer :: currentPatch - type(ed_cohort_type), pointer :: currentCohort - - currentPatch => currentSite%oldest_patch - - do while(associated(currentPatch)) - - if (currentPatch%fire == 1) then - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - currentCohort%fire_mort = 0.0_r8 - currentCohort%crownfire_mort = 0.0_r8 - if (pftcon%woody(currentCohort%pft) == 1) then - ! Equation 22 in Thonicke et al. 2010. - currentCohort%crownfire_mort = EDecophyscon%crown_kill(currentCohort%pft)*currentCohort%cfa**3.0_r8 - ! Equation 18 in Thonicke et al. 2010. - currentCohort%fire_mort = currentCohort%crownfire_mort+currentCohort%cambial_mort- & - (currentCohort%crownfire_mort*currentCohort%cambial_mort) !joint prob. - else - currentCohort%fire_mort = 0.0_r8 !I have changed this to zero and made the mode of death removal of leaves... - endif !trees - - currentCohort => currentCohort%shorter - - enddo !end cohort loop - endif !fire? - - currentPatch => currentPatch%younger - - enddo !end patch loop - - end subroutine post_fire_mortality - - ! ============================================================================ -end module SFMainMod diff --git a/src/ED/fire/SFParamsMod.F90 b/src/ED/fire/SFParamsMod.F90 deleted file mode 100644 index 3caa526a01..0000000000 --- a/src/ED/fire/SFParamsMod.F90 +++ /dev/null @@ -1,212 +0,0 @@ -module SFParamsMod - ! - ! module that deals with reading the SF parameter file - ! - use shr_kind_mod , only: r8 => shr_kind_r8 - use EDtypesMod , only: NLSC,NFSC,NCWD - - implicit none - save - ! private - if we allow this module to be private, it does not allow the protected values below to be - ! seen outside of this module. - - ! - ! this is what the user can use for the actual values - ! - real(r8),protected :: SF_val_fdi_a - real(r8),protected :: SF_val_fdi_b - real(r8),protected :: SF_val_fdi_alpha - real(r8),protected :: SF_val_miner_total - real(r8),protected :: SF_val_fuel_energy - real(r8),protected :: SF_val_part_dens - real(r8),protected :: SF_val_miner_damp - real(r8),protected :: SF_val_max_durat - real(r8),protected :: SF_val_durat_slope - real(r8),protected :: SF_val_alpha_SH - real(r8),protected :: SF_val_alpha_FMC(NLSC) - real(r8),protected :: SF_val_CWD_frac(NCWD) - real(r8),protected :: SF_val_max_decomp(NLSC) - real(r8),protected :: SF_val_SAV(NFSC) - real(r8),protected :: SF_val_FBD(NFSC) - real(r8),protected :: SF_val_min_moisture(NFSC) - real(r8),protected :: SF_val_mid_moisture(NFSC) - real(r8),protected :: SF_val_low_moisture_C(NFSC) - real(r8),protected :: SF_val_low_moisture_S(NFSC) - real(r8),protected :: SF_val_mid_moisture_C(NFSC) - real(r8),protected :: SF_val_mid_moisture_S(NFSC) - - character(len=20),parameter :: SF_name_fdi_a = "fdi_a" - character(len=20),parameter :: SF_name_fdi_b = "fdi_b" - character(len=20),parameter :: SF_name_fdi_alpha = "fdi_alpha" - character(len=20),parameter :: SF_name_miner_total = "miner_total" - character(len=20),parameter :: SF_name_fuel_energy = "fuel_energy" - character(len=20),parameter :: SF_name_part_dens = "part_dens" - character(len=20),parameter :: SF_name_miner_damp = "miner_damp" - character(len=20),parameter :: SF_name_max_durat = "max_durat" - character(len=20),parameter :: SF_name_durat_slope = "durat_slope" - character(len=20),parameter :: SF_name_alpha_SH = "alpha_SH" - character(len=20),parameter :: SF_name_alpha_FMC = "alpha_FMC" - character(len=20),parameter :: SF_name_CWD_frac = "CWD_frac" - character(len=20),parameter :: SF_name_max_decomp = "max_decomp" - character(len=20),parameter :: SF_name_SAV = "SAV" - character(len=20),parameter :: SF_name_FBD = "FBD" - character(len=20),parameter :: SF_name_min_moisture = "min_moisture" - character(len=20),parameter :: SF_name_mid_moisture = "mid_moisture" - character(len=20),parameter :: SF_name_low_moisture_C = "low_moisture_C" - character(len=20),parameter :: SF_name_low_moisture_S = "low_moisture_S" - character(len=20),parameter :: SF_name_mid_moisture_C = "mid_moisture_C" - character(len=20),parameter :: SF_name_mid_moisture_S = "mid_moisture_S" - - public :: SFParamsRead - -contains - !----------------------------------------------------------------------- - ! - !----------------------------------------------------------------------- - subroutine SFParamsRead(ncid) - ! - ! calls to initialize parameter instance and do ncdio read - ! - use ncdio_pio , only : file_desc_t - - implicit none - - ! arguments - type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id - - call SFParamsReadLocal(ncid) - - end subroutine SFParamsRead - !----------------------------------------------------------------------- - - !----------------------------------------------------------------------- - ! - !----------------------------------------------------------------------- - subroutine SFParamsReadLocal(ncid) - ! - ! read the netcdf file and populate internalInstScalar - ! - use ncdio_pio , only : file_desc_t - use paramUtilMod , only : readNcdio - - implicit none - - ! arguments - type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id - - ! local vars - character(len=32) :: subname = 'SFParamsReadLocal::' - - ! - ! call read function - ! - - call readNcdio(ncid = ncid, & - varName=SF_name_fdi_a, & - callingName=subname, & - retVal=SF_val_fdi_a) - - call readNcdio(ncid = ncid, & - varName=SF_name_fdi_b, & - callingName=subname, & - retVal=SF_val_fdi_b) - - call readNcdio(ncid = ncid, & - varName=SF_name_fdi_alpha, & - callingName=subname, & - retVal=SF_val_fdi_alpha) - - call readNcdio(ncid = ncid, & - varName=SF_name_miner_total, & - callingName=subname, & - retVal=SF_val_miner_total) - - call readNcdio(ncid = ncid, & - varName=SF_name_fuel_energy, & - callingName=subname, & - retVal=SF_val_fuel_energy) - - call readNcdio(ncid = ncid, & - varName=SF_name_part_dens, & - callingName=subname, & - retVal=SF_val_part_dens) - - call readNcdio(ncid = ncid, & - varName=SF_name_miner_damp, & - callingName=subname, & - retVal=SF_val_miner_damp) - - call readNcdio(ncid = ncid, & - varName=SF_name_max_durat, & - callingName=subname, & - retVal=SF_val_max_durat) - - call readNcdio(ncid = ncid, & - varName=SF_name_durat_slope, & - callingName=subname, & - retVal=SF_val_durat_slope) - - call readNcdio(ncid = ncid, & - varName=SF_name_alpha_SH, & - callingName=subname, & - retVal=SF_val_alpha_SH) - - call readNcdio(ncid = ncid, & - varName=SF_name_alpha_FMC, & - callingName=subname, & - retVal=SF_val_alpha_FMC) - - call readNcdio(ncid = ncid, & - varName=SF_name_CWD_frac, & - callingName=subname, & - retVal=SF_val_CWD_frac) - - call readNcdio(ncid = ncid, & - varName=SF_name_max_decomp, & - callingName=subname, & - retVal=SF_val_max_decomp) - - call readNcdio(ncid = ncid, & - varName=SF_name_SAV, & - callingName=subname, & - retVal=SF_val_SAV) - - call readNcdio(ncid = ncid, & - varName=SF_name_FBD, & - callingName=subname, & - retVal=SF_val_FBD) - - call readNcdio(ncid = ncid, & - varName=SF_name_min_moisture, & - callingName=subname, & - retVal=SF_val_min_moisture) - - call readNcdio(ncid = ncid, & - varName=SF_name_mid_moisture, & - callingName=subname, & - retVal=SF_val_mid_moisture) - - call readNcdio(ncid = ncid, & - varName=SF_name_low_moisture_C, & - callingName=subname, & - retVal=SF_val_low_moisture_C) - - call readNcdio(ncid = ncid, & - varName=SF_name_low_moisture_S, & - callingName=subname, & - retVal=SF_val_low_moisture_S) - - call readNcdio(ncid = ncid, & - varName=SF_name_mid_moisture_C, & - callingName=subname, & - retVal=SF_val_mid_moisture_C) - - call readNcdio(ncid = ncid, & - varName=SF_name_mid_moisture_S, & - callingName=subname, & - retVal=SF_val_mid_moisture_S) - - end subroutine SFParamsReadLocal - !----------------------------------------------------------------------- - -end module SFParamsMod diff --git a/src/ED/main/CMakeLists.txt b/src/ED/main/CMakeLists.txt deleted file mode 100644 index 5f8dbdcfb9..0000000000 --- a/src/ED/main/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Note that this is just used for unit testing; hence, we only need to add -# source files that are currently used in unit tests - -list(APPEND clm_sources - EDPftvarcon.F90 - ) - -sourcelist_to_parent(clm_sources) - diff --git a/src/ED/main/EDCLMLinkMod.F90 b/src/ED/main/EDCLMLinkMod.F90 deleted file mode 100755 index 340b19c4e3..0000000000 --- a/src/ED/main/EDCLMLinkMod.F90 +++ /dev/null @@ -1,2371 +0,0 @@ -module EDCLMLinkMod - - ! ============================================================================ - ! Modules to control the passing of infomation generated by ED into CLM to be used for either - ! diagnostics, or as input to the land surface components. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_infnan_mod, only : isnan => shr_infnan_isnan - use decompMod , only : bounds_type - use clm_varpar , only : numpft, numcft, mxpft - use clm_varctl , only : iulog - use ColumnType , only : col - use EDtypesMod , only : ed_site_type, ed_cohort_type, ed_patch_type, ncwd - use EDtypesMod , only : sclass_ed, nlevsclass_ed, AREA, cp_nclmax, cp_nlevcan - use CanopyStateType , only : canopystate_type - use clm_varctl , only : use_vertsoilc - use EDParamsMod , only : ED_val_ag_biomass - use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type - use SoilBiogeochemCarbonStatetype , only : soilbiogeochem_carbonstate_type - use clm_time_manager , only : is_beg_curr_day, get_step_size, get_nstep - use shr_const_mod, only: SHR_CONST_CDAY - use abortutils , only : endrun - use shr_log_mod , only : errMsg => shr_log_errMsg - use EDCanopyStructureMod, only : calc_areaindex - - ! - implicit none - private - ! - logical :: DEBUG = .false. ! for debugging this module (EDCLMLinkMod.F90) - - ! !PUBLIC DATA MEMBERS - real(r8), public :: cwd_fcel_ed - real(r8), public :: cwd_flig_ed - - type, public :: ed_clm_type - - real(r8), pointer, private :: trimming_patch (:) - real(r8), pointer, private :: area_plant_patch (:) - real(r8), pointer, private :: area_trees_patch (:) - real(r8), pointer, private :: canopy_spread_patch (:) - real(r8), pointer, private :: PFTbiomass_patch (:,:) ! total biomass of each patch - real(r8), pointer, private :: PFTleafbiomass_patch (:,:) ! total biomass of each patch - real(r8), pointer, private :: PFTstorebiomass_patch (:,:) ! total biomass of each patch - real(r8), pointer, private :: PFTnindivs_patch (:,:) ! total biomass of each patch - - real(r8), pointer, private :: nesterov_fire_danger_patch (:) ! total biomass of each patch - real(r8), pointer, private :: spitfire_ROS_patch (:) ! total biomass of each patch - real(r8), pointer, private :: effect_wspeed_patch (:) ! total biomass of each patch - real(r8), pointer, private :: TFC_ROS_patch (:) ! total biomass of each patch - real(r8), pointer, private :: fire_intensity_patch (:) ! total biomass of each patch - real(r8), pointer, private :: fire_area_patch (:) ! total biomass of each patch - real(r8), pointer, private :: scorch_height_patch (:) ! total biomass of each patch - real(r8), pointer, private :: fire_fuel_bulkd_patch (:) ! total biomass of each patch - real(r8), pointer, private :: fire_fuel_eff_moist_patch (:) ! total biomass of each patch - real(r8), pointer, private :: fire_fuel_sav_patch (:) ! total biomass of each patch - real(r8), pointer, private :: fire_fuel_mef_patch (:) ! total biomass of each patch - real(r8), pointer, private :: sum_fuel_patch (:) ! total biomass of each patch - - real(r8), pointer, private :: litter_in_patch (:) ! total biomass of each patch - real(r8), pointer, private :: litter_out_patch (:) ! total biomass of each patch - real(r8), pointer, private :: efpot_patch (:) ! potential transpiration - real(r8), pointer, private :: rb_patch (:) ! boundary layer conductance - - real(r8), pointer, private :: daily_temp_patch (:) ! daily temperature for fire and phenology models - real(r8), pointer, private :: daily_rh_patch (:) ! daily RH for fire model - real(r8), pointer, private :: daily_prec_patch (:) ! daily rain for fire and phenology models. - - !seed model. Aggregated to gridcell for now. - - real(r8), pointer, private :: seed_bank_patch (:) ! kGC/m2 Mass of seeds. - real(r8), pointer, private :: seeds_in_patch (:) ! kGC/m2/year Production of seed mass. - real(r8), pointer, private :: seed_decay_patch (:) ! kGC/m2/year Decay of seed mass. - real(r8), pointer, private :: seed_germination_patch (:) ! kGC/m2/year Germiantion rate of seed mass. - - real(r8), pointer, private :: ED_bstore_patch (:) ! kGC/m2 Total stored biomass. - real(r8), pointer, private :: ED_bdead_patch (:) ! kGC/m2 Total dead biomass. - real(r8), pointer, private :: ED_balive_patch (:) ! kGC/m2 Total alive biomass. - real(r8), pointer, private :: ED_bleaf_patch (:) ! kGC/m2 Total leaf biomass. - real(r8), pointer, private :: ED_biomass_patch (:) ! kGC/m2 Total biomass. - - ! vegetation carbon fluxes at the patch scale - real(r8), pointer, private :: npp_patch (:) ! (gC/m2/s) patch net primary production - real(r8), pointer, private :: gpp_patch (:) ! (gC/m2/s) patch gross primary production - real(r8), pointer, private :: ar_patch (:) ! (gC/m2/s) patch autotrophic respiration - real(r8), pointer, private :: maint_resp_patch (:) ! (gC/m2/s) patch maintenance respiration - real(r8), pointer, private :: growth_resp_patch (:) ! (gC/m2/s) patch growth respiration - - real(r8), pointer :: ed_gpp_col_scpf (:,:) ! [kg/m2/yr] gross primary production - real(r8), pointer :: ed_npp_totl_col_scpf (:,:) ! [kg/m2/yr] net primary production (npp) - real(r8), pointer :: ed_npp_leaf_col_scpf (:,:) ! [kg/m2/yr] npp flux into leaf pool - real(r8), pointer :: ed_npp_seed_col_scpf (:,:) ! [kg/m2/yr] npp flux into flower,fruit,nut,seed - real(r8), pointer :: ed_npp_fnrt_col_scpf (:,:) ! [kg/m2/yr] npp flux into fine roots - real(r8), pointer :: ed_npp_bgsw_col_scpf (:,:) ! [kg/m2/yr] npp flux into below ground sapwood - real(r8), pointer :: ed_npp_bgdw_col_scpf (:,:) ! [kg/m2/yr] npp flux into below ground structural (dead) wood - real(r8), pointer :: ed_npp_agsw_col_scpf (:,:) ! [kg/m2/yr] npp flux into above ground sapwood - real(r8), pointer :: ed_npp_agdw_col_scpf (:,:) ! [kg/m2/yr] npp flux into below ground structural (dead) wood - real(r8), pointer :: ed_npp_stor_col_scpf (:,:) ! [kg/m2/yr] npp flux through the storage pool - real(r8), pointer :: ed_litt_leaf_col_scpf (:,:) ! [kg/m2/yr] carbon flux of live leaves to litter - real(r8), pointer :: ed_litt_fnrt_col_scpf (:,:) ! [kg/m2/yr] carbon flux of fine roots to litter - real(r8), pointer :: ed_litt_sawd_col_scpf (:,:) ! [kg/m2/yr] carbon flux of sapwood to litter (above+below) - real(r8), pointer :: ed_litt_ddwd_col_scpf (:,:) ! [kg/m2/yr] carbon flux of dead wood (above+below) to litter - real(r8), pointer :: ed_r_leaf_col_scpf (:,:) ! [kg/m2/yr] total leaf respiration - real(r8), pointer :: ed_r_stem_col_scpf (:,:) ! [kg/m2/yr] total above ground live wood (stem) respiration - real(r8), pointer :: ed_r_root_col_scpf (:,:) ! [kg/m2/yr] total below ground live wood (root) respiration - real(r8), pointer :: ed_r_stor_col_scpf (:,:) ! [kg/m2/yr] total storage respiration - - ! Carbon State Variables for direct comparison to inventory - dimensions: (disturbance patch, pft x size) - - real(r8), pointer :: ed_ddbh_col_scpf (:,:) ! [cm/yr] diameter increment - real(r8), pointer :: ed_ba_col_scpf (:,:) ! [m2/ha] basal area - real(r8), pointer :: ed_np_col_scpf (:,:) ! [/m2] number of plants - real(r8), pointer :: ed_m1_col_scpf (:,:) ! [Stems/ha/yr] Mean Background Mortality - real(r8), pointer :: ed_m2_col_scpf (:,:) ! [Stems/ha/yr] Mean Hydraulic Mortaliry - real(r8), pointer :: ed_m3_col_scpf (:,:) ! [Stems/ha/yr] Mean Carbon Starvation Mortality - real(r8), pointer :: ed_m4_col_scpf (:,:) ! [Stems/ha/yr] Mean Impact Mortality - real(r8), pointer :: ed_m5_col_scpf (:,:) ! [Stems/ha/yr] Mean Fire Mortality - - ! summary carbon fluxes at the column level - real(r8), pointer, private :: nep_col(:) ! [gC/m2/s] Net ecosystem production, i.e. fast-timescale carbon balance that does not include disturbance - real(r8), pointer, private :: nep_timeintegrated_col(:) ! [gC/m2/s] Net ecosystem production, i.e. fast-timescale carbon balance that does not include disturbance - real(r8), pointer, private :: npp_timeintegrated_col(:) ! [gC/m2/s] Net primary production, time integrated at column level for carbon balance checking - real(r8), pointer, private :: hr_timeintegrated_col(:) ! [gC/m2/s] heterotrophic respiration, time integrated for carbon balance checking - real(r8), pointer, private :: nbp_col(:) ! [gC/m2/s] Net biosphere production, i.e. slow-timescale carbon balance that integrates to total carbon change - real(r8), pointer, private :: npp_col(:) ! [gC/m2/s] Net primary production at the fast timescale, aggregated to the column level - real(r8), pointer, private :: fire_c_to_atm_col(:) ! [gC/m2/s] total fire carbon loss to atmosphere - real(r8), pointer, private :: ed_to_bgc_this_edts_col(:) ! [gC/m2/s] total flux of carbon from ED to BGC models on current ED timestep - real(r8), pointer, private :: ed_to_bgc_last_edts_col(:) ! [gC/m2/s] total flux of carbon from ED to BGC models on prior ED timestep - real(r8), pointer, private :: seed_rain_flux_col(:) ! [gC/m2/s] total flux of carbon from seed rain - - ! summary carbon states at the column level - real(r8), pointer, private :: totecosysc_col(:) ! [gC/m2] Total ecosystem carbon at the column level, including vegetation, CWD, litter, and soil pools - real(r8), pointer, private :: totecosysc_old_col(:) ! [gC/m2] Total ecosystem C at the column level from last call to balance check - real(r8), pointer, private :: totedc_col(:) ! [gC/m2] Total ED carbon at the column level, including vegetation, CWD, seeds, and ED litter - real(r8), pointer, private :: totedc_old_col(:) ! [gC/m2] Total ED C at the column level from last call to balance check - real(r8), pointer, private :: totbgcc_col(:) ! [gC/m2] Total BGC carbon at the column level, including litter, and soil pools - real(r8), pointer, private :: totbgcc_old_col(:) ! [gC/m2] Total BGC C at the column level from last call to balance check - real(r8), pointer, private :: biomass_stock_col(:) ! [gC/m2] total biomass at the column level in gC / m2 - real(r8), pointer, private :: ed_litter_stock_col(:) ! [gC/m2] ED litter at the column level in gC / m2 - real(r8), pointer, private :: cwd_stock_col(:) ! [gC/m2] ED CWD at the column level in gC / m2 - real(r8), pointer, private :: seed_stock_col(:) ! [gC/m2] ED seed mass carbon at the column level in gC / m2 - - ! carbon balance errors. at some point we'll reduce these to close to zero and delete, but for now we'll just keep[ track of them - real(r8), pointer, private :: cbalance_error_ed_col(:) ! [gC/m2/s] total carbon balance error for the ED side - real(r8), pointer, private :: cbalance_error_bgc_col(:) ! [gC/m2/s] total carbon balance error for the BGC side - real(r8), pointer, private :: cbalance_error_total_col(:) ! [gC/m2/s] total carbon balance error for the whole thing - - ! ED patch/cohort data - real(r8), pointer, private :: ed_npatches_col(:) ! [#] the number of patches per ED site - real(r8), pointer, private :: ed_ncohorts_col(:) ! [#] the number of cohorts per ED site - - contains - - ! Public routines - procedure , public :: Init - procedure , public :: Restart - procedure , public :: SetValues - procedure , public :: ed_clm_link - procedure , public :: SummarizeNetFluxes - procedure , public :: SummarizeProductivityFluxes - procedure , public :: ED_BGC_Carbon_Balancecheck - - ! Private routines - procedure , private :: ed_clm_leaf_area_profile - procedure , private :: ed_update_history_variables - procedure , private :: InitAllocate - procedure , private :: InitHistory -! procedure , private :: InitCold - - end type ed_clm_type - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - - ! 10/30/09: Created by Rosie Fisher - !----------------------------------------------------------------------- - -contains - - !------------------------------------------------------------------------ - subroutine Init(this, bounds) - ! - ! !DESCRIPTION: - ! Initialize module data structure instance - ! - ! !ARGUMENTS: - class(ed_clm_type) :: this - type(bounds_type), intent(in) :: bounds - !----------------------------------------------------------------------- - - call this%InitAllocate(bounds) - call this%InitHistory(bounds) - !call this%InitCold(bounds) - - end subroutine Init - - !------------------------------------------------------------------------ - subroutine InitAllocate(this, bounds) - ! - ! !USES: - use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) - use clm_varpar , only : nlevgrnd, nlevdecomp_full - use EDtypesMod , only : numpft_ed - ! - ! !ARGUMENTS: - class (ed_clm_type) :: this - type(bounds_type), intent(in) :: bounds - ! - ! !LOCAL VARIABLES: - integer :: begp,endp - integer :: begc,endc !bounds - integer :: begg,endg - !------------------------------------------------------------------------ - - begp = bounds%begp; endp = bounds%endp - begc = bounds%begc; endc = bounds%endc - - - allocate(this%trimming_patch (begp:endp)) ; this%trimming_patch (:) = 0.0_r8 - allocate(this%canopy_spread_patch (begp:endp)) ; this%canopy_spread_patch (:) = 0.0_r8 - allocate(this%area_plant_patch (begp:endp)) ; this%area_plant_patch (:) = 0.0_r8 - allocate(this%area_trees_patch (begp:endp)) ; this%area_trees_patch (:) = 0.0_r8 - allocate(this%PFTbiomass_patch (begp:endp,1:nlevgrnd)) ; this%PFTbiomass_patch (:,:) = 0.0_r8 - allocate(this%PFTleafbiomass_patch (begp:endp,1:nlevgrnd)) ; this%PFTleafbiomass_patch (:,:) = 0.0_r8 - allocate(this%PFTstorebiomass_patch (begp:endp,1:nlevgrnd)) ; this%PFTstorebiomass_patch (:,:) = 0.0_r8 - allocate(this%PFTnindivs_patch (begp:endp,1:nlevgrnd)) ; this%PFTnindivs_patch (:,:) = 0.0_r8 - allocate(this%nesterov_fire_danger_patch (begp:endp)) ; this%nesterov_fire_danger_patch (:) = 0.0_r8 - allocate(this%spitfire_ROS_patch (begp:endp)) ; this%spitfire_ROS_patch (:) = 0.0_r8 - allocate(this%effect_wspeed_patch (begp:endp)) ; this%effect_wspeed_patch (:) = 0.0_r8 - allocate(this%TFC_ROS_patch (begp:endp)) ; this%TFC_ROS_patch (:) = 0.0_r8 - allocate(this%fire_intensity_patch (begp:endp)) ; this%fire_intensity_patch (:) = 0.0_r8 - allocate(this%fire_area_patch (begp:endp)) ; this%fire_area_patch (:) = 0.0_r8 - allocate(this%scorch_height_patch (begp:endp)) ; this%scorch_height_patch (:) = 0.0_r8 - allocate(this%fire_fuel_bulkd_patch (begp:endp)) ; this%fire_fuel_bulkd_patch (:) = 0.0_r8 - allocate(this%fire_fuel_eff_moist_patch (begp:endp)) ; this%fire_fuel_eff_moist_patch (:) = 0.0_r8 - allocate(this%fire_fuel_sav_patch (begp:endp)) ; this%fire_fuel_sav_patch (:) = 0.0_r8 - allocate(this%fire_fuel_mef_patch (begp:endp)) ; this%fire_fuel_mef_patch (:) = 0.0_r8 - allocate(this%sum_fuel_patch (begp:endp)) ; this%sum_fuel_patch (:) = 0.0_r8 - allocate(this%litter_in_patch (begp:endp)) ; this%litter_in_patch (:) = 0.0_r8 - allocate(this%litter_out_patch (begp:endp)) ; this%litter_out_patch (:) = 0.0_r8 - allocate(this%efpot_patch (begp:endp)) ; this%efpot_patch (:) = 0.0_r8 - allocate(this%rb_patch (begp:endp)) ; this%rb_patch (:) = 0.0_r8 - allocate(this%seed_bank_patch (begp:endp)) ; this%seed_bank_patch (:) = 0.0_r8 - allocate(this%seed_decay_patch (begp:endp)) ; this%seed_decay_patch (:) = 0.0_r8 - allocate(this%seeds_in_patch (begp:endp)) ; this%seeds_in_patch (:) = 0.0_r8 - allocate(this%seed_germination_patch (begp:endp)) ; this%seed_germination_patch (:) = 0.0_r8 - allocate(this%ED_bstore_patch (begp:endp)) ; this%ED_bstore_patch (:) = 0.0_r8 - allocate(this%ED_bdead_patch (begp:endp)) ; this%ED_bdead_patch (:) = 0.0_r8 - allocate(this%ED_balive_patch (begp:endp)) ; this%ED_balive_patch (:) = 0.0_r8 - allocate(this%ED_bleaf_patch (begp:endp)) ; this%ED_bleaf_patch (:) = 0.0_r8 - allocate(this%ED_biomass_patch (begp:endp)) ; this%ED_biomass_patch (:) = 0.0_r8 - - allocate(this%gpp_patch (begp:endp)) ; this%gpp_patch (:) = nan - allocate(this%npp_patch (begp:endp)) ; this%npp_patch (:) = nan - allocate(this%ar_patch (begp:endp)) ; this%ar_patch (:) = nan - allocate(this%maint_resp_patch (begp:endp)) ; this%maint_resp_patch (:) = nan - allocate(this%growth_resp_patch (begp:endp)) ; this%growth_resp_patch (:) = nan - - allocate(this%ed_to_bgc_this_edts_col (begc:endc)) ; this%ed_to_bgc_this_edts_col (:) = nan - allocate(this%ed_to_bgc_last_edts_col (begc:endc)) ; this%ed_to_bgc_last_edts_col (:) = nan - allocate(this%seed_rain_flux_col (begc:endc)) ; this%seed_rain_flux_col (:) = nan - - allocate(this%nep_col (begc:endc)) ; this%nep_col (:) = nan - allocate(this%nep_timeintegrated_col (begc:endc)) ; this%nep_timeintegrated_col (:) = nan - allocate(this%npp_timeintegrated_col (begc:endc)) ; this%npp_timeintegrated_col (:) = nan - allocate(this%hr_timeintegrated_col (begc:endc)) ; this%hr_timeintegrated_col (:) = nan - - allocate(this%nbp_col (begc:endc)) ; this%nbp_col (:) = nan - allocate(this%npp_col (begc:endc)) ; this%npp_col (:) = nan - allocate(this%fire_c_to_atm_col (begc:endc)) ; this%fire_c_to_atm_col (:) = nan - - allocate(this%totecosysc_col (begc:endc)) ; this%totecosysc_col (:) = nan - allocate(this%totecosysc_old_col (begc:endc)) ; this%totecosysc_old_col (:) = nan - allocate(this%totedc_col (begc:endc)) ; this%totedc_col (:) = nan - allocate(this%totedc_old_col (begc:endc)) ; this%totedc_old_col (:) = nan - allocate(this%totbgcc_col (begc:endc)) ; this%totbgcc_col (:) = nan - allocate(this%totbgcc_old_col (begc:endc)) ; this%totbgcc_old_col (:) = nan - allocate(this%biomass_stock_col (begc:endc)) ; this%biomass_stock_col (:) = nan - allocate(this%ed_litter_stock_col (begc:endc)) ; this%ed_litter_stock_col (:) = nan - allocate(this%cwd_stock_col (begc:endc)) ; this%cwd_stock_col (:) = nan - allocate(this%seed_stock_col (begc:endc)) ; this%seed_stock_col (:) = nan - - allocate(this%cbalance_error_ed_col (begc:endc)) ; this%cbalance_error_ed_col (:) = nan - allocate(this%cbalance_error_bgc_col (begc:endc)) ; this%cbalance_error_bgc_col (:) = nan - allocate(this%cbalance_error_total_col (begc:endc)) ; this%cbalance_error_total_col (:) = nan - - allocate(this%ed_npatches_col (begc:endc)) ; this%ed_npatches_col (:) = nan - allocate(this%ed_ncohorts_col (begc:endc)) ; this%ed_ncohorts_col (:) = nan - - allocate(this%ed_gpp_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_gpp_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_totl_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_totl_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_leaf_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_leaf_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_seed_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_seed_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_fnrt_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_fnrt_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_bgsw_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_bgsw_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_bgdw_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_bgdw_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_agsw_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_agsw_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_agdw_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_agdw_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_npp_stor_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_npp_stor_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_litt_leaf_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_litt_leaf_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_litt_fnrt_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_litt_fnrt_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_litt_sawd_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_litt_sawd_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_litt_ddwd_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_litt_ddwd_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_r_leaf_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_r_leaf_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_r_stem_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_r_stem_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_r_root_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_r_root_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_r_stor_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)); this%ed_r_stor_col_scpf (:,:) = 0.0_r8 - - ! Carbon State Variables for direct comparison to inventory - dimensions: (disturbance patch, pft x size) - allocate(this%ed_ddbh_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_ddbh_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_ba_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_ba_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_np_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_np_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_m1_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_m1_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_m2_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_m2_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_m3_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_m3_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_m4_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_m4_col_scpf (:,:) = 0.0_r8 - allocate(this%ed_m5_col_scpf (begc:endc,1:nlevsclass_ed*mxpft)) ; this%ed_m5_col_scpf (:,:) = 0.0_r8 - - end subroutine InitAllocate - - !------------------------------------------------------------------------ - subroutine InitHistory(this, bounds) - ! - ! !DESCRIPTION: - ! add history fields for all variables, always set as default='inactive' - ! - ! !USES: - use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools - use clm_varpar , only : nlevdecomp, nlevdecomp_full - use clm_varcon , only : spval - use histFileMod, only : hist_addfld1d, hist_addfld2d, hist_addfld_decomp - ! - ! !ARGUMENTS: - class(ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds - ! - ! !LOCAL VARIABLES: - integer :: k,l,ii,jj - character(8) :: vr_suffix - character(10) :: active - integer :: begp,endp - integer :: begc,endc - character(24) :: fieldname - character(100) :: longname - real(r8), pointer :: data1dptr(:) ! temp. pointer for slicing larger arrays - !--------------------------------------------------------------------- - - begp = bounds%begp; endp = bounds%endp - begc = bounds%begc; endc = bounds%endc - - call hist_addfld1d (fname='TRIMMING', units='none', & - avgflag='A', long_name='Degree to which canopy expansion is limited by leaf economics', & - ptr_patch=this%trimming_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='AREA_PLANT', units='m2', & - avgflag='A', long_name='area occupied by all plants', & - ptr_patch=this%area_plant_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='AREA_TREES', units='m2', & - avgflag='A', long_name='area occupied by woody plants', & - ptr_patch=this%area_trees_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='CANOPY_SPREAD', units='none', & - avgflag='A', long_name='Scaling factor between tree basal area and canopy area', & - ptr_patch=this%canopy_spread_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld2d (fname='PFTbiomass', units='gC/m2', type2d='levgrnd', & - avgflag='A', long_name='total PFT level biomass', & - ptr_patch=this%PFTbiomass_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld2d (fname='PFTleafbiomass', units='gC/m2', type2d='levgrnd', & - avgflag='A', long_name='total PFT level leaf biomass', & - ptr_patch=this%PFTleafbiomass_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld2d (fname='PFTstorebiomass', units='gC/m2', type2d='levgrnd', & - avgflag='A', long_name='total PFT level stored biomass', & - ptr_patch=this%PFTstorebiomass_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld2d (fname='PFTnindivs', units='indiv / m2', type2d='levgrnd', & - avgflag='A', long_name='total PFT level number of individuals', & - ptr_patch=this%PFTnindivs_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='FIRE_NESTEROV_INDEX', units='none', & - avgflag='A', long_name='nesterov_fire_danger index', & - ptr_patch=this%nesterov_fire_danger_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='FIRE_ROS', units='m/min', & - avgflag='A', long_name='fire rate of spread m/min', & - ptr_patch=this%spitfire_ROS_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='EFFECT_WSPEED', units='none', & - avgflag='A', long_name='effective windspeed for fire spread', & - ptr_patch=this%effect_wspeed_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='FIRE_TFC_ROS', units='none', & - avgflag='A', long_name='total fuel consumed', & - ptr_patch=this%TFC_ROS_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='FIRE_INTENSITY', units='kJ/m/s', & - avgflag='A', long_name='spitfire fire intensity: kJ/m/s', & - ptr_patch=this%fire_intensity_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='FIRE_AREA', units='fraction', & - avgflag='A', long_name='spitfire fire area:m2', & - ptr_patch=this%fire_area_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='SCORCH_HEIGHT', units='m', & - avgflag='A', long_name='spitfire fire area:m2', & - ptr_patch=this%scorch_height_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='fire_fuel_mef', units='m', & - avgflag='A', long_name='spitfire fuel moisture', & - ptr_patch=this%fire_fuel_mef_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='fire_fuel_bulkd', units='m', & - avgflag='A', long_name='spitfire fuel bulk density', & - ptr_patch=this%fire_fuel_bulkd_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='fire_fuel_eff_moist', units='m', & - avgflag='A', long_name='spitfire fuel moisture', & - ptr_patch=this%fire_fuel_eff_moist_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='fire_fuel_sav', units='m', & - avgflag='A', long_name='spitfire fuel surface/volume ', & - ptr_patch=this%fire_fuel_sav_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='SUM_FUEL', units='gC m-2', & - avgflag='A', long_name='total ground fuel related to ros (omits 1000hr fuels)', & - ptr_patch=this%sum_fuel_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='LITTER_IN', units='gC m-2 s-1', & - avgflag='A', long_name='Litter flux in leaves', & - ptr_patch=this%litter_in_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='LITTER_OUT', units='gC m-2 s-1', & - avgflag='A', long_name='Litter flux out leaves', & - ptr_patch=this%litter_out_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='SEED_BANK', units='gC m-2', & - avgflag='A', long_name='Total Seed Mass of all PFTs', & - ptr_patch=this%seed_bank_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='SEEDS_IN', units='gC m-2 s-1', & - avgflag='A', long_name='Seed Production Rate', & - ptr_patch=this%seeds_in_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='SEED_GERMINATION', units='gC m-2 s-1', & - avgflag='A', long_name='Seed mass converted into new cohorts', & - ptr_patch=this%seed_germination_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='SEED_DECAY', units='gC m-2 s-1', & - avgflag='A', long_name='Seed mass decay', & - ptr_patch=this%seed_decay_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='ED_bstore', units='gC m-2', & - avgflag='A', long_name='ED stored biomass', & - ptr_patch=this%ED_bstore_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='ED_bdead', units='gC m-2', & - avgflag='A', long_name='ED dead biomass', & - ptr_patch=this%ED_bdead_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='ED_balive', units='gC m-2', & - avgflag='A', long_name='ED live biomass', & - ptr_patch=this%ED_balive_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='ED_bleaf', units='gC m-2', & - avgflag='A', long_name='ED leaf biomass', & - ptr_patch=this%ED_bleaf_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='ED_biomass', units='gC m-2', & - avgflag='A', long_name='ED total biomass', & - ptr_patch=this%ED_biomass_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='RB', units='s m-1', & - avgflag='A', long_name='leaf boundary resistance', & - ptr_patch=this%rb_patch, set_lake=0._r8, set_urb=0._r8) - - call hist_addfld1d (fname='EFPOT', units='', & - avgflag='A', long_name='potential evap', & - ptr_patch=this%efpot_patch, set_lake=0._r8, set_urb=0._r8) - - this%gpp_patch(begp:endp) = spval - call hist_addfld1d (fname='GPP', units='gC/m^2/s', & - avgflag='A', long_name='gross primary production', & - ptr_patch=this%gpp_patch) - - this%npp_patch(begp:endp) = spval - call hist_addfld1d (fname='NPP', units='gC/m^2/s', & - avgflag='A', long_name='net primary production', & - ptr_patch=this%npp_patch) - - this%ar_patch(begp:endp) = spval - call hist_addfld1d (fname='AR', units='gC/m^2/s', & - avgflag='A', long_name='autotrophic respiration', & - ptr_patch=this%ar_patch) - - this%growth_resp_patch(begp:endp) = spval - call hist_addfld1d (fname='GROWTH_RESP', units='gC/m^2/s', & - avgflag='A', long_name='growth respiration', & - ptr_patch=this%growth_resp_patch) - - this%maint_resp_patch(begp:endp) = spval - call hist_addfld1d (fname='MAINT_RESP', units='gC/m^2/s', & - avgflag='A', long_name='maintenance respiration', & - ptr_patch=this%maint_resp_patch) - - this%nep_col(begc:endc) = spval - call hist_addfld1d (fname='NEP', units='gC/m^2/s', & - avgflag='A', long_name='net ecosystem production', & - ptr_col=this%nep_col) - - this%fire_c_to_atm_col(begc:endc) = spval - call hist_addfld1d (fname='Fire_Closs', units='gC/m^2/s', & - avgflag='A', long_name='ED/SPitfire Carbon loss to atmosphere', & - ptr_col=this%fire_c_to_atm_col) - - this%nbp_col(begc:endc) = spval - call hist_addfld1d (fname='NBP', units='gC/m^2/s', & - avgflag='A', long_name='net biosphere production', & - ptr_col=this%nbp_col) - - this%npp_col(begc:endc) = spval - call hist_addfld1d (fname='NPP_column', units='gC/m^2/s', & - avgflag='A', long_name='net primary production on column level', & - ptr_col=this%npp_col,default='inactive') - - this%totecosysc_col(begc:endc) = spval - call hist_addfld1d (fname='TOTECOSYSC', units='gC/m^2', & - avgflag='A', long_name='total ecosystem carbon', & - ptr_col=this%totecosysc_col) - - this%cbalance_error_ed_col(begc:endc) = spval - call hist_addfld1d (fname='CBALANCE_ERROR_ED', units='gC/m^2/s', & - avgflag='A', long_name='total carbon balance error on ED side', & - ptr_col=this%cbalance_error_ed_col) - - this%cbalance_error_bgc_col(begc:endc) = spval - call hist_addfld1d (fname='CBALANCE_ERROR_BGC', units='gC/m^2/s', & - avgflag='A', long_name='total carbon balance error on BGC side', & - ptr_col=this%cbalance_error_bgc_col) - - this%cbalance_error_total_col(begc:endc) = spval - call hist_addfld1d (fname='CBALANCE_ERROR_TOTAL', units='gC/m^2/s', & - avgflag='A', long_name='total carbon balance error total', & - ptr_col=this%cbalance_error_total_col) - - this%biomass_stock_col(begc:endc) = spval - call hist_addfld1d (fname='BIOMASS_STOCK_COL', units='gC/m^2', & - avgflag='A', long_name='total ED biomass carbon at the column level', & - ptr_col=this%biomass_stock_col) - - this%ed_litter_stock_col(begc:endc) = spval - call hist_addfld1d (fname='ED_LITTER_STOCK_COL', units='gC/m^2', & - avgflag='A', long_name='total ED litter carbon at the column level', & - ptr_col=this%ed_litter_stock_col) - - this%cwd_stock_col(begc:endc) = spval - call hist_addfld1d (fname='CWD_STOCK_COL', units='gC/m^2', & - avgflag='A', long_name='total CWD carbon at the column level', & - ptr_col=this%cwd_stock_col) - - this%seed_stock_col(begc:endc) = spval - call hist_addfld1d (fname='SEED_STOCK_COL', units='gC/m^2', & - avgflag='A', long_name='total seed carbon at the column level', & - ptr_col=this%seed_stock_col) - - - ! Carbon Flux (grid dimension x scpf) - ! ============================================================== - - call hist_addfld2d (fname='ED_GPP_COL_SCPF',units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='gross primary production', & - ptr_gcell=this%ed_gpp_col_scpf,default='inactive') - - call hist_addfld2d (fname='ED_NPP_LEAF_COL_SCPF',units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into leaves', & - ptr_gcell=this%ed_npp_leaf_col_scpf,default='inactive') - - call hist_addfld2d (fname='ED_NPP_SEED_COL_SCPF',units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into seeds', & - ptr_gcell=this%ed_npp_seed_col_scpf,default='inactive') - - call hist_addfld2d (fname='ED_NPP_FNRT_COL_SCPF',units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into fine roots', & - ptr_gcell=this%ed_npp_fnrt_col_scpf,default='inactive') - - call hist_addfld2d (fname='ED_NPP_BGSW_COL_SCPF',units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into below-ground sapwood', & - ptr_gcell=this%ed_npp_bgsw_col_scpf,default='inactive') - - call hist_addfld2d (fname='ED_NPP_BGDW_COL_SCPF',units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into below-ground deadwood', & - ptr_gcell=this%ed_npp_bgdw_col_scpf,default='inactive') - - call hist_addfld2d (fname='ED_NPP_AGSW_COL_SCPF',units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into above-ground sapwood', & - ptr_gcell=this%ed_npp_agsw_col_scpf,default='inactive') - - call hist_addfld2d ( fname = 'ED_NPP_AGDW_COL_SCPF', units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into above-ground deadwood', & - ptr_gcell=this%ed_npp_agdw_col_scpf,default='inactive') - - call hist_addfld2d ( fname = 'ED_NPP_STOR_COL_SCPF', units='kgC/m2/yr',type2d='levscpf',& - avgflag='A', long_name='NPP flux into storage', & - ptr_gcell=this%ed_npp_stor_col_scpf,default='inactive') - - call hist_addfld2d (fname='ED_DDBH_COL_SCPF', units = 'cm/yr/ha', type2d = 'levscpf', & - avgflag='A', long_name='diameter growth increment and pft/size', & - ptr_gcell=this%ed_ddbh_col_scpf, default='inactive') - - call hist_addfld2d (fname='ED_BA_COL_SCPF',units = 'm2/ha', type2d = 'levscpf', & - avgflag='A', long_name='basal area by patch and pft/size', & - ptr_gcell=this%ed_ba_col_scpf, default='inactive') - - call hist_addfld2d (fname='ED_NPLANT_COL_SCPF',units = 'N/ha', type2d = 'levscpf', & - avgflag='A', long_name='stem number density by patch and pft/size', & - ptr_gcell=this%ed_np_col_scpf, default='inactive') - - call hist_addfld2d (fname='ED_M1_COL_SCPF',units = 'N/ha/yr', type2d = 'levscpf', & - avgflag='A', long_name='background mortality count by patch and pft/size', & - ptr_gcell=this%ed_m1_col_scpf, default='inactive') - - call hist_addfld2d (fname='ED_M2_COL_SCPF',units = 'N/ha/yr', type2d = 'levscpf', & - avgflag='A', long_name='hydraulic mortality count by patch and pft/size', & - ptr_gcell=this%ed_m2_col_scpf, default='inactive') - - call hist_addfld2d (fname='ED_M3_COL_SCPF',units = 'N/ha/yr', type2d = 'levscpf', & - avgflag='A', long_name='carbon starvation mortality count by patch and pft/size', & - ptr_gcell=this%ed_m3_col_scpf, default='inactive') - - call hist_addfld2d (fname='ED_M4_COL_SCPF',units = 'N/ha/yr', type2d = 'levscpf', & - avgflag='A', long_name='impact mortality count by patch and pft/size', & - ptr_gcell=this%ed_m4_col_scpf, default='inactive') - - call hist_addfld2d (fname='ED_M5_COL_SCPF',units = 'N/ha/yr', type2d = 'levscpf', & - avgflag='A', long_name='fire mortality count by patch and pft/size', & - ptr_gcell=this%ed_m5_col_scpf, default='inactive') - - this%ed_npatches_col(begc:endc) = spval - call hist_addfld1d (fname='ED_NPATCHES', units='unitless', & - avgflag='A', long_name='ED total number of patches per site', & - ptr_col=this%ed_npatches_col) - - this%ed_ncohorts_col(begc:endc) = spval - call hist_addfld1d (fname='ED_NCOHORTS', units='unitless', & - avgflag='A', long_name='ED total number of cohorts per site', & - ptr_col=this%ed_ncohorts_col) - - end subroutine InitHistory - - !----------------------------------------------------------------------- - ! subroutine InitCold(this, bounds) - ! ! - ! ! !DESCRIPTION: - ! ! Initialize relevant time varying variables - ! ! - ! ! !ARGUMENTS: - ! class (ed_clm_type) :: this - ! type(bounds_type), intent(in) :: bounds - ! ! - ! ! !LOCAL VARIABLES: - ! integer :: p - ! !----------------------------------------------------------------------- - - ! ! do p = bounds%begp,bounds%endp - ! ! this%dispvegc_patch(p) = 0._r8 - ! ! this%storvegc_patch(p) = 0._r8 - ! ! end do - - ! end subroutine InitCold - !----------------------------------------------------------------------- - subroutine Restart ( this, bounds, ncid, flag ) - ! - ! !DESCRIPTION: - ! Read/write restart data - ! - ! !USES: - use restUtilMod - use ncdio_pio - ! use EDtypesMod , only : numpft_ed - - ! - ! !ARGUMENTS: - class (ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds - type(file_desc_t) , intent(inout) :: ncid - character(len=*) , intent(in) :: flag !'read' or 'write' or 'define' - ! - ! !LOCAL VARIABLES: - logical :: readvar - real(r8), pointer :: ptr2d(:,:) ! temp. pointers for slicing larger arrays - real(r8), pointer :: ptr1d(:) ! temp. pointers for slicing larger arrays - ! character(LEN=3) :: istr1 - ! integer :: k - !------------------------------------------------------------------------ - - ptr1d => this%nep_timeintegrated_col(:) - call restartvar(ncid=ncid, flag=flag, varname='nep_timeintegrated_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%npp_timeintegrated_col(:) - call restartvar(ncid=ncid, flag=flag, varname='npp_timeintegrated_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%hr_timeintegrated_col(:) - call restartvar(ncid=ncid, flag=flag, varname='hr_timeintegrated_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%totecosysc_old_col(:) - call restartvar(ncid=ncid, flag=flag, varname='totecosysc_old_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%cbalance_error_ed_col(:) - call restartvar(ncid=ncid, flag=flag, varname='cbalance_error_ed_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%cbalance_error_bgc_col(:) - call restartvar(ncid=ncid, flag=flag, varname='cbalance_error_bgc_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%cbalance_error_total_col(:) - call restartvar(ncid=ncid, flag=flag, varname='cbalance_error_total_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%totedc_old_col(:) - call restartvar(ncid=ncid, flag=flag, varname='totedc_old_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%totbgcc_old_col(:) - call restartvar(ncid=ncid, flag=flag, varname='totbgcc_old_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%ed_to_bgc_this_edts_col(:) - call restartvar(ncid=ncid, flag=flag, varname='ed_to_bgc_this_edts_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%ed_to_bgc_last_edts_col(:) - call restartvar(ncid=ncid, flag=flag, varname='ed_to_bgc_last_edts_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - ptr1d => this%seed_rain_flux_col(:) - call restartvar(ncid=ncid, flag=flag, varname='seed_rain_flux_col', xtype=ncd_double, & - dim1name='column', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=ptr1d) - - - end subroutine Restart - - !----------------------------------------------------------------------- - subroutine SetValues( this, bounds, val) - ! - ! !ARGUMENTS: - class (ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds - real(r8) , intent(in) :: val - ! - ! !LOCAL VARIABLES: - integer :: fi,i,j,k,l ! loop index - !----------------------------------------------------------------------- - - ! - ! FIX(SPM,082714) - commenting these lines out while merging ED branch to CLM - ! trunk. Commented out by RF to work out science issues - ! - !this%trimming_patch (:) = val - !this%canopy_spread_patch (:) = val - !this%PFTbiomass_patch (:,:) = val - !this%PFTleafbiomass_patch (:,:) = val - !this%PFTstorebiomass_patch (:,:) = val - !this%PFTnindivs_patch (:,:) = val - this%efpot_patch (:) = val - this%rb_patch (:) = val - - end subroutine SetValues - - !----------------------------------------------------------------------- - - subroutine ed_clm_link( this, bounds, nsites, sites, fcolumn, waterstate_inst, canopystate_inst) - ! - ! !USES: - use landunit_varcon , only : istsoil - use EDGrowthFunctionsMod , only : tree_lai, c_area - use EDEcophysConType , only : EDecophyscon - use EDtypesMod , only : area - use PatchType , only : clmpatch => patch - use LandunitType , only : lun - use pftconMod , only : pftcon - use CanopyStateType , only : canopystate_type - use WaterStateType , only : waterstate_type - - ! !ARGUMENTS - class(ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - type(waterstate_type) , intent(inout) :: waterstate_inst - type(canopystate_type) , intent(inout) :: canopystate_inst - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort - integer :: g,l,p,c,s - integer :: ft ! plant functional type - integer :: patchn ! identification number for each patch. - real(r8) :: total_bare_ground ! sum of the bare fraction in all pfts. - real(r8) :: total_patch_area - real(r8) :: coarse_wood_frac - real(r8) :: canopy_leaf_area ! total amount of leaf area in the vegetated area. m2. - integer :: begp_fp, endp_fp ! Valid range of patch indices that are associated with - ! FATES (F) for each parent (P) iteration (grid/column) - !---------------------------------------------------------------------- - - if ( DEBUG ) then - write(iulog,*) 'in ed_clm_link' - endif - - associate( & - tlai => canopystate_inst%tlai_patch , & - elai => canopystate_inst%elai_patch , & - tsai => canopystate_inst%tsai_patch , & - esai => canopystate_inst%esai_patch , & - htop => canopystate_inst%htop_patch , & - hbot => canopystate_inst%hbot_patch , & - begg => bounds%begg , & - endg => bounds%endg , & - begc => bounds%begc , & - endc => bounds%endc , & - begp => bounds%begp , & - endp => bounds%endp & - ) - - - do s = 1,nsites - - c = fcolumn(s) - - ! ============================================================================ - ! Zero the bare ground tile BGC variables. - ! Valid Range for zero'ing here is the soil_patch and non crop patches - ! If the crops are not turned on, don't worry, they were zero'd once and should - ! not change again (RGK). - ! col%patchi(c) + numpft - numcft - ! ============================================================================ - - begp_fp = col%patchi(c) - endp_fp = col%patchi(c) + numpft - numcft - - clmpatch%is_veg(begp_fp:endp_fp) = .false. - clmpatch%is_bareground(begp_fp:endp_fp) = .false. - - tlai(begp_fp:endp_fp) = 0.0_r8 - htop(begp_fp:endp_fp) = 0.0_r8 - hbot(begp_fp:endp_fp) = 0.0_r8 - elai(begp_fp:endp_fp) = 0.0_r8 - tsai(begp_fp:endp_fp) = 0.0_r8 - esai(begp_fp:endp_fp) = 0.0_r8 - - - patchn = 0 - total_bare_ground = 0.0_r8 - total_patch_area = 0._r8 - - currentPatch => sites(s)%oldest_patch - do while(associated(currentPatch)) - patchn = patchn + 1 - currentPatch%patchno = patchn - - if (patchn <= numpft - numcft)then !don't expand into crop patches. - - currentPatch%clm_pno = col%patchi(c) + patchn !the first 'soil' patch is unvegetated... - - ! INTERF-TODO: currentPatch%clm_pno should be removed (FATES internal variable with CLM iformation) - - p = col%patchi(c) + patchn - - if(c .ne. clmpatch%column(p))then - write(iulog,*) ' fcolumn(s) does not match clmpatch%column(p)' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - clmpatch%is_veg(p) = .true. !this .is. a tile filled with vegetation... - - call currentPatch%set_root_fraction() - - !zero cohort-summed variables. - currentPatch%total_canopy_area = 0.0_r8 - currentPatch%total_tree_area = 0.0_r8 - currentPatch%lai = 0.0_r8 - canopy_leaf_area = 0.0_r8 - - !update cohort quantitie s - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - - ft = currentCohort%pft - currentCohort%livestemn = currentCohort%bsw / pftcon%leafcn(currentCohort%pft) - - currentCohort%livecrootn = 0.0_r8 - - if (pftcon%woody(ft) == 1) then - coarse_wood_frac = 0.5_r8 - else - coarse_wood_frac = 0.0_r8 - end if - - if ( DEBUG ) then - write(iulog,*) 'EDCLMLink 618 ',currentCohort%livecrootn - write(iulog,*) 'EDCLMLink 619 ',currentCohort%br - write(iulog,*) 'EDCLMLink 620 ',coarse_wood_frac - write(iulog,*) 'EDCLMLink 621 ',pftcon%leafcn(ft) - endif - - currentCohort%livecrootn = currentCohort%br * coarse_wood_frac / pftcon%leafcn(ft) - - if ( DEBUG ) write(iulog,*) 'EDCLMLink 625 ',currentCohort%livecrootn - - currentCohort%b = currentCohort%balive+currentCohort%bdead+currentCohort%bstore - currentCohort%treelai = tree_lai(currentCohort) - - currentCohort%c_area = c_area(currentCohort) - canopy_leaf_area = canopy_leaf_area + currentCohort%treelai *currentCohort%c_area - - - if(currentCohort%canopy_layer==1)then - currentPatch%total_canopy_area = currentPatch%total_canopy_area + currentCohort%c_area - if(pftcon%woody(ft)==1)then - currentPatch%total_tree_area = currentPatch%total_tree_area + currentCohort%c_area - endif - endif - - ! Check for erroneous zero values. - if(currentCohort%dbh <= 0._r8 .or. currentCohort%n == 0._r8)then - write(iulog,*) 'ED: dbh or n is zero in clmedlink', currentCohort%dbh,currentCohort%n - endif - if(currentCohort%pft == 0.or.currentCohort%canopy_trim <= 0._r8)then - write(iulog,*) 'ED: PFT or trim is zero in clmedlink',currentCohort%pft,currentCohort%canopy_trim - endif - if(currentCohort%balive <= 0._r8)then - write(iulog,*) 'ED: balive is zero in clmedlink',currentCohort%balive - endif - - currentCohort => currentCohort%taller - - enddo ! ends 'do while(associated(currentCohort)) - - if ( currentPatch%total_canopy_area-currentPatch%area > 0.000001_r8 ) then - write(iulog,*) 'ED: canopy area bigger than area',currentPatch%total_canopy_area ,currentPatch%area - currentPatch%total_canopy_area = currentPatch%area - endif - - ! PASS BACK PATCH-LEVEL QUANTITIES THAT ARE NEEDED BY THE CLM CODE - if (associated(currentPatch%tallest)) then - htop(p) = currentPatch%tallest%hite - else - ! FIX(RF,040113) - should this be a parameter for the minimum possible vegetation height? - htop(p) = 0.1_r8 - endif - - hbot(p) = max(0._r8, min(0.2_r8, htop(p)- 1.0_r8)) - - ! leaf area index: of .only. the areas with some vegetation on them, as the non-vegetated areas - ! are merged into the bare ground fraction. This introduces a degree of unrealism, - ! which could be fixed if the surface albedo routine took account of the possibiltiy of bare - ! ground mixed with trees. - - if(currentPatch%total_canopy_area > 0)then; - tlai(p) = canopy_leaf_area/currentPatch%total_canopy_area - else - tlai(p) = 0.0_r8 - endif - - - ! We are assuming here that grass is all located underneath tree canopies. - ! The alternative is to assume it is all spatial distinct from tree canopies. - ! In which case, the bare area would have to be reduced by the grass area... - ! currentPatch%total_canopy_area/currentPatch%area is fraction of this patch cover by plants - ! currentPatch%area/AREA is the fraction of the soil covered by this patch. - - - clmpatch%wt_ed(p) = min(1.0_r8,(currentPatch%total_canopy_area/currentPatch%area)) * & - (currentPatch%area/AREA) - currentPatch%bare_frac_area = (1.0_r8 - min(1.0_r8,currentPatch%total_canopy_area/currentPatch%area)) * & - (currentPatch%area/AREA) - - if ( DEBUG ) then - write(iulog, *) 'EDCLMLinkMod bare frac', currentPatch%bare_frac_area - end if - - total_patch_area = total_patch_area + clmpatch%wt_ed(p) + currentPatch%bare_frac_area - total_bare_ground = total_bare_ground + currentPatch%bare_frac_area - - else - write(iulog,*) 'ED: too many patches' - end if ! patchn<15 - - currentPatch => currentPatch%younger - end do !patch loop - - if((total_patch_area-1.0_r8)>1e-9)then - write(iulog,*) 'total area is wrong in CLMEDLINK',total_patch_area - endif - - ! loop round all and zero the remaining empty vegetation patches - ! while ED's domain of influence only extends to non-crop patches - ! wt_ed should not be non-zero anwhere but ED patches, so this loop is ok - do p = col%patchi(c)+patchn+1,col%patchi(c)+numpft - clmpatch%wt_ed(p) = 0.0_r8 - enddo - - !set the area of the bare ground patch. - p = col%patchi(c) - clmpatch%wt_ed(p) = total_bare_ground - clmpatch%is_bareground = .true. - - call this%ed_clm_leaf_area_profile(sites(s), c, waterstate_inst, canopystate_inst ) - - end do ! column loop - - call this%ed_update_history_variables(bounds, nsites, sites(:), fcolumn(:), canopystate_inst) - - end associate - - end subroutine ed_clm_link - - !----------------------------------------------------------------------- - subroutine ed_update_history_variables( this, bounds, nsites, sites, fcolumn, canopystate_inst) - ! - ! !USES: - use CanopyStateType , only : canopystate_type - use PatchType , only : clmpatch => patch - use pftconMod , only : pftcon - - ! - ! !ARGUMENTS: - class(ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds ! clump bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type) , pointer :: currentCohort - type(canopystate_type) , intent(inout) :: canopystate_inst - ! - ! !LOCAL VARIABLES: - integer :: p,ft,c,s -! integer :: firstsoilpatch(bounds%begg:bounds%endg) - real(r8) :: n_density ! individual of cohort per m2. - real(r8) :: n_perm2 ! individuals per m2 for the whole column - real(r8) :: patch_scaling_scalar ! ratio of canopy to patch area for counteracting patch scaling - real(r8) :: dbh ! actual dbh used to identify relevant size class - integer :: scpf ! size class x pft index - integer :: sc - !----------------------------------------------------------------------- - - associate( & - trimming => this%trimming_patch , & ! Output: - canopy_spread => this%canopy_spread_patch , & ! Output: - PFTbiomass => this%PFTbiomass_patch , & ! Output: - PFTleafbiomass => this%PFTleafbiomass_patch , & ! Output: - PFTstorebiomass => this%PFTstorebiomass_patch , & ! Output: - PFTnindivs => this%PFTnindivs_patch , & ! Output: - area_plant => this%area_plant_patch , & ! Output: - area_trees => this%area_trees_patch , & ! Output: - nesterov_fire_danger => this%nesterov_fire_danger_patch , & ! Output: - spitfire_ROS => this%spitfire_ROS_patch , & ! Output: - effect_wspeed => this%effect_wspeed_patch , & ! Output: - TFC_ROS => this%TFC_ROS_patch , & ! Output: - sum_fuel => this%sum_fuel_patch , & ! Output: - fire_intensity => this%fire_intensity_patch , & ! Output: - fire_area => this%fire_area_patch , & ! Output: - scorch_height => this%scorch_height_patch , & ! Output: - fire_fuel_bulkd => this%fire_fuel_bulkd_patch , & ! Output: - fire_fuel_eff_moist => this%fire_fuel_eff_moist_patch , & ! Output: - fire_fuel_sav => this%fire_fuel_sav_patch , & ! Output: - fire_fuel_mef => this%fire_fuel_mef_patch , & ! Output: - litter_in => this%litter_in_patch , & ! Output: - litter_out => this%litter_out_patch , & ! Output: - seed_bank => this%seed_bank_patch , & ! Output: - seeds_in => this%seeds_in_patch , & ! Output: - seed_decay => this%seed_decay_patch , & ! Output: - seed_germination => this%seed_germination_patch , & ! Output: - - ED_biomass => this%ED_biomass_patch , & ! InOut: - ED_bdead => this%ED_bdead_patch , & ! InOut: - ED_bleaf => this%ED_bleaf_patch , & ! InOut: - ED_balive => this%ED_balive_patch , & ! InOut: - ED_bstore => this%ED_bstore_patch , & ! InOut: - - ed_gpp_scpf => this%ed_gpp_col_scpf , & - ed_npp_totl_scpf => this%ed_npp_totl_col_scpf , & - ed_npp_leaf_scpf => this%ed_npp_leaf_col_scpf , & - ed_npp_seed_scpf => this%ed_npp_seed_col_scpf , & - ed_npp_fnrt_scpf => this%ed_npp_fnrt_col_scpf , & - ed_npp_bgsw_scpf => this%ed_npp_bgsw_col_scpf , & - ed_npp_bgdw_scpf => this%ed_npp_bgdw_col_scpf , & - ed_npp_agsw_scpf => this%ed_npp_agsw_col_scpf , & - ed_npp_agdw_scpf => this%ed_npp_agdw_col_scpf , & - ed_npp_stor_scpf => this%ed_npp_stor_col_scpf , & - - ed_npatches => this%ed_npatches_col , & - ed_ncohorts => this%ed_ncohorts_col , & - - ed_ddbh_col_scpf => this%ed_ddbh_col_scpf , & - ed_ba_col_scpf => this%ed_ba_col_scpf , & - ed_np_col_scpf => this%ed_np_col_scpf , & - ed_m1_col_scpf => this%ed_m1_col_scpf , & - ed_m2_col_scpf => this%ed_m2_col_scpf , & - ed_m3_col_scpf => this%ed_m3_col_scpf , & - ed_m4_col_scpf => this%ed_m4_col_scpf , & - ed_m5_col_scpf => this%ed_m5_col_scpf , & - - tlai => canopystate_inst%tlai_patch , & ! InOut: - elai => canopystate_inst%elai_patch , & ! InOut: - tsai => canopystate_inst%tsai_patch , & ! InOut: - esai => canopystate_inst%esai_patch , & ! InOut: - - begp => bounds%begp , & - endp => bounds%endp & - ) - - ! ============================================================================ - ! Zero the whole variable so we dont have ghost values when patch number declines. - ! ============================================================================ - - trimming(:) = 1.0_r8 !the default value of this is 1.0, making it 0.0 means that the output is confusing. - canopy_spread(:) = 0.0_r8 - PFTbiomass(:,:) = 0.0_r8 - PFTleafbiomass(:,:) = 0.0_r8 - PFTstorebiomass(:,:) = 0.0_r8 - PFTnindivs(:,:) = 0.0_r8 - area_plant(:) = 0.0_r8 - area_trees(:) = 0.0_r8 - nesterov_fire_danger(:) = 0.0_r8 - spitfire_ROS(:) = 0.0_r8 - effect_wspeed = 0.0_r8 - TFC_ROS(:) = 0.0_r8 - fire_intensity(:) = 0.0_r8 - fire_area(:) = 0.0_r8 - scorch_height(:) = 0.0_r8 - fire_fuel_bulkd(:) = 0.0_r8 - fire_fuel_eff_moist(:) = 0.0_r8 - fire_fuel_sav(:) = 0.0_r8 - fire_fuel_mef(:) = 0.0_r8 - litter_in(:) = 0.0_r8 - litter_out(:) = 0.0_r8 - seed_bank(:) = 0.0_r8 - seeds_in(:) = 0.0_r8 - seed_decay(:) = 0.0_r8 - seed_germination(:) = 0.0_r8 - ED_biomass(:) = 0.0_r8 - ED_bdead(:) = 0.0_r8 - ED_bleaf(:) = 0.0_r8 - ED_bstore(:) = 0.0_r8 - ED_balive(:) = 0.0_r8 - - ed_gpp_scpf(:,:) = 0.0_r8 - ed_npp_totl_scpf(:,:) = 0.0_r8 - ed_npp_leaf_scpf(:,:) = 0.0_r8 - ed_npp_seed_scpf(:,:) = 0.0_r8 - ed_npp_fnrt_scpf(:,:) = 0.0_r8 - ed_npp_bgsw_scpf(:,:) = 0.0_r8 - ed_npp_bgdw_scpf(:,:) = 0.0_r8 - ed_npp_agsw_scpf(:,:) = 0.0_r8 - ed_npp_agdw_scpf(:,:) = 0.0_r8 - ed_npp_stor_scpf(:,:) = 0.0_r8 - - ed_ddbh_col_scpf(:,:) = 0.0_r8 - ed_ba_col_scpf(:,:) = 0.0_r8 - ed_np_col_scpf(:,:) = 0.0_r8 - ed_m1_col_scpf(:,:) = 0.0_r8 - ed_m2_col_scpf(:,:) = 0.0_r8 - ed_m3_col_scpf(:,:) = 0.0_r8 - ed_m4_col_scpf(:,:) = 0.0_r8 - ed_m5_col_scpf(:,:) = 0.0_r8 - - ed_npatches(:) = 0._r8 - ed_ncohorts(:) = 0._r8 - - do s = 1,nsites - - c = fcolumn(s) - - ! ============================================================================ - ! Zero the bare ground tile BGC variables. - ! ============================================================================ - - p = col%patchi(c) - - ! INTERF-TODO: THIS ZERO'ING IS REDUNDANT, THE WHOLE PATCH CLUMP IS ALREADY ZERO'D - - trimming(p) = 1.0_r8 - canopy_spread(p) = 0.0_r8 - PFTbiomass(p,:) = 0.0_r8 - PFTleafbiomass(p,:) = 0.0_r8 - PFTstorebiomass(p,:) = 0.0_r8 - PFTnindivs(p,:) = 0.0_r8 - area_plant(p) = 0.0_r8 - area_trees(p) = 0.0_r8 - nesterov_fire_danger(p) = 0.0_r8 - spitfire_ROS(p) = 0.0_r8 - TFC_ROS(p) = 0.0_r8 - effect_wspeed(p) = 0.0_r8 - fire_intensity(p) = 0.0_r8 - fire_area(p) = 0.0_r8 - scorch_height(p) = 0.0_r8 - fire_fuel_bulkd(p) = 0.0_r8 - fire_fuel_eff_moist(p) = 0.0_r8 - fire_fuel_sav(p) = 0.0_r8 - fire_fuel_mef(p) = 0.0_r8 - litter_in(p) = 0.0_r8 - litter_out(p) = 0.0_r8 - seed_bank(p) = 0.0_r8 - seeds_in(p) = 0.0_r8 - seed_decay(p) = 0.0_r8 - seed_germination(p) = 0.0_r8 - ED_biomass(p) = 0.0_r8 - ED_balive(p) = 0.0_r8 - ED_bdead(p) = 0.0_r8 - ED_bstore(p) = 0.0_r8 - ED_bleaf(p) = 0.0_r8 - elai(p) = 0.0_r8 - tlai(p) = 0.0_r8 - tsai(p) = 0.0_r8 - esai(p) = 0.0_r8 - ED_bleaf(p) = 0.0_r8 - sum_fuel(p) = 0.0_r8 - - currentPatch => sites(s)%oldest_patch - do while(associated(currentPatch)) - - ! INTERF-TODO: THIS LOGIC SHOULDN'T BE NECESSARY, SHOULD BE CHECKED AT THE BEGINNING - ! OF LINKING, ONCE - ! %patchno is the local index of the ED/FATES patches, starting at 1 - if(currentPatch%patchno <= numpft - numcft)then !don't expand into crop patches. - - ! Increment CLM/ALM patch index, first was non-veg, these are veg - p = p + 1 - - ed_npatches(c) = ed_npatches(c) + 1._r8 - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - !accumulate into history variables. - - ft = currentCohort%pft - - ed_ncohorts(c) = ed_ncohorts(c) + 1._r8 - - if ((currentPatch%area .gt. 0._r8) .and. (currentPatch%total_canopy_area .gt. 0._r8)) then - - ! for quantities that are at the CLM patch level, because of the way that CLM patches are weighted for radiative purposes - ! this # density needs to be over either ED patch canopy area or ED patch total area, whichever is less - n_density = currentCohort%n/min(currentPatch%area,currentPatch%total_canopy_area) - - ! for quantities that are natively at column level, calculate plant density using whole area - n_perm2 = currentCohort%n/AREA - - else - n_density = 0.0_r8 - n_perm2 = 0.0_r8 - endif - - if ( DEBUG ) then - write(iulog,*) 'EDCLMLinkMod I ',currentCohort%bstore - write(iulog,*) 'EDCLMLinkMod II ',p,ED_bstore(p) - endif - - ED_bleaf(p) = ED_bleaf(p) + n_density * currentCohort%bl * 1.e3_r8 - ED_bstore(p) = ED_bstore(p) + n_density * currentCohort%bstore * 1.e3_r8 - ED_biomass(p) = ED_biomass(p) + n_density * currentCohort%b * 1.e3_r8 - ED_bdead(p) = ED_bdead(p) + n_density * currentCohort%bdead * 1.e3_r8 - ED_balive(p) = ED_balive(p) + n_density * currentCohort%balive * 1.e3_r8 - PFTbiomass(p,ft) = PFTbiomass(p,ft) + n_density * currentCohort%b * 1.e3_r8 - PFTleafbiomass(p,ft) = PFTleafbiomass(p,ft) + n_density * currentCohort%bl * 1.e3_r8 - PFTstorebiomass(p,ft) = PFTstorebiomass(p,ft) + n_density * currentCohort%bstore * 1.e3_r8 - PFTnindivs(p,ft) = PFTnindivs(p,ft) + currentCohort%n - - dbh = currentCohort%dbh !-0.5*(1./365.25)*currentCohort%ddbhdt - sc = count(dbh-sclass_ed.ge.0.0) - scpf = (ft-1)*nlevsclass_ed+sc - - ! Flux Variables (must pass a NaN check on growth increment and not be recruits) - if( .not.(currentCohort%isnew) ) then - ed_gpp_scpf(c,scpf) = ed_gpp_scpf(c,scpf) + n_perm2*currentCohort%gpp ! [kgC/m2/yr] - ed_npp_totl_scpf(c,scpf) = ed_npp_totl_scpf(c,scpf) + currentcohort%npp*n_perm2 - ed_npp_leaf_scpf(c,scpf) = ed_npp_leaf_scpf(c,scpf) + currentcohort%npp_leaf*n_perm2 - ed_npp_fnrt_scpf(c,scpf) = ed_npp_fnrt_scpf(c,scpf) + currentcohort%npp_froot*n_perm2 - ed_npp_bgsw_scpf(c,scpf) = ed_npp_bgsw_scpf(c,scpf) + currentcohort%npp_bsw*(1._r8-ED_val_ag_biomass)*n_perm2 - ed_npp_agsw_scpf(c,scpf) = ed_npp_agsw_scpf(c,scpf) + currentcohort%npp_bsw*ED_val_ag_biomass*n_perm2 - ed_npp_bgdw_scpf(c,scpf) = ed_npp_bgdw_scpf(c,scpf) + currentcohort%npp_bdead*(1._r8-ED_val_ag_biomass)*n_perm2 - ed_npp_agdw_scpf(c,scpf) = ed_npp_agdw_scpf(c,scpf) + currentcohort%npp_bdead*ED_val_ag_biomass*n_perm2 - ed_npp_seed_scpf(c,scpf) = ed_npp_seed_scpf(c,scpf) + currentcohort%npp_bseed*n_perm2 - ed_npp_stor_scpf(c,scpf) = ed_npp_stor_scpf(c,scpf) + currentcohort%npp_store*n_perm2 - if( abs(currentcohort%npp-(currentcohort%npp_leaf+currentcohort%npp_froot+ & - currentcohort%npp_bsw+currentcohort%npp_bdead+ & - currentcohort%npp_bseed+currentcohort%npp_store))>1.e-9) then - write(iulog,*) 'NPP Partitions are not balancing' - write(iulog,*) 'Fractional Error: ',abs(currentcohort%npp-(currentcohort%npp_leaf+currentcohort%npp_froot+ & - currentcohort%npp_bsw+currentcohort%npp_bdead+ & - currentcohort%npp_bseed+currentcohort%npp_store))/currentcohort%npp - write(iulog,*) 'Terms: ',currentcohort%npp,currentcohort%npp_leaf,currentcohort%npp_froot, & - currentcohort%npp_bsw,currentcohort%npp_bdead, & - currentcohort%npp_bseed,currentcohort%npp_store - write(iulog,*) ' NPP components during FATES-HLM linking does not balance ' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - ! Woody State Variables (basal area and number density and mortality) - if (pftcon%woody(ft) == 1) then - - ed_m1_col_scpf(c,scpf) = ed_m1_col_scpf(c,scpf) + currentcohort%bmort*n_perm2*AREA - ed_m2_col_scpf(c,scpf) = ed_m2_col_scpf(c,scpf) + currentcohort%hmort*n_perm2*AREA - ed_m3_col_scpf(c,scpf) = ed_m3_col_scpf(c,scpf) + currentcohort%cmort*n_perm2*AREA - ed_m4_col_scpf(c,scpf) = ed_m4_col_scpf(c,scpf) + currentcohort%imort*n_perm2*AREA - ed_m5_col_scpf(c,scpf) = ed_m5_col_scpf(c,scpf) + currentcohort%fmort*n_perm2*AREA - - ! basal area [m2/ha] - ed_ba_col_scpf(c,scpf) = ed_ba_col_scpf(c,scpf) + & - 0.25*3.14159*((dbh/100.0)**2.0)*n_perm2*AREA - - ! number density [/ha] - ed_np_col_scpf(c,scpf) = ed_np_col_scpf(c,scpf) + AREA*n_perm2 - - ! Growth Incrments must have NaN check and woody check - if(currentCohort%ddbhdt == currentCohort%ddbhdt) then - ed_ddbh_col_scpf(c,scpf) = ed_ddbh_col_scpf(c,scpf) + & - currentCohort%ddbhdt*n_perm2*AREA - else - ed_ddbh_col_scpf(c,scpf) = -999.9 - end if - end if - - end if - - currentCohort => currentCohort%taller - enddo ! cohort loop - - !Patch specific variables that are already calculated - - !These things are all duplicated. Should they all be converted to LL or array structures RF? - ! define scalar to counteract the patch albedo scaling logic for conserved quantities - - if (currentPatch%area .gt. 0._r8 .and. currentPatch%total_canopy_area .gt.0 ) then - patch_scaling_scalar = min(1._r8, currentPatch%area / currentPatch%total_canopy_area) - else - patch_scaling_scalar = 0._r8 - endif - - nesterov_fire_danger(p) = sites(s)%acc_NI - spitfire_ROS(p) = currentPatch%ROS_front - TFC_ROS(p) = currentPatch%TFC_ROS - effect_wspeed(p) = currentPatch%effect_wspeed - fire_intensity(p) = currentPatch%FI - fire_area(p) = currentPatch%frac_burnt - scorch_height(p) = currentPatch%SH - fire_fuel_bulkd(p) = currentPatch%fuel_bulkd - fire_fuel_eff_moist(p) = currentPatch%fuel_eff_moist - fire_fuel_sav(p) = currentPatch%fuel_sav - fire_fuel_mef(p) = currentPatch%fuel_mef - sum_fuel(p) = currentPatch%sum_fuel * 1.e3_r8 * patch_scaling_scalar - - litter_in(p) = (sum(currentPatch%CWD_AG_in) + sum(currentPatch%leaf_litter_in)) * & - 1.e3_r8 * 365.0_r8 * SHR_CONST_CDAY * patch_scaling_scalar - - litter_out(p) = (sum(currentPatch%CWD_AG_out) + sum(currentPatch%leaf_litter_out)) * & - 1.e3_r8 * 365.0_r8 * SHR_CONST_CDAY * patch_scaling_scalar - - seed_bank(p) = sum(currentPatch%seed_bank) * 1.e3_r8 * patch_scaling_scalar - - seeds_in(p) = sum(currentPatch%seeds_in) * 1.e3_r8 * 365.0_r8 * SHR_CONST_CDAY * patch_scaling_scalar - - seed_decay(p) = sum(currentPatch%seed_decay) * 1.e3_r8 * 365.0_r8 * SHR_CONST_CDAY * patch_scaling_scalar - - seed_germination(p) = sum(currentPatch%seed_germination) * & - 1.e3_r8 * 365.0_r8 * SHR_CONST_CDAY * patch_scaling_scalar - - canopy_spread(p) = currentPatch%spread(1) - area_plant(p) = 1._r8 - if (min(currentPatch%total_canopy_area,currentPatch%area)>0.0_r8) then - area_trees(p) = currentPatch%total_tree_area / min(currentPatch%total_canopy_area,currentPatch%area) - else - area_trees(p) = 0.0_r8 - end if - if(associated(currentPatch%tallest))then - trimming(p) = currentPatch%tallest%canopy_trim - else - trimming(p) = 0.0_r8 - endif - - else - write(iulog,*) 'ED: too many patches' - end if ! patchn<15 - - currentPatch => currentPatch%younger - end do !patch loop - - enddo ! site loop - - end associate - - end subroutine ed_update_history_variables - - !------------------------------------------------------------------------ - - ! INTERF-TODO: THIS ROUTINE COULD BE SPLIT. IT CALCULATES BOTH FATES/ED INTERNALS - ! AS WELL AS VARIABLES FOR CLM/ALM. - - - subroutine ed_clm_leaf_area_profile( this, currentSite, colindex, waterstate_inst, canopystate_inst ) - ! - ! !DESCRIPTION: - ! Load LAI in each layer into array to send to CLM - ! - ! !USES: - use FatesGlobals, only : fates_log - - use EDGrowthFunctionsMod , only : tree_lai, tree_sai, c_area - use EDtypesMod , only : area, dinc_ed, hitemax, numpft_ed, n_hite_bins - use EDEcophysConType , only : EDecophyscon - use CanopyStateType , only : canopystate_type - use WaterStateType , only : waterstate_type - use PatchType , only : clmpatch => patch - ! - ! !ARGUMENTS - class(ed_clm_type) :: this - type(ed_site_type) , intent(inout) :: currentSite - integer , intent(in) :: colindex ! ALM/CLM column index of this site - type(waterstate_type) , intent(inout) :: waterstate_inst - type(canopystate_type) , intent(inout) :: canopystate_inst - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort - real(r8) :: remainder !Thickness of layer at bottom of canopy. - real(r8) :: fleaf ! fraction of cohort incepting area that is leaves. - integer :: ft ! Plant functional type index. - integer :: iv ! Vertical leaf layer index - integer :: L ! Canopy layer index - integer :: p ! clm patch index - - real(r8) :: tlai_temp ! calculation of tlai to check this method - real(r8) :: elai_temp ! make a new elai based on the layer-by-layer snow coverage. - real(r8) :: tsai_temp ! - real(r8) :: esai_temp ! - real(r8) :: fraction_exposed ! how much of this layer is not covered by snow? - real(r8) :: layer_top_hite ! notional top height of this canopy layer (m) - real(r8) :: layer_bottom_hite ! notional bottom height of this canopy layer (m) - integer :: smooth_leaf_distribution ! is the leaf distribution this option (1) or not (0) - real(r8) :: frac_canopy(N_HITE_BINS) ! amount of canopy in each height class - real(r8) :: minh(N_HITE_BINS) ! minimum height in height class (m) - real(r8) :: maxh(N_HITE_BINS) ! maximum height in height class (m) - real(r8) :: dh ! vertical detph of height class (m) - real(r8) :: min_chite ! bottom of cohort canopy (m) - real(r8) :: max_chite ! top of cohort canopy (m) - real(r8) :: lai ! summed lai for checking m2 m-2 - real(r8) :: snow_depth_col ! averaged snow over whole columb - integer :: NC ! number of cohorts, for bug fixing. - - !---------------------------------------------------------------------- - - smooth_leaf_distribution = 0 - - associate( & - snow_depth => waterstate_inst%snow_depth_col , & !Input: - frac_sno_eff => waterstate_inst%frac_sno_eff_col , & !Input: - snowdp => waterstate_inst%snowdp_col , & !Output: - - frac_veg_nosno_alb => canopystate_inst%frac_veg_nosno_alb_patch , & !Output: - tlai => canopystate_inst%tlai_patch , & !Output - elai => canopystate_inst%elai_patch , & !Output - tsai => canopystate_inst%tsai_patch , & !Output - esai => canopystate_inst%esai_patch & !Output - ) - - ! Here we are trying to generate a profile of leaf area, indexed by 'z' and by pft - ! We assume that each point in the canopy recieved the light attenuated by the average - ! leaf area index above it, irrespective of PFT identity... - ! Each leaf is defined by how deep in the canopy it is, in terms of LAI units. (FIX(RF,032414), GB) - - currentPatch => currentSite%oldest_patch ! ed patch - p = col%patchi(colindex) ! first patch of the column of interest, for vegetated - ! columns this is the non-veg patch - - do while(associated(currentPatch)) - p = p + 1 ! First CLM/ALM patch is non-veg, increment at loop start - - !Calculate tree and canopy areas. - currentPatch%canopy_area = 0._r8 - currentPatch%canopy_layer_lai(:) = 0._r8 - NC = 0 - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - currentCohort%c_area = c_area(currentCohort) - currentPatch%canopy_area = currentPatch%canopy_area + currentCohort%c_area - NC = NC+1 - currentCohort => currentCohort%taller - enddo - ! if plants take up all the tile, then so does the canopy. - currentPatch%canopy_area = min(currentPatch%canopy_area,currentPatch%area) - - !calculate tree lai and sai. - currentPatch%ncan(:,:) = 0 - currentPatch%nrad(:,:) = 0 - currentPatch%lai = 0._r8 - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - currentCohort%treelai = tree_lai(currentCohort) - currentCohort%treesai = tree_sai(currentCohort) - currentCohort%lai = currentCohort%treelai *currentCohort%c_area/currentPatch%canopy_area - currentCohort%sai = currentCohort%treesai *currentCohort%c_area/currentPatch%canopy_area - !Calculate the LAI plus SAI in each canopy storey. - currentCohort%NV = ceiling((currentCohort%treelai+currentCohort%treesai)/dinc_ed) - - currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft) = & - max(currentPatch%ncan(currentCohort%canopy_layer,currentCohort%pft),currentCohort%NV) - currentPatch%lai = currentPatch%lai +currentCohort%lai - - do L = 1,cp_nclmax-1 - if(currentCohort%canopy_layer == L)then - currentPatch%canopy_layer_lai(L) = currentPatch%canopy_layer_lai(L) + currentCohort%lai + & - currentCohort%sai - endif - enddo - - currentCohort => currentCohort%taller - - enddo !currentCohort - currentPatch%nrad = currentPatch%ncan - - if(smooth_leaf_distribution == 1)then - ! we are going to ignore the concept of canopy layers, and put all of the leaf area into height banded bins. - ! using the same domains as we had before, except that CL always = 1 - currentPatch%tlai_profile = 0._r8 - currentPatch%tsai_profile = 0._r8 - currentPatch%elai_profile = 0._r8 - currentPatch%esai_profile = 0._r8 - - ! this is a crude way of dividing up the bins. Should it be a function of actual maximum height? - dh = 1.0_r8*(HITEMAX/N_HITE_BINS) - do iv = 1,N_HITE_BINS - if (iv == 1) then - minh(iv) = 0.0_r8 - maxh(iv) = dh - else - minh(iv) = (iv-1)*dh - maxh(iv) = (iv)*dh - endif - enddo - - !c = clmpatch%column(currentPatch%clm_pno) - - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - ft = currentCohort%pft - min_chite = currentCohort%hite - currentCohort%hite * EDecophyscon%crown(ft) - max_chite = currentCohort%hite - do iv = 1,N_HITE_BINS - frac_canopy(iv) = 0.0_r8 - ! this layer is in the middle of the canopy - if(max_chite > maxh(iv).and.min_chite < minh(iv))then - frac_canopy(iv)= min(1.0_r8,dh / (currentCohort%hite*EDecophyscon%crown(ft))) - ! this is the layer with the bottom of the canopy in it. - elseif(min_chite < maxh(iv).and.min_chite > minh(iv).and.max_chite > maxh(iv))then - frac_canopy(iv) = (maxh(iv) -min_chite ) / (currentCohort%hite*EDecophyscon%crown(ft)) - ! this is the layer with the top of the canopy in it. - elseif(max_chite > minh(iv).and.max_chite < maxh(iv).and.min_chite < minh(iv))then - frac_canopy(iv) = (max_chite - minh(iv)) / (currentCohort%hite*EDecophyscon%crown(ft)) - elseif(max_chite < maxh(iv).and.min_chite > minh(iv))then !the whole cohort is within this layer. - frac_canopy(iv) = 1.0_r8 - endif - - ! no m2 of leaf per m2 of ground in each height class - currentPatch%tlai_profile(1,ft,iv) = currentPatch%tlai_profile(1,ft,iv) + frac_canopy(iv) * & - currentCohort%lai - currentPatch%tsai_profile(1,ft,iv) = currentPatch%tsai_profile(1,ft,iv) + frac_canopy(iv) * & - currentCohort%sai - - !snow burial -!write(fates_log(), *) 'calc snow' - snow_depth_col = snow_depth(colindex) * frac_sno_eff(colindex) - if(snow_depth_col > maxh(iv))then - fraction_exposed = 0._r8 - endif - if(snow_depth_col < minh(iv))then - fraction_exposed = 1._r8 - endif - if(snow_depth_col>= minh(iv).and.snow_depth_col <= maxh(iv))then !only partly hidden... - fraction_exposed = max(0._r8,(min(1.0_r8,(snow_depth_col-minh(iv))/dh))) - endif - fraction_exposed = 1.0_r8 - ! no m2 of leaf per m2 of ground in each height class - ! FIX(SPM,032414) these should be uncommented this and double check - - if ( DEBUG ) write(fates_log(), *) 'EDCLMLink 1154 ', currentPatch%elai_profile(1,ft,iv) - - currentPatch%elai_profile(1,ft,iv) = currentPatch%tlai_profile(1,ft,iv) * fraction_exposed - currentPatch%esai_profile(1,ft,iv) = currentPatch%tsai_profile(1,ft,iv) * fraction_exposed - - if ( DEBUG ) write(fates_log(), *) 'EDCLMLink 1159 ', currentPatch%elai_profile(1,ft,iv) - - enddo ! (iv) hite bins - - currentCohort => currentCohort%taller - - enddo !currentCohort - - !check - currentPatch%lai = 0._r8 - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - currentPatch%lai = currentPatch%lai +currentCohort%lai - currentCohort => currentCohort%taller - enddo !currentCohort - lai = 0.0_r8 - do ft = 1,numpft_ed - lai = lai+ sum(currentPatch%tlai_profile(1,ft,:)) - enddo - - if(lai > currentPatch%lai)then - write(fates_log(), *) 'ED: problem with lai assignments' - endif - - - else ! smooth leaf distribution - !Go through all cohorts and add their leaf area and canopy area to the accumulators. - currentPatch%tlai_profile = 0._r8 - currentPatch%tsai_profile = 0._r8 - currentPatch%elai_profile = 0._r8 - currentPatch%esai_profile = 0._r8 - currentPatch%layer_height_profile = 0._r8 - currentPatch%canopy_area_profile(:,:,:) = 0._r8 - currentPatch%ncan(:,:) = 0 - currentPatch%nrad(:,:) = 0 - currentCohort => currentPatch%shortest - - do while(associated(currentCohort)) - L = currentCohort%canopy_layer - ft = currentCohort%pft - !Calculate the number of layers of thickness dlai, including the last one. - currentCohort%NV = CEILING((currentCohort%treelai+currentCohort%treesai)/dinc_ed) - !how much of each tree is stem area index? Assuming that there is - if(currentCohort%treelai+currentCohort%treesai > 0._r8)then - fleaf = currentCohort%lai / (currentCohort%lai + currentCohort%sai) - else - fleaf = 0._r8 - write(fates_log(), *) 'ED: no stem or leaf area' ,currentCohort%pft,currentCohort%bl, & - currentCohort%balive,currentCohort%treelai,currentCohort%treesai,currentCohort%dbh, & - currentCohort%n,currentCohort%status_coh - endif - currentPatch%ncan(L,ft) = max(currentPatch%ncan(L,ft),currentCohort%NV) - currentPatch%nrad(L,ft) = currentPatch%ncan(L,ft) !fudge - this needs to be altered for snow burial - if(currentCohort%NV > currentPatch%nrad(L,ft))then - write(fates_log(), *) 'ED: issue with NV',currentCohort%NV,currentCohort%pft,currentCohort%canopy_layer - endif - - ! c = clmpatch%column(currentPatch%clm_pno) - ! INTERF-TODO: REMOVE THIS AT SOME POINT, THIS SANITY CHECK IS NOT NEEDED WHEN THE - ! COLUMNIZATION IS COMPLETE - if( clmpatch%column(currentPatch%clm_pno) .ne. colindex .or. currentPatch%clm_pno .ne. p )then - ! ERROR - write(fates_log(), *) ' clmpatch%column(currentPatch%clm_pno) .ne. colindex .or. currentPatch%clm_pno .ne. p ' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - - !Whole layers. Make a weighted average of the leaf area in each layer before dividing it by the total area. - !fill up layer for whole layers. FIX(RF,032414)- for debugging jan 2012 - do iv = 1,currentCohort%NV-1 - - ! what is the height of this layer? (for snow burial purposes...) - ! pftcon%vertical_canopy_frac(ft))! fudge - this should be pft specific but i cant get it to compile. - layer_top_hite = currentCohort%hite-((iv/currentCohort%NV) * currentCohort%hite * & - EDecophyscon%crown(currentCohort%pft) ) - layer_bottom_hite = currentCohort%hite-(((iv+1)/currentCohort%NV) * currentCohort%hite * & - EDecophyscon%crown(currentCohort%pft)) ! pftcon%vertical_canopy_frac(ft)) - - write(fates_log(), *) 'calc snow 2', colindex, snow_depth(colindex) , frac_sno_eff(colindex) - ! fraction_exposed = 1.0_r8 !default. - - ! snow_depth_col = snow_depth(c) ! * frac_sno_eff(c) - ! if(snow_depth_col > layer_top_hite)then - ! fraction_exposed = 0._r8 - ! endif - ! if(snow_depth_col < layer_bottom_hite)then - ! fraction_exposed = 1._r8 - ! endif - ! if(snow_depth_col>= layer_bottom_hite.and.snow_depth_col <= layer_top_hite)then !only partly hidden... - ! fraction_exposed = max(0._r8,(min(1.0_r8,(snow_depth_col-layer_bottom_hite)/ & - ! (layer_top_hite-layer_bottom_hite )))) - ! endif -fraction_exposed =1.0_r8 - - currentPatch%tlai_profile(L,ft,iv) = currentPatch%tlai_profile(L,ft,iv)+ dinc_ed * fleaf * & - currentCohort%c_area/currentPatch%total_canopy_area - currentPatch%elai_profile(L,ft,iv) = currentPatch%elai_profile(L,ft,iv)+ dinc_ed * fleaf * & - currentCohort%c_area/currentPatch%total_canopy_area * fraction_exposed - - currentPatch%tsai_profile(L,ft,iv) = currentPatch%tsai_profile(L,ft,iv)+ dinc_ed * (1._r8 - fleaf) * & - currentCohort%c_area/currentPatch%total_canopy_area - currentPatch%esai_profile(L,ft,iv) = currentPatch%esai_profile(L,ft,iv)+ dinc_ed * (1._r8 - fleaf) * & - currentCohort%c_area/currentPatch%total_canopy_area * fraction_exposed - - currentPatch%canopy_area_profile(L,ft,iv) = min(1.0_r8,currentPatch%canopy_area_profile(L,ft,iv) + & - currentCohort%c_area/currentPatch%total_canopy_area) - currentPatch%layer_height_profile(L,ft,iv) = currentPatch%layer_height_profile(L,ft,iv) + (dinc_ed * fleaf * & - currentCohort%c_area/currentPatch%total_canopy_area *(layer_top_hite+layer_bottom_hite)/2.0_r8) !average height of layer. - - write(fates_log(), *) 'LHP', currentPatch%layer_height_profile(L,ft,iv) - if ( DEBUG ) write(fates_log(), *) 'EDCLMLink 1246 ', currentPatch%elai_profile(1,ft,iv) - - end do - - !Bottom layer - iv = currentCohort%NV - ! pftcon%vertical_canopy_frac(ft))! fudge - this should be pft specific but i cant get it to compile. - layer_top_hite = currentCohort%hite-((iv/currentCohort%NV) * currentCohort%hite * & - EDecophyscon%crown(currentCohort%pft) ) - ! pftcon%vertical_canopy_frac(ft)) - layer_bottom_hite = currentCohort%hite-(((iv+1)/currentCohort%NV) * currentCohort%hite * & - EDecophyscon%crown(currentCohort%pft)) - -!write(fates_log(), *) 'calc snow 3', snow_depth(c) , frac_sno_eff(c) - fraction_exposed = 1.0_r8 !default. - snow_depth_col = snow_depth(colindex) * frac_sno_eff(colindex) - if(snow_depth_col > layer_top_hite)then - fraction_exposed = 0._r8 - endif - if(snow_depth_col < layer_bottom_hite)then - fraction_exposed = 1._r8 - - endif - if(snow_depth_col>= layer_bottom_hite.and.snow_depth_col <= layer_top_hite)then !only partly hidden... - fraction_exposed = max(0._r8,(min(1.0_r8,(snow_depth_col-layer_bottom_hite)/ & - (layer_top_hite-layer_bottom_hite )))) - endif -fraction_exposed= 1.0_r8 - - - remainder = (currentCohort%treelai + currentCohort%treesai) - (dinc_ed*(currentCohort%NV-1)) - if(remainder > 1.0_r8)then - write(fates_log(), *)'ED: issue with remainder',currentCohort%treelai,currentCohort%treesai,dinc_ed, & - currentCohort%NV - endif - !assumes that fleaf is unchanging FIX(RF,032414) - - currentPatch%tlai_profile(L,ft,iv) = currentPatch%tlai_profile(L,ft,iv)+ remainder * fleaf * & - currentCohort%c_area/currentPatch%total_canopy_area - currentPatch%elai_profile(L,ft,iv) = currentPatch%elai_profile(L,ft,iv) + remainder * fleaf * & - currentCohort%c_area/currentPatch%total_canopy_area * fraction_exposed - !assumes that fleaf is unchanging FIX(RF,032414) - - currentPatch%tsai_profile(L,ft,iv) = currentPatch%tsai_profile(L,ft,iv)+ remainder * & - (1.0_r8-fleaf) * currentCohort%c_area/currentPatch%total_canopy_area - currentPatch%esai_profile(L,ft,iv) = currentPatch%esai_profile(L,ft,iv)+ remainder * & - (1.0_r8-fleaf) * currentCohort%c_area/currentPatch%total_canopy_area * fraction_exposed - - currentPatch%canopy_area_profile(L,ft,iv) = min(1.0_r8,currentPatch%canopy_area_profile(L,ft,iv) + & - currentCohort%c_area/currentPatch%total_canopy_area) - currentPatch%layer_height_profile(L,ft,iv) = currentPatch%layer_height_profile(L,ft,iv) + (remainder * fleaf * & - currentCohort%c_area/currentPatch%total_canopy_area*(layer_top_hite+layer_bottom_hite)/2.0_r8) - write(fates_log(), *) 'LHP', currentPatch%layer_height_profile(L,ft,iv) - if(currentCohort%dbh <= 0._r8.or.currentCohort%n == 0._r8)then - write(fates_log(), *) 'ED: dbh or n is zero in clmedlink', currentCohort%dbh,currentCohort%n - endif - if(currentCohort%pft == 0.or.currentCohort%canopy_trim <= 0._r8)then - write(fates_log(), *) 'ED: PFT or trim is zero in clmedlink',currentCohort%pft,currentCohort%canopy_trim - endif - if(currentCohort%balive <= 0._r8.or.currentCohort%bl < 0._r8)then - write(fates_log(), *) 'ED: balive is zero in clmedlink',currentCohort%balive,currentCohort%bl - endif - - currentCohort => currentCohort%taller - - enddo !cohort - - do L = 1,currentPatch%NCL_p - do ft = 1,numpft_ed - do iv = 1,currentPatch%nrad(L,ft) - !account for total canopy area - currentPatch%tlai_profile(L,ft,iv) = currentPatch%tlai_profile(L,ft,iv) / & - currentPatch%canopy_area_profile(L,ft,iv) - currentPatch%tsai_profile(L,ft,iv) = currentPatch%tsai_profile(L,ft,iv) / & - currentPatch%canopy_area_profile(L,ft,iv) - - if ( DEBUG ) write(fates_log(), *) 'EDCLMLink 1293 ', currentPatch%elai_profile(L,ft,iv) - - currentPatch%elai_profile(L,ft,iv) = currentPatch%elai_profile(L,ft,iv) / & - currentPatch%canopy_area_profile(L,ft,iv) - currentPatch%esai_profile(L,ft,iv) = currentPatch%esai_profile(L,ft,iv) / & - currentPatch%canopy_area_profile(L,ft,iv) - currentPatch%layer_height_profile(L,ft,iv) = currentPatch%layer_height_profile(L,ft,iv) & - /currentPatch%tlai_profile(L,ft,iv) - enddo - - currentPatch%tlai_profile(L,ft,currentPatch%nrad(L,ft)+1: cp_nlevcan) = 0._r8 - currentPatch%tsai_profile(L,ft,currentPatch%nrad(L,ft)+1: cp_nlevcan) = 0._r8 - currentPatch%elai_profile(L,ft,currentPatch%nrad(L,ft)+1: cp_nlevcan) = 0._r8 - currentPatch%esai_profile(L,ft,currentPatch%nrad(L,ft)+1: cp_nlevcan) = 0._r8 - - enddo - enddo - - !what is the resultant leaf area? - - - - tlai_temp = 0._r8 -! elai_temp = 0._r8 -! tsai_temp = 0._r8 -! esai_temp = 0._r8 - - do L = 1,currentPatch%NCL_p - do ft = 1,numpft_ed - - tlai_temp = tlai_temp + sum(currentPatch%canopy_area_profile(L,ft,1:currentPatch%nrad(L,ft)) * & - currentPatch%tlai_profile(L,ft,1:currentPatch%nrad(L,ft))) - ! elai_temp = elai_temp + sum(currentPatch%canopy_area_profile(L,ft,1:currentPatch%nrad(L,ft)) * & - ! currentPatch%elai_profile(L,ft,1:currentPatch%nrad(L,ft))) - ! tsai_temp = tsai_temp + sum(currentPatch%canopy_area_profile(L,ft,1:currentPatch%nrad(L,ft)) * & - ! currentPatch%tsai_profile(L,ft,1:currentPatch%nrad(L,ft))) - ! esai_temp = esai_temp + sum(currentPatch%canopy_area_profile(L,ft,1:currentPatch%nrad(L,ft)) * & - ! currentPatch%esai_profile(L,ft,1:currentPatch%nrad(L,ft))) - enddo - enddo - - ! This should not had changed -! p = currentPatch%clm_pno - if(abs(tlai(p)-tlai_temp) > 0.0001_r8) then - - write(fates_log(), *) 'ED: error with tlai calcs',& - NC,colindex, abs(tlai(p)-tlai_temp), tlai_temp,tlai(p) - - do L = 1,currentPatch%NCL_p - write(fates_log(), *) 'ED: carea profile',L,currentPatch%canopy_area_profile(L,1,1:currentPatch%nrad(L,1)) - write(fates_log(), *) 'ED: tlai profile',L,currentPatch%tlai_profile(L,1,1:currentPatch%nrad(L,1)) - end do - - endif - - elai(p) = calc_areaindex(currentPatch,'elai') - tlai(p) = calc_areaindex(currentPatch,'tlai') - esai(p) = calc_areaindex(currentPatch,'esai') - tsai(p) = calc_areaindex(currentPatch,'tsai') - - ! Fraction of vegetation free of snow. What does this do? Is it right? - if ((elai(p) + esai(p)) > 0._r8) then - frac_veg_nosno_alb(p) = 1.0_r8 - else - frac_veg_nosno_alb(p) = 0.0_r8 - end if - - currentPatch%nrad = currentPatch%ncan - do L = 1,currentPatch%NCL_p - do ft = 1,numpft_ed - if(currentPatch%nrad(L,ft) > 30)then - write(fates_log(), *) 'ED: issue w/ nrad' - endif - currentPatch%present(L,ft) = 0 - do iv = 1, currentPatch%nrad(L,ft); - if(currentPatch%canopy_area_profile(L,ft,iv) > 0._r8)then - currentPatch%present(L,ft) = 1 - endif - end do !iv - enddo !ft - - if ( L == 1 .and. abs(sum(currentPatch%canopy_area_profile(1,1:numpft_ed,1))) < 0.99999 & - .and. currentPatch%NCL_p > 1 ) then - write(fates_log(), *) 'ED: canopy area too small',sum(currentPatch%canopy_area_profile(1,1:numpft_ed,1)) - write(fates_log(), *) 'ED: cohort areas', currentPatch%canopy_area_profile(1,1:numpft_ed,:) - endif - - if (L == 1 .and. currentPatch%NCL_p > 1 .and. & - abs(sum(currentPatch%canopy_area_profile(1,1:numpft_ed,1))) < 0.99999) then - write(fates_log(), *) 'ED: not enough area in the top canopy', & - sum(currentPatch%canopy_area_profile(L,1:numpft_ed,1)), & - currentPatch%canopy_area_profile(L,1:numpft_ed,1) - endif - - if(abs(sum(currentPatch%canopy_area_profile(L,1:numpft_ed,1))) > 1.00001)then - write(fates_log(), *) 'ED: canopy-area-profile wrong', & - sum(currentPatch%canopy_area_profile(L,1:numpft_ed,1)), & - colindex, currentPatch%patchno, L - write(fates_log(), *) 'ED: areas',currentPatch%canopy_area_profile(L,1:2,1),currentPatch%patchno - - currentCohort => currentPatch%shortest - - do while(associated(currentCohort)) - - if(currentCohort%canopy_layer==1)then - write(fates_log(), *) 'ED: cohorts',currentCohort%dbh,currentCohort%c_area, & - currentPatch%total_canopy_area,currentPatch%area,currentPatch%canopy_area - write(fates_log(), *) 'ED: fracarea', currentCohort%pft, & - currentCohort%c_area/currentPatch%total_canopy_area - endif - - currentCohort => currentCohort%taller - - enddo !currentCohort - endif - enddo ! loop over L - - do L = 1,currentPatch%NCL_p - do ft = 1,numpft_ed - if(currentPatch%present(L,FT) > 1)then - write(fates_log(), *) 'ED: present issue',currentPatch%clm_pno,L,ft,currentPatch%present(L,FT) - currentPatch%present(L,ft) = 1 - endif - enddo - enddo - - endif !leaf distribution - - currentPatch => currentPatch%younger - - enddo !patch - - end associate - - end subroutine ed_clm_leaf_area_profile - - ! ===================================================================================== - - subroutine SummarizeProductivityFluxes(this, bounds, nsites, sites, fcolumn) - - ! Summarize the fast production inputs from fluxes per ED individual to fluxes per CLM patch and column - ! Must be called between calculation of productivity fluxes and daily ED calls - ! (since daily ED calls reorganize the patch / cohort structure) - - ! Written By Charlie Koven, April 2016 - ! - ! !USES: - use LandunitType , only : lun - use landunit_varcon , only : istsoil - !use subgridAveMod , only : p2c - ! - implicit none - ! - ! !ARGUMENTS - class(ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(in), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - ! - ! !LOCAL VARIABLES: - real(r8) :: dt ! radiation time step (seconds) - integer :: c, fc, l, p, s - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort - integer :: firstsoilpatch(bounds%begg:bounds%endg) ! the first patch in this gridcell that is soil and thus bare... - real(r8) :: n_density ! individual of cohort per m2. - real(r8) :: n_perm2 ! individuals per m2 of the whole column - - associate(& - npp_col => this%npp_col, & - npp => this%npp_patch, & - gpp => this%gpp_patch, & - ar => this%ar_patch, & - growth_resp => this%growth_resp_patch, & - maint_resp => this%maint_resp_patch & - ) - - ! set time steps - dt = real( get_step_size(), r8 ) - - ! zero variables first - ! column variables - do c = bounds%begc,bounds%endc - ! summary flux variables - npp_col(c) = 0._r8 - end do - - ! patch variables - do p = bounds%begp,bounds%endp - npp(p) = 0._r8 - gpp(p) = 0._r8 - ar(p) = 0._r8 - growth_resp(p) = 0._r8 - maint_resp(p) = 0._r8 - end do - - ! retrieve the first soil patch associated with each gridcell. - ! make sure we only get the first patch value for places which have soil. - - do s = 1,nsites - - c = fcolumn(s) - p = col%patchi(c) - - currentPatch => sites(s)%oldest_patch - do while(associated(currentPatch)) - - p = p + 1 - - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - - if ((currentPatch%area .gt. 0._r8) .and. (currentPatch%total_canopy_area .gt. 0._r8)) then - - ! for quantities that are at the CLM patch level, because of the way that CLM patches are weighted for radiative purposes - ! this # density needs to be over either ED patch canopy area or ED patch total area, whichever is less - n_density = currentCohort%n/min(currentPatch%area,currentPatch%total_canopy_area) - - ! for quantities that are natively at column level or higher, calculate plant density using whole area (for grid cell averages) - n_perm2 = currentCohort%n/AREA - - else - n_density = 0.0_r8 - n_perm2 = 0.0_r8 - endif - - if ( .not. currentCohort%isnew ) then - - ! map ed cohort-level fluxes to clm patch fluxes - npp(p) = npp(p) + currentCohort%npp_tstep * 1.e3_r8 * n_density / dt - gpp(p) = gpp(p) + currentCohort%gpp_tstep * 1.e3_r8 * n_density / dt - ar(p) = ar(p) + currentCohort%resp_tstep * 1.e3_r8 * n_density / dt - growth_resp(p) = growth_resp(p) + currentCohort%resp_g * 1.e3_r8 * n_density / dt - maint_resp(p) = maint_resp(p) + currentCohort%resp_m * 1.e3_r8 * n_density / dt - - ! map ed cohort-level npp fluxes to clm column fluxes - npp_col(c) = npp_col(c) + currentCohort%npp_tstep * n_perm2 * 1.e3_r8 /dt - - endif - - currentCohort => currentCohort%shorter - enddo !currentCohort - currentPatch => currentPatch%younger - end do !currentPatch - - end do ! site loop - - ! leaving this as a comment here. it should produce same answer for npp_col as above, - ! so it may be useful to try as a check to make sure machinery is working proerly - !call p2c(bounds,num_soilc, filter_soilc, npp(bounds%begp:bounds%endp), npp_col(bounds%begc:bounds%endc)) - - end associate -end subroutine SummarizeProductivityFluxes - - !------------------------------------------------------------------------ - subroutine SummarizeNetFluxes(this, bounds, num_soilc, filter_soilc, & - nsites, sites, fcolumn, soilbiogeochem_carbonflux_inst, & - soilbiogeochem_carbonstate_inst) - - ! Summarize the combined production and decomposition fluxes into net fluxes - ! This is done on the fast timestep, and to be called after both daily ED calls and fast BGC calls - ! Does not include summarization of fast-timestsp productivity calls because these must be summarized prior to daily ED calls - ! - ! Written by Charlie Koven, Feb 2016 - ! - ! !USES: - use LandunitType , only : lun - use landunit_varcon , only : istsoil - ! - implicit none - ! - ! !ARGUMENTS - class(ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - integer , intent(in) :: nsites - type(ed_site_type) , intent(in), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst - type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst - ! - ! !LOCAL VARIABLES: - real(r8) :: dt ! radiation time step (seconds) - integer :: c, s, cc, fc, l, p, pp - type(ed_site_type), pointer :: cs - type (ed_patch_type) , pointer :: currentPatch - type (ed_cohort_type) , pointer :: currentCohort -! integer :: firstsoilpatch(bounds%begg:bounds%endg) ! the first patch in this gridcell that is soil and thus bare... - real(r8) :: n_perm2 ! individuals per m2 of the whole column - - associate(& - hr => soilbiogeochem_carbonflux_inst%hr_col, & ! (gC/m2/s) total heterotrophic respiration - totsomc => soilbiogeochem_carbonstate_inst%totsomc_col, & ! (gC/m2) total soil organic matter carbon - totlitc => soilbiogeochem_carbonstate_inst%totlitc_col, & ! (gC/m2) total litter carbon in BGC pools - npp_col => this%npp_col, & - nep => this%nep_col, & - fire_c_to_atm => this%fire_c_to_atm_col, & - nbp => this%nbp_col, & - totecosysc => this%totecosysc_col, & - totedc => this%totedc_col, & - totbgcc => this%totbgcc_col, & - biomass_stock => this%biomass_stock_col, & ! total biomass in gC / m2 - ed_litter_stock => this%ed_litter_stock_col, & ! ED litter in gC / m2 - cwd_stock => this%cwd_stock_col, & ! total CWD in gC / m2 - seed_stock => this%seed_stock_col, & ! total seed mass in gC / m2 - ed_to_bgc_this_edts => this%ed_to_bgc_this_edts_col, & - ed_to_bgc_last_edts => this%ed_to_bgc_last_edts_col, & - seed_rain_flux => this%seed_rain_flux_col & - ) - - ! set time steps - dt = real( get_step_size(), r8 ) - - ! zero variables first - ! column variables - do c = bounds%begc,bounds%endc - ! summary flux variables - fire_c_to_atm(c) = 0._r8 - - ! summary stock variables - ed_litter_stock(c) = 0._r8 - cwd_stock(c) = 0._r8 - seed_stock(c) = 0._r8 - biomass_stock(c) = 0._r8 - end do - - do s = 1, nsites - - c = fcolumn(s) - p = col%patchi(c) - - ! map ed site-level fire fluxes to clm column fluxes - fire_c_to_atm(c) = sites(s)%total_burn_flux_to_atm / ( AREA * SHR_CONST_CDAY * 1.e3_r8) - - currentPatch => sites(s)%oldest_patch - do while(associated(currentPatch)) - - p = p + 1 - - ! map litter, CWD, and seed pools to column level - cwd_stock(c) = cwd_stock(c) + (currentPatch%area / AREA) * (sum(currentPatch%cwd_ag)+ & - sum(currentPatch%cwd_bg)) * 1.e3_r8 - ed_litter_stock(c) = ed_litter_stock(c) + (currentPatch%area / AREA) * & - (sum(currentPatch%leaf_litter)+sum(currentPatch%root_litter)) * 1.e3_r8 - seed_stock(c) = seed_stock(c) + (currentPatch%area / AREA) * sum(currentPatch%seed_bank) * 1.e3_r8 - - currentCohort => currentPatch%tallest - do while(associated(currentCohort)) - - ! for quantities that are natively at column level or higher, calculate plant density using whole area (for grid cell averages) - n_perm2 = currentCohort%n/AREA - - ! map biomass pools to column level - biomass_stock(c) = biomass_stock(c) + (currentCohort%bdead + currentCohort%balive + & - currentCohort%bstore) * n_perm2 * 1.e3_r8 - - currentCohort => currentCohort%shorter - enddo !currentCohort - currentPatch => currentPatch%younger - end do ! patch loop - end do ! site loop - - ! calculate NEP and NBP fluxes. ????? - do fc = 1,num_soilc - c = filter_soilc(fc) - nep(c) = npp_col(c) - hr(c) - nbp(c) = npp_col(c) - ( hr(c) + fire_c_to_atm(c) ) - end do - - ! calculate total stocks - do fc = 1,num_soilc - c = filter_soilc(fc) - - totedc(c) = ed_litter_stock(c) + cwd_stock(c) + seed_stock(c) + biomass_stock(c) ! ED stocks - totbgcc(c) = totsomc(c) + totlitc(c) ! BGC stocks - totecosysc(c) = totedc(c) + totbgcc(c) - - end do - - ! in ED timesteps, because of offset between when ED and BGC reconcile the gain and loss of litterfall carbon, - ! (i.e. ED reconciles it instantly, while BGC reconciles it incrementally over the subsequent day) - ! calculate the total ED -> BGC flux and keep track of the last day's info for balance checking purposes - if ( is_beg_curr_day() ) then - ! - do s = 1,nsites - c = fcolumn(s) - ed_to_bgc_last_edts(c) = ed_to_bgc_this_edts(c) - end do - ! - do s = 1,nsites - c = fcolumn(s) - ed_to_bgc_this_edts(c) = 0._r8 - seed_rain_flux(c) = 0._r8 - end do - ! - do s = 1,nsites - c = fcolumn(s) - - currentPatch => sites(s)%oldest_patch - do while(associated(currentPatch)) - ! - ed_to_bgc_this_edts(c) = ed_to_bgc_this_edts(c) + & - (sum(currentPatch%CWD_AG_out) + sum(currentPatch%CWD_BG_out) + & - sum(currentPatch%seed_decay) + sum(currentPatch%leaf_litter_out) + & - sum(currentPatch%root_litter_out)) * & - ( currentPatch%area/AREA ) * 1.e3_r8 / ( 365.0_r8*SHR_CONST_CDAY ) - ! - seed_rain_flux(c) = seed_rain_flux(c) + sum(currentPatch%seed_rain_flux) * 1.e3_r8 / ( 365.0_r8*SHR_CONST_CDAY ) - ! - currentPatch => currentPatch%younger - end do !currentPatch - end do - endif - - end associate - - end subroutine SummarizeNetFluxes - - - subroutine ED_BGC_Carbon_Balancecheck(this, bounds, num_soilc, filter_soilc, soilbiogeochem_carbonflux_inst) - - ! Integrate in time the fluxes into and out of the ecosystem, and compare these on a daily timestep - ! to the chagne in carbon stocks of the ecosystem - ! - ! Written by Charlie Koven, Feb 2016 - ! - ! !USES: - ! - implicit none - ! - ! !ARGUMENTS - class(ed_clm_type) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_soilc ! number of soil columns in filter - integer , intent(in) :: filter_soilc(:) ! filter for soil columns - type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst - ! - ! !LOCAL VARIABLES: - real(r8) :: dtime ! land model time step (sec) - integer :: nstep ! model timestep - real(r8) :: nbp_integrated(bounds%begc:bounds%endc) ! total net biome production integrated - real(r8) :: error_total(bounds%begc:bounds%endc) - real(r8) :: error_ed(bounds%begc:bounds%endc) - real(r8) :: error_bgc(bounds%begc:bounds%endc) - real(r8) :: error_tolerance = 1.e-6_r8 - real(r8) :: max_error_ed - real(r8) :: max_error_bgc - real(r8) :: max_error_total - integer :: fc,c - - associate(& - nep => this%nep_col, & - nep_timeintegrated => this%nep_timeintegrated_col, & - hr => soilbiogeochem_carbonflux_inst%hr_col, & - hr_timeintegrated => this%hr_timeintegrated_col, & - npp_col => this%npp_col, & - npp_timeintegrated => this%npp_timeintegrated_col, & - fire_c_to_atm => this%fire_c_to_atm_col, & - totecosysc_old => this%totecosysc_old_col, & - totecosysc => this%totecosysc_col, & - totedc_old => this%totedc_old_col, & - totedc => this%totedc_col, & - totbgcc_old => this%totbgcc_old_col, & - totbgcc => this%totbgcc_col, & - ed_to_bgc_this_edts => this%ed_to_bgc_this_edts_col, & - ed_to_bgc_last_edts => this%ed_to_bgc_last_edts_col, & - seed_rain_flux => this%seed_rain_flux_col, & - cbalance_error_ed => this%cbalance_error_ed_col, & - cbalance_error_bgc => this%cbalance_error_bgc_col, & - cbalance_error_total=> this%cbalance_error_total_col & - ) - - dtime = get_step_size() - nstep = get_nstep() - - if (nstep .le. 1) then - ! when starting up the model, initialize the integrator variables - do fc = 1,num_soilc - c = filter_soilc(fc) - totecosysc_old(c) = totecosysc(c) - totedc_old(c) = totedc(c) - totbgcc_old(c) = totbgcc(c) - nep_timeintegrated(c) = 0._r8 - hr_timeintegrated(c) = 0._r8 - npp_timeintegrated(c) = 0._r8 - ! - ! also initialize the ed-BGC flux variables - ed_to_bgc_this_edts(c) = 0._r8 - ed_to_bgc_last_edts(c) = 0._r8 - ! - cbalance_error_ed(c) = 0._r8 - cbalance_error_bgc(c) = 0._r8 - cbalance_error_total(c) = 0._r8 - end do - endif - - if ( .not. is_beg_curr_day() ) then - ! on CLM (half-hourly) timesteps, integrate the NEP fluxes - do fc = 1,num_soilc - c = filter_soilc(fc) - nep_timeintegrated(c) = nep_timeintegrated(c) + nep(c) * dtime - hr_timeintegrated(c) = hr_timeintegrated(c) + hr(c) * dtime - npp_timeintegrated(c) = npp_timeintegrated(c) + npp_col(c) * dtime - end do - else - ! on ED (daily) timesteps, first integrate the NEP fluxes and add in the daily disturbance flux - do fc = 1,num_soilc - c = filter_soilc(fc) - nep_timeintegrated(c) = nep_timeintegrated(c) + nep(c) * dtime - hr_timeintegrated(c) = hr_timeintegrated(c) + hr(c) * dtime - npp_timeintegrated(c) = npp_timeintegrated(c) + npp_col(c) * dtime - nbp_integrated(c) = nep_timeintegrated(c) - fire_c_to_atm(c) * SHR_CONST_CDAY + seed_rain_flux(c)* SHR_CONST_CDAY - end do - - ! next compare the change in carbon and calculate the error - do fc = 1,num_soilc - c = filter_soilc(fc) - error_ed(c) = totedc(c) - totedc_old(c) - & - (npp_timeintegrated(c) + seed_rain_flux(c) * SHR_CONST_CDAY - & - ed_to_bgc_this_edts(c) * SHR_CONST_CDAY - & - fire_c_to_atm(c) * SHR_CONST_CDAY) - - error_bgc(c) = totbgcc(c) - totbgcc_old(c) - & - (ed_to_bgc_last_edts(c) * SHR_CONST_CDAY - hr_timeintegrated(c)) - - error_total(c) = totecosysc(c) - totecosysc_old(c) - & - (nbp_integrated(c) + ed_to_bgc_last_edts(c) * SHR_CONST_CDAY - & - ed_to_bgc_this_edts(c)* SHR_CONST_CDAY) - end do - ! - ! put in consistent flux units and send to history so we can keep track of the errors - do fc = 1,num_soilc - c = filter_soilc(fc) - cbalance_error_ed(c) = error_ed(c) / SHR_CONST_CDAY - cbalance_error_bgc(c) = error_bgc(c) / SHR_CONST_CDAY - cbalance_error_total(c) = error_total(c) / SHR_CONST_CDAY - end do - - ! for now, rather than crashing the model, lets just report the largest error to see what we're up against - ! - ! RETURN TO THIS LATER AND ADD A CRASHER IF BALANCE EXCEEDS THRESHOLD - ! - ! max_error_total = 0._r8 - ! do fc = 1,num_soilc - ! c = filter_soilc(fc) - ! if (abs(error_total(c)) .gt. max_error_total) then - ! max_error_ed = abs(error_ed(c)) - ! max_error_bgc = abs(error_bgc(c)) - ! max_error_total = abs(error_total(c)) - ! endif - ! end do - ! write(iulog,*) 'ED_BGC_Carbon_Balancecheck: max_error_ed, max_error_bgc, max_error_total (gC / m2 / day): ', max_error_ed, max_error_bgc, max_error_total - - ! reset the C stock and flux integrators - do fc = 1,num_soilc - c = filter_soilc(fc) - totecosysc_old(c) = totecosysc(c) - totedc_old(c) = totedc(c) - totbgcc_old(c) = totbgcc(c) - nep_timeintegrated(c) = 0._r8 - npp_timeintegrated(c) = 0._r8 - hr_timeintegrated(c) = 0._r8 - end do - - endif - - end associate - - end subroutine ED_BGC_Carbon_Balancecheck - -end module EDCLMLinkMod diff --git a/src/ED/main/EDEcophysConType.F90 b/src/ED/main/EDEcophysConType.F90 deleted file mode 100644 index e305510f0a..0000000000 --- a/src/ED/main/EDEcophysConType.F90 +++ /dev/null @@ -1,110 +0,0 @@ -module EDEcophysConType - - !---------------------------------------------------- - ! ED ecophysiological constants - !---------------------------------------------------- - ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) - ! - implicit none - save - private - ! - ! !PUBLIC MEMBER FUNCTIONS: - public :: EDecophysconInit - ! - ! !PUBLIC TYPES: - type, public :: EDecophyscon_type - real(r8), pointer :: max_dbh (:) ! maximum dbh at which height growth ceases... - real(r8), pointer :: freezetol (:) ! minimum temperature tolerance... - real(r8), pointer :: wood_density (:) ! wood density g cm^-3 ... - real(r8), pointer :: alpha_stem (:) ! live stem turnover rate. y-1 - real(r8), pointer :: hgt_min (:) ! sapling height m - real(r8), pointer :: cushion (:) ! labile carbon storage target as multiple of leaf pool. - real(r8), pointer :: leaf_stor_priority (:) ! leaf turnover vs labile carbon use prioritisation. ! (1=lose leaves, 0=use store). - real(r8), pointer :: leafwatermax (:) ! amount of water allowed on leaf surfaces - real(r8), pointer :: rootresist (:) - real(r8), pointer :: soilbeta (:) - real(r8), pointer :: crown (:) ! fraction of the height of the plant that is occupied by crown. For fire model. - real(r8), pointer :: bark_scaler (:) ! scaler from dbh to bark thickness. For fire model. - real(r8), pointer :: crown_kill (:) ! scaler on fire death. For fire model. - real(r8), pointer :: initd (:) ! initial seedling density - real(r8), pointer :: sd_mort (:) ! rate of death of seeds produced from reproduction. - real(r8), pointer :: seed_rain (:) ! seeds that come from outside the gridbox. - real(r8), pointer :: BB_slope (:) ! ball berry slope parameter - real(r8), pointer :: root_long (:) ! root longevity (yrs) - real(r8), pointer :: clone_alloc (:) ! fraction of carbon balance allocated to clonal reproduction. - real(r8), pointer :: seed_alloc (:) ! fraction of carbon balance allocated to seeds. - real(r8), pointer :: sapwood_ratio (:) ! amount of sapwood per unit leaf carbon and m height - end type EDecophyscon_type - - type(EDecophyscon_type), public :: EDecophyscon ! ED ecophysiological constants structure - !------------------------------------------------------------------------ - -contains - - !------------------------------------------------------------------------ - subroutine EDecophysconInit(EDpftvarcon_inst, numpft) - ! - ! !USES: - use EDPftvarcon, only : EDPftvarcon_type - ! - ! !ARGUMENTS: - type(EDpftVarCon_type) , intent(in) :: EDpftvarcon_inst - integer , intent(in) :: numpft - ! - ! !LOCAL VARIABLES: - integer :: m, ib - !------------------------------------------------------------------------ - - allocate( EDecophyscon%max_dbh (0:numpft)); EDecophyscon%max_dbh (:) = nan - allocate( EDecophyscon%freezetol (0:numpft)); EDecophyscon%freezetol (:) = nan - allocate( EDecophyscon%wood_density (0:numpft)); EDecophyscon%wood_density (:) = nan - allocate( EDecophyscon%alpha_stem (0:numpft)); EDecophyscon%alpha_stem (:) = nan - allocate( EDecophyscon%hgt_min (0:numpft)); EDecophyscon%hgt_min (:) = nan - allocate( EDecophyscon%cushion (0:numpft)); EDecophyscon%cushion (:) = nan - allocate( EDecophyscon%leaf_stor_priority (0:numpft)); EDecophyscon%leaf_stor_priority (:) = nan - allocate( EDecophyscon%leafwatermax (0:numpft)); EDecophyscon%leafwatermax (:) = nan - allocate( EDecophyscon%rootresist (0:numpft)); EDecophyscon%rootresist (:) = nan - allocate( EDecophyscon%soilbeta (0:numpft)); EDecophyscon%soilbeta (:) = nan - allocate( EDecophyscon%crown (0:numpft)); EDecophyscon%crown (:) = nan - allocate( EDecophyscon%bark_scaler (0:numpft)); EDecophyscon%bark_scaler (:) = nan - allocate( EDecophyscon%crown_kill (0:numpft)); EDecophyscon%crown_kill (:) = nan - allocate( EDecophyscon%initd (0:numpft)); EDecophyscon%initd (:) = nan - allocate( EDecophyscon%sd_mort (0:numpft)); EDecophyscon%sd_mort (:) = nan - allocate( EDecophyscon%seed_rain (0:numpft)); EDecophyscon%seed_rain (:) = nan - allocate( EDecophyscon%BB_slope (0:numpft)); EDecophyscon%BB_slope (:) = nan - allocate( EDecophyscon%root_long (0:numpft)); EDecophyscon%root_long (:) = nan - allocate( EDecophyscon%seed_alloc (0:numpft)); EDecophyscon%seed_alloc (:) = nan - allocate( EDecophyscon%clone_alloc (0:numpft)); EDecophyscon%clone_alloc (:) = nan - allocate( EDecophyscon%sapwood_ratio (0:numpft)); EDecophyscon%sapwood_ratio (:) = nan - - do m = 0,numpft - EDecophyscon%max_dbh(m) = EDPftvarcon_inst%max_dbh(m) - EDecophyscon%freezetol(m) = EDPftvarcon_inst%freezetol(m) - EDecophyscon%wood_density(m) = EDPftvarcon_inst%wood_density(m) - EDecophyscon%alpha_stem(m) = EDPftvarcon_inst%alpha_stem(m) - EDecophyscon%hgt_min(m) = EDPftvarcon_inst%hgt_min(m) - EDecophyscon%cushion(m) = EDPftvarcon_inst%cushion(m) - EDecophyscon%leaf_stor_priority(m) = EDPftvarcon_inst%leaf_stor_priority(m) - EDecophyscon%leafwatermax(m) = EDPftvarcon_inst%leafwatermax(m) - EDecophyscon%rootresist(m) = EDPftvarcon_inst%rootresist(m) - EDecophyscon%soilbeta(m) = EDPftvarcon_inst%soilbeta(m) - EDecophyscon%crown(m) = EDPftvarcon_inst%crown(m) - EDecophyscon%bark_scaler(m) = EDPftvarcon_inst%bark_scaler(m) - EDecophyscon%crown_kill(m) = EDPftvarcon_inst%crown_kill(m) - EDecophyscon%initd(m) = EDPftvarcon_inst%initd(m) - EDecophyscon%sd_mort(m) = EDPftvarcon_inst%sd_mort(m) - EDecophyscon%seed_rain(m) = EDPftvarcon_inst%seed_rain(m) - EDecophyscon%bb_slope(m) = EDPftvarcon_inst%bb_slope(m) - EDecophyscon%root_long(m) = EDPftvarcon_inst%root_long(m) - EDecophyscon%seed_alloc(m) = EDPftvarcon_inst%seed_alloc(m) - EDecophyscon%clone_alloc(m) = EDPftvarcon_inst%clone_alloc(m) - EDecophyscon%sapwood_ratio(m) = EDPftvarcon_inst%sapwood_ratio(m) - end do - - end subroutine EDecophysconInit - -end module EDEcophysConType diff --git a/src/ED/main/EDInitMod.F90 b/src/ED/main/EDInitMod.F90 deleted file mode 100755 index dd263295f1..0000000000 --- a/src/ED/main/EDInitMod.F90 +++ /dev/null @@ -1,297 +0,0 @@ -module EDInitMod - - ! ============================================================================ - ! Contains all modules to set up the ED structure. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8; - use spmdMod , only : masterproc - use decompMod , only : bounds_type - use abortutils , only : endrun - use EDTypesMod , only : cp_nclmax - use clm_varctl , only : iulog, use_ed_spit_fire - use clm_time_manager , only : is_restart - use CanopyStateType , only : canopystate_type - use WaterStateType , only : waterstate_type - use GridcellType , only : grc - use pftconMod , only : pftcon - use EDEcophysConType , only : EDecophyscon - use EDGrowthFunctionsMod , only : bdead, bleaf, dbh - use EDCohortDynamicsMod , only : create_cohort, fuse_cohorts, sort_cohorts - use EDPatchDynamicsMod , only : create_patch - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type, area - use EDTypesMod , only : cohorts_per_col, ncwd, numpft_ed, udata - use EDCLMLinkMod , only : ed_clm_type - - implicit none - private - - logical :: DEBUG = .false. - - public :: zero_site - public :: init_patches - public :: set_site_properties - - private :: init_cohorts - ! ============================================================================ - -contains - - ! ============================================================================ - - subroutine zero_site( site_in ) - ! - ! !DESCRIPTION: - ! - ! !USES: - use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) - ! - ! !ARGUMENTS - type(ed_site_type), intent(inout) :: site_in - ! - ! !LOCAL VARIABLES: - !---------------------------------------------------------------------- - - site_in%oldest_patch => null() ! pointer to oldest patch at the site - site_in%youngest_patch => null() ! pointer to yngest patch at the site - - ! INDICES - site_in%lat = nan - site_in%lon = nan - - ! DISTURBANCE - site_in%disturbance_rate = 0._r8 ! site level disturbance rates from mortality and fire. - site_in%dist_type = 0 ! disturbance dist_type id. - - ! PHENOLOGY - site_in%status = 0 ! are leaves in this pixel on or off? - site_in%dstatus = 0 - site_in%ED_GDD_site = nan ! growing degree days - site_in%ncd = nan ! no chilling days - site_in%last_n_days(:) = 999 ! record of last 10 days temperature for senescence model. - site_in%leafondate = 999 ! doy of leaf on - site_in%leafoffdate = 999 ! doy of leaf off - site_in%dleafondate = 999 ! doy of leaf on drought - site_in%dleafoffdate = 999 ! doy of leaf on drought - site_in%water_memory(:) = nan - - ! FIRE - site_in%acc_ni = 0.0_r8 ! daily nesterov index accumulating over time. time unlimited theoretically. - site_in%frac_burnt = 0.0_r8 ! burn area read in from external file - - end subroutine zero_site - - ! ============================================================================ - subroutine set_site_properties( nsites, sites) - ! - ! !DESCRIPTION: - ! - ! !USES: - ! - ! !ARGUMENTS - - integer, intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - ! - ! !LOCAL VARIABLES: - integer :: s - real(r8) :: leafon - real(r8) :: leafoff - real(r8) :: stat - real(r8) :: NCD - real(r8) :: GDD - real(r8) :: dstat - real(r8) :: acc_NI - real(r8) :: watermem - integer :: dleafoff - integer :: dleafon - !---------------------------------------------------------------------- - - if ( .not. is_restart() ) then - !initial guess numbers for site condition. - NCD = 0.0_r8 - GDD = 30.0_r8 - leafon = 100.0_r8 - leafoff = 300.0_r8 - stat = 2 - acc_NI = 0.0_r8 - dstat = 2 - dleafoff = 300 - dleafon = 100 - watermem = 0.5_r8 - - else ! assignements for restarts - - NCD = 1.0_r8 ! NCD should be 1 on restart - GDD = 0.0_r8 - leafon = 0.0_r8 - leafoff = 0.0_r8 - stat = 1 - acc_NI = 0.0_r8 - dstat = 2 - dleafoff = 300 - dleafon = 100 - watermem = 0.5_r8 - - endif - - do s = 1,nsites - sites(s)%ncd = NCD - sites(s)%leafondate = leafon - sites(s)%leafoffdate = leafoff - sites(s)%dleafoffdate = dleafoff - sites(s)%dleafondate = dleafon - sites(s)%ED_GDD_site = GDD - - if ( .not. is_restart() ) then - sites(s)%water_memory(1:10) = watermem - end if - - sites(s)%status = stat - !start off with leaves off to initialise - sites(s)%dstatus= dstat - - sites(s)%acc_NI = acc_NI - sites(s)%frac_burnt = 0.0_r8 - sites(s)%old_stock = 0.0_r8 - end do - - return - end subroutine set_site_properties - - ! ============================================================================ - subroutine init_patches( nsites, sites) - ! - ! !DESCRIPTION: - !initialize patches on new ground - ! - ! !USES: - use EDParamsMod , only : ED_val_maxspread - ! - ! !ARGUMENTS - integer, intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - ! - ! !LOCAL VARIABLES: - integer :: s - real(r8) :: cwd_ag_local(ncwd) - real(r8) :: cwd_bg_local(ncwd) - real(r8) :: spread_local(cp_nclmax) - real(r8) :: leaf_litter_local(numpft_ed) - real(r8) :: root_litter_local(numpft_ed) - real(r8) :: seed_bank_local(numpft_ed) - real(r8) :: age !notional age of this patch - type(ed_patch_type), pointer :: newp - !---------------------------------------------------------------------- - - cwd_ag_local(:) = 0.0_r8 !ED_val_init_litter -- arbitrary value for litter pools. kgC m-2 - cwd_bg_local(:) = 0.0_r8 !ED_val_init_litter - leaf_litter_local(:) = 0.0_r8 - root_litter_local(:) = 0.0_r8 - spread_local(:) = ED_val_maxspread - seed_bank_local(:) = 0.0_r8 !Note (mv,11-04-2014, this is a bug fix - this line was missing) - age = 0.0_r8 - - !FIX(SPM,032414) clean this up...inits out of this loop - do s = 1, nsites - - allocate(newp) - - newp%patchno = 1 - newp%younger => null() - newp%older => null() - - sites(s)%youngest_patch => newp - sites(s)%youngest_patch => newp - sites(s)%oldest_patch => newp - - ! make new patch... - call create_patch(sites(s), newp, age, AREA, & - spread_local, cwd_ag_local, cwd_bg_local, leaf_litter_local, & - root_litter_local, seed_bank_local) - - call init_cohorts(newp) - - enddo - - end subroutine init_patches - - ! ============================================================================ - subroutine init_cohorts( patch_in ) - ! - ! !DESCRIPTION: - ! initialize new cohorts on bare ground - ! - ! !USES: - ! - ! !ARGUMENTS - type(ed_patch_type), intent(inout), pointer :: patch_in - ! - ! !LOCAL VARIABLES: - type(ed_cohort_type),pointer :: temp_cohort - integer :: cstatus - integer :: pft - !---------------------------------------------------------------------- - - patch_in%tallest => null() - patch_in%shortest => null() - - do pft = 1,numpft_ed !FIX(RF,032414) - turning off veg dynamics - - if(EDecophyscon%initd(pft)>1.0E-7) then - - allocate(temp_cohort) ! temporary cohort - - temp_cohort%pft = pft - temp_cohort%n = EDecophyscon%initd(pft) * patch_in%area - temp_cohort%hite = EDecophyscon%hgt_min(pft) - temp_cohort%dbh = Dbh(temp_cohort) ! FIX(RF, 090314) - comment out addition of ' + 0.0001_r8*pft ' - seperate out PFTs a little bit... - temp_cohort%canopy_trim = 1.0_r8 - temp_cohort%bdead = Bdead(temp_cohort) - temp_cohort%balive = Bleaf(temp_cohort)*(1.0_r8 + pftcon%froot_leaf(pft) & - + EDecophyscon%sapwood_ratio(temp_cohort%pft)*temp_cohort%hite) - temp_cohort%b = temp_cohort%balive + temp_cohort%bdead - - if( pftcon%evergreen(pft) == 1) then - temp_cohort%bstore = Bleaf(temp_cohort) * EDecophyscon%cushion(pft) - temp_cohort%laimemory = 0._r8 - cstatus = 2 - endif - - if( pftcon%season_decid(pft) == 1 ) then !for dorment places - temp_cohort%bstore = Bleaf(temp_cohort) * EDecophyscon%cushion(pft) !stored carbon in new seedlings. - if(patch_in%siteptr%status == 2)then - temp_cohort%laimemory = 0.0_r8 - else - temp_cohort%laimemory = Bleaf(temp_cohort) - endif - ! reduce biomass according to size of store, this will be recovered when elaves com on. - temp_cohort%balive = temp_cohort%balive - temp_cohort%laimemory - cstatus = patch_in%siteptr%status - endif - - if ( pftcon%stress_decid(pft) == 1 ) then - temp_cohort%bstore = Bleaf(temp_cohort) * EDecophyscon%cushion(pft) - temp_cohort%laimemory = Bleaf(temp_cohort) - temp_cohort%balive = temp_cohort%balive - temp_cohort%laimemory - cstatus = patch_in%siteptr%dstatus - endif - - if ( DEBUG ) write(iulog,*) 'EDInitMod.F90 call create_cohort ' - - call create_cohort(patch_in, pft, temp_cohort%n, temp_cohort%hite, temp_cohort%dbh, & - temp_cohort%balive, temp_cohort%bdead, temp_cohort%bstore, & - temp_cohort%laimemory, cstatus, temp_cohort%canopy_trim, 1) - - deallocate(temp_cohort) ! get rid of temporary cohort - - endif - - enddo !numpft - - call fuse_cohorts(patch_in) - call sort_cohorts(patch_in) - - end subroutine init_cohorts - -end module EDInitMod diff --git a/src/ED/main/EDMainMod.F90 b/src/ED/main/EDMainMod.F90 deleted file mode 100755 index f920f39709..0000000000 --- a/src/ED/main/EDMainMod.F90 +++ /dev/null @@ -1,426 +0,0 @@ -module EDMainMod - - ! =========================================================================== - ! Main ED module. - ! ============================================================================ - - use shr_kind_mod , only : r8 => shr_kind_r8 - - use clm_varctl , only : iulog - use atm2lndType , only : atm2lnd_type - use SoilStateType , only : soilstate_type - use TemperatureType , only : temperature_type - use WaterStateType , only : waterstate_type - use EDCohortDynamicsMod , only : allocate_live_biomass, terminate_cohorts, fuse_cohorts, sort_cohorts, count_cohorts - use EDPatchDynamicsMod , only : disturbance_rates, fuse_patches, spawn_patches, terminate_patches - use EDPhysiologyMod , only : canopy_derivs, non_canopy_derivs, phenology, recruitment, trim_canopy - use SFMainMod , only : fire_model - use EDtypesMod , only : ncwd, numpft_ed, udata - use EDtypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type - use EDCLMLinkMod , only : ed_clm_type - - implicit none - private - - ! - ! !PUBLIC MEMBER FUNCTIONS: - public :: ed_ecosystem_dynamics - public :: ed_update_site - ! - ! !PRIVATE MEMBER FUNCTIONS: - - private :: ed_integrate_state_variables - private :: ed_total_balance_check - - logical :: DEBUG = .false. - ! - ! 10/30/09: Created by Rosie Fisher - !----------------------------------------------------------------------- - -contains - - !-------------------------------------------------------------------------------! - subroutine ed_ecosystem_dynamics(currentSite, & - ed_clm_inst, atm2lnd_inst, & - soilstate_inst, temperature_inst, waterstate_inst) - ! - ! !DESCRIPTION: - ! Core of ed model, calling all subsequent vegetation dynamics routines - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(inout), target :: currentSite - type(ed_clm_type) , intent(in) :: ed_clm_inst - type(atm2lnd_type) , intent(in) :: atm2lnd_inst - type(soilstate_type) , intent(in) :: soilstate_inst - type(temperature_type) , intent(in) :: temperature_inst - type(waterstate_type) , intent(in) :: waterstate_inst - ! - ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: currentPatch - !----------------------------------------------------------------------- - - !************************************************************************** - ! Fire, growth, biogeochemistry. - !************************************************************************** - - !FIX(SPM,032414) take this out. On startup these values are all zero and on restart it - !zeros out values read in the restart file - - call ed_total_balance_check(currentSite, 0) - - call phenology(currentSite, temperature_inst, waterstate_inst) - - call fire_model(currentSite, atm2lnd_inst, temperature_inst) - - ! Calculate disturbance and mortality based on previous timestep vegetation. - call disturbance_rates(currentSite) - - ! Integrate state variables from annual rates to daily timestep - call ed_integrate_state_variables(currentSite, temperature_inst ) - - !****************************************************************************** - ! Reproduction, Recruitment and Cohort Dynamics : controls cohort organisation - !****************************************************************************** - - currentPatch => currentSite%oldest_patch - do while (associated(currentPatch)) - - ! adds small cohort of each PFT - call recruitment(0,currentPatch) - - currentPatch => currentPatch%younger - enddo - - call ed_total_balance_check(currentSite,1) - - currentPatch => currentSite%oldest_patch - do while (associated(currentPatch)) - - ! puts cohorts in right order - call sort_cohorts(currentPatch) - - ! fuses similar cohorts - call fuse_cohorts(currentPatch) - - ! kills cohorts that are too small - call terminate_cohorts(currentPatch) - - - currentPatch => currentPatch%younger - enddo - - call ed_total_balance_check(currentSite,2) - - !********************************************************************************* - ! Patch dynamics sub-routines: fusion, new patch creation (spwaning), termination. - !********************************************************************************* - - ! make new patches from disturbed land - call spawn_patches(currentSite) - - call ed_total_balance_check(currentSite,3) - - ! fuse on the spawned patches. - call fuse_patches(currentSite) - - call ed_total_balance_check(currentSite,4) - - ! kill patches that are too small - call terminate_patches(currentSite) - - call ed_total_balance_check(currentSite,5) - - end subroutine ed_ecosystem_dynamics - - !-------------------------------------------------------------------------------! - subroutine ed_integrate_state_variables(currentSite, temperature_inst ) - ! - ! !DESCRIPTION: - ! FIX(SPM,032414) refactor so everything goes through interface - ! - ! !USES: - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(in) :: currentSite - type(temperature_type) , intent(in) :: temperature_inst - ! - ! !LOCAL VARIABLES: - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type) , pointer :: currentCohort - - integer :: c ! Counter for litter size class - integer :: p ! Counter for PFT - real(r8) :: small_no ! to circumvent numerical errors that cause negative values of things that can't be negative - real(r8) :: cohort_biomass_store ! remembers the biomass in the cohort for balance checking - !----------------------------------------------------------------------- - - small_no = 0.0000000000_r8 ! Obviously, this is arbitrary. RF - changed to zero - - currentPatch => currentSite%youngest_patch - - do while(associated(currentPatch)) - - currentPatch%age = currentPatch%age + udata%deltat - ! FIX(SPM,032414) valgrind 'Conditional jump or move depends on uninitialised value' - if( currentPatch%age < 0._r8 )then - write(iulog,*) 'negative patch age?',currentPatch%age, & - currentPatch%patchno,currentPatch%area - endif - - ! Find the derivatives of the growth and litter processes. - call canopy_derivs(currentPatch) - - ! Update Canopy Biomass Pools - currentCohort => currentPatch%shortest - do while(associated(currentCohort)) - - cohort_biomass_store = (currentCohort%balive+currentCohort%bdead+currentCohort%bstore) - currentCohort%dbh = max(small_no,currentCohort%dbh + currentCohort%ddbhdt * udata%deltat ) - currentCohort%balive = currentCohort%balive + currentCohort%dbalivedt * udata%deltat - currentCohort%bdead = max(small_no,currentCohort%bdead + currentCohort%dbdeaddt * udata%deltat ) - if ( DEBUG ) then - write(iulog,*) 'EDMainMod dbstoredt I ',currentCohort%bstore, & - currentCohort%dbstoredt,udata%deltat - end if - currentCohort%bstore = currentCohort%bstore + currentCohort%dbstoredt * udata%deltat - if ( DEBUG ) then - write(iulog,*) 'EDMainMod dbstoredt II ',currentCohort%bstore, & - currentCohort%dbstoredt,udata%deltat - end if - - if( (currentCohort%balive+currentCohort%bdead+currentCohort%bstore)*currentCohort%n<0._r8)then - write(iulog,*) 'biomass is negative', currentCohort%n,currentCohort%balive, & - currentCohort%bdead,currentCohort%bstore - endif - - if(abs((currentCohort%balive+currentCohort%bdead+currentCohort%bstore+udata%deltat*(currentCohort%md+ & - currentCohort%seed_prod)-cohort_biomass_store)-currentCohort%npp_acc) > 1e-8_r8)then - write(iulog,*) 'issue with c balance in integration', abs(currentCohort%balive+currentCohort%bdead+ & - currentCohort%bstore+udata%deltat* & - (currentCohort%md+currentCohort%seed_prod)-cohort_biomass_store-currentCohort%npp_acc) - endif - !do we need these any more? - currentCohort%npp_acc = 0.0_r8 - currentCohort%gpp_acc = 0.0_r8 - currentCohort%resp_acc = 0.0_r8 - - call allocate_live_biomass(currentCohort,1) - - currentCohort => currentCohort%taller - - enddo - - if ( DEBUG ) then - write(6,*)'DEBUG18: calling non_canopy_derivs with pno= ',currentPatch%clm_pno - endif - - call non_canopy_derivs( currentPatch, temperature_inst ) - - !update state variables simultaneously according to derivatives for this time period. - do p = 1,numpft_ed - currentPatch%seed_bank(p) = currentPatch%seed_bank(p) + currentPatch%dseed_dt(p)*udata%deltat - enddo - - do c = 1,ncwd - currentPatch%cwd_ag(c) = currentPatch%cwd_ag(c) + currentPatch%dcwd_ag_dt(c)* udata%deltat - currentPatch%cwd_bg(c) = currentPatch%cwd_bg(c) + currentPatch%dcwd_bg_dt(c)* udata%deltat - enddo - - do p = 1,numpft_ed - currentPatch%leaf_litter(p) = currentPatch%leaf_litter(p) + currentPatch%dleaf_litter_dt(p)* udata%deltat - currentPatch%root_litter(p) = currentPatch%root_litter(p) + currentPatch%droot_litter_dt(p)* udata%deltat - enddo - - ! Check for negative values. Write out warning to show carbon balance. - do p = 1,numpft_ed - if(currentPatch%seed_bank(p) currentPatch%shortest - do while(associated(currentCohort)) - currentCohort%n = max(small_no,currentCohort%n + currentCohort%dndt * udata%deltat ) - currentCohort => currentCohort%taller - enddo - - currentPatch => currentPatch%older - - enddo - - end subroutine ed_integrate_state_variables - - !-------------------------------------------------------------------------------! - subroutine ed_update_site( currentSite ) - ! - ! !DESCRIPTION: - ! Calls routines to consolidate the ED growth process. - ! Canopy Structure to assign canopy layers to cohorts - ! Canopy Spread to figure out the size of tree crowns - ! Trim_canopy to figure out the target leaf biomass. - ! Extra recruitment to fill empty patches. - ! - ! !USES: - use EDCanopyStructureMod , only : canopy_spread, canopy_structure - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(inout), target :: currentSite - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: currentPatch - integer :: cohort_number ! To print out the number of cohorts. - integer :: g ! Counter for sites - !----------------------------------------------------------------------- - - call canopy_spread(currentSite) - - call ed_total_balance_check(currentSite,6) - - call canopy_structure(currentSite) - - call ed_total_balance_check(currentSite,7) - - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - - call terminate_cohorts(currentPatch) - - ! FIX(SPM,040314) why is this needed for BFB restarts? Look into this at some point - cohort_number = count_cohorts(currentPatch) - if ( DEBUG ) then - write(iulog,*) 'tempCount ',cohort_number - endif - - ! Note (RF) - ! This breaks the balance check, but if we leave it out, then - ! the first new patch that isn't fused has no cohorts at the end of the spawn process - ! and so there are radiation errors instead. - ! Fixing this would likely require a re-work of how seed germination works which would be tricky. - if(currentPatch%countcohorts < 1)then - !write(iulog,*) 'ED: calling recruitment for no cohorts',currentPatch%siteptr%clmgcell,currentPatch%patchno - !call recruitment(1,currentPatch) - ! write(iulog,*) 'patch empty',currentPatch%area,currentPatch%age - endif - - currentPatch => currentPatch%younger - - enddo - - ! FIX(RF,032414). This needs to be monthly, not annual - if((udata%time_period == udata%n_sub-1))then - write(iulog,*) 'calling trim canopy' - call trim_canopy(currentSite) - endif - - end subroutine ed_update_site - - !-------------------------------------------------------------------------------! - subroutine ed_total_balance_check (currentSite, call_index ) - ! - ! !DESCRIPTION: - ! This routine looks at the carbon in and out of the ED model and compares it to - ! the change in total carbon stocks. - ! Fluxes in are NPP. Fluxes out are decay of CWD and litter into SOM pools. - ! ed_allsites_inst%flux_out and ed_allsites_inst%flux_in are set where they occur - ! in the code. - ! - ! !ARGUMENTS: - type(ed_site_type) , intent(inout) :: currentSite - integer , intent(in) :: call_index - ! - ! !LOCAL VARIABLES: - real(r8) :: biomass_stock ! total biomass in KgC/site - real(r8) :: litter_stock ! total litter in KgC/site - real(r8) :: seed_stock ! total seed mass in KgC/site - real(r8) :: total_stock ! total ED carbon in KgC/site - real(r8) :: change_in_stock ! Change since last time we set ed_allsites_inst%old_stock in this routine. KgC/site - real(r8) :: error ! How much carbon did we gain or lose (should be zero!) - real(r8) :: net_flux ! Difference between recorded fluxes in and out. KgC/site - - ! nb. There is no time associated with these variables - ! because this routine can be called between any two - ! arbitrary points in code, even if no time has passed. - ! Also, the carbon pools are per site/gridcell, so that - ! we can account for the changing areas of patches. - - type(ed_patch_type) , pointer :: currentPatch - type(ed_cohort_type) , pointer :: currentCohort - !----------------------------------------------------------------------- - - change_in_stock = 0.0_r8 - biomass_stock = 0.0_r8 - litter_stock = 0.0_r8 - seed_stock = 0.0_r8 - - currentPatch => currentSite%oldest_patch - do while(associated(currentPatch)) - - litter_stock = litter_stock + currentPatch%area * (sum(currentPatch%cwd_ag)+ & - sum(currentPatch%cwd_bg)+sum(currentPatch%leaf_litter)+sum(currentPatch%root_litter)) - seed_stock = seed_stock + currentPatch%area * sum(currentPatch%seed_bank) - currentCohort => currentPatch%tallest; - - do while(associated(currentCohort)) - - biomass_stock = biomass_stock + (currentCohort%bdead + currentCohort%balive + & - currentCohort%bstore) * currentCohort%n - currentCohort => currentCohort%shorter; - - enddo !end cohort loop - - currentPatch => currentPatch%younger - - enddo !end patch loop - - total_stock = biomass_stock + seed_stock +litter_stock - change_in_stock = total_stock - currentSite%old_stock - net_flux = currentSite%flux_in - currentSite%flux_out - error = abs(net_flux - change_in_stock) - - if ( abs(error) > 10e-6 ) then - write(iulog,*) 'total error: call index: ',call_index, & - 'in: ',currentSite%flux_in, & - 'out: ',currentSite%flux_out, & - 'net: ',net_flux, & - 'dstock: ',change_in_stock, & - 'error=net_flux-dstock:', error - write(iulog,*) 'biomass,litter,seeds', biomass_stock,litter_stock,seed_stock - write(iulog,*) 'lat lon',currentSite%lat,currentSite%lon - endif - - currentSite%flux_in = 0.0_r8 - currentSite%flux_out = 0.0_r8 - currentSite%old_stock = total_stock - - end subroutine ed_total_balance_check - -end module EDMainMod diff --git a/src/ED/main/EDParamsMod.F90 b/src/ED/main/EDParamsMod.F90 deleted file mode 100644 index 16e2f2f577..0000000000 --- a/src/ED/main/EDParamsMod.F90 +++ /dev/null @@ -1,150 +0,0 @@ -module EDParamsMod - ! - ! module that deals with reading the ED parameter file - ! - use shr_kind_mod , only: r8 => shr_kind_r8 - use EDtypesMod , only: maxPft - - implicit none - save - ! private - if we allow this module to be private, it does not allow the protected values below to be - ! seen outside of this module. - - ! - ! this is what the user can use for the actual values - ! - real(r8),protected :: ED_val_grass_spread - real(r8),protected :: ED_val_comp_excln - real(r8),protected :: ED_val_stress_mort - real(r8),protected :: ED_val_dispersal - real(r8),protected :: ED_val_grperc(maxPft) - real(r8),protected :: ED_val_maxspread - real(r8),protected :: ED_val_minspread - real(r8),protected :: ED_val_init_litter - real(r8),protected :: ED_val_nfires - real(r8),protected :: ED_val_understorey_death - real(r8),protected :: ED_val_profile_tol - real(r8),protected :: ED_val_ag_biomass - - character(len=20),parameter :: ED_name_grass_spread = "grass_spread" - character(len=20),parameter :: ED_name_comp_excln = "comp_excln" - character(len=20),parameter :: ED_name_stress_mort = "stress_mort" - character(len=20),parameter :: ED_name_dispersal = "dispersal" - character(len=20),parameter :: ED_name_grperc = "grperc" - character(len=20),parameter :: ED_name_maxspread = "maxspread" - character(len=20),parameter :: ED_name_minspread = "minspread" - character(len=20),parameter :: ED_name_init_litter = "init_litter" - character(len=20),parameter :: ED_name_nfires = "nfires" - character(len=20),parameter :: ED_name_understorey_death = "understorey_death" - character(len=20),parameter :: ED_name_profile_tol = "profile_tol" - character(len=20),parameter :: ED_name_ag_biomass= "ag_biomass" - - public :: EDParamsRead - -contains - - !----------------------------------------------------------------------- - ! - !----------------------------------------------------------------------- - subroutine EDParamsRead(ncid) - ! - ! calls to initialize parameter instance and do ncdio read - ! - use ncdio_pio , only : file_desc_t - - implicit none - - ! arguments - type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id - - call EDParamsReadLocal(ncid) - - end subroutine EDParamsRead - !----------------------------------------------------------------------- - - !----------------------------------------------------------------------- - ! - !----------------------------------------------------------------------- - subroutine EDParamsReadLocal(ncid) - ! - ! read the netcdf file and populate internalInstScalar - ! - use ncdio_pio , only : file_desc_t - use paramUtilMod , only : readNcdio - - implicit none - - ! arguments - type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id - - ! local vars - character(len=32) :: subname = 'EDParamsReadLocal::' - - ! - ! call read function - ! - - call readNcdio(ncid = ncid, & - varName=ED_name_grass_spread, & - callingName=subname, & - retVal=ED_val_grass_spread) - - call readNcdio(ncid = ncid, & - varName=ED_name_comp_excln, & - callingName=subname, & - retVal=ED_val_comp_excln) - - call readNcdio(ncid = ncid, & - varName=ED_name_stress_mort, & - callingName=subname, & - retVal=ED_val_stress_mort) - - call readNcdio(ncid = ncid, & - varName=ED_name_dispersal, & - callingName=subname, & - retVal=ED_val_dispersal) - - call readNcdio(ncid = ncid, & - varName=ED_name_grperc, & - callingName=subname, & - retVal=ED_val_grperc) - - call readNcdio(ncid = ncid, & - varName=ED_name_maxspread, & - callingName=subname, & - retVal=ED_val_maxspread) - - call readNcdio(ncid = ncid, & - varName=ED_name_minspread, & - callingName=subname, & - retVal=ED_val_minspread) - - call readNcdio(ncid = ncid, & - varName=ED_name_init_litter, & - callingName=subname, & - retVal=ED_val_init_litter) - - call readNcdio(ncid = ncid, & - varName=ED_name_nfires, & - callingName=subname, & - retVal=ED_val_nfires) - - call readNcdio(ncid = ncid, & - varName=ED_name_understorey_death, & - callingName=subname, & - retVal=ED_val_understorey_death) - - call readNcdio(ncid = ncid, & - varName=ED_name_profile_tol, & - callingName=subname, & - retVal=ED_val_profile_tol) - - call readNcdio(ncid = ncid, & - varName=ED_name_ag_biomass, & - callingName=subname, & - retVal=ED_val_ag_biomass) - - end subroutine EDParamsReadLocal - !----------------------------------------------------------------------- - -end module EDParamsMod diff --git a/src/ED/main/EDPftvarcon.F90 b/src/ED/main/EDPftvarcon.F90 deleted file mode 100644 index 475ee7b1bb..0000000000 --- a/src/ED/main/EDPftvarcon.F90 +++ /dev/null @@ -1,143 +0,0 @@ -module EDPftvarcon - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Module containing vegetation constants and method to - ! read and initialize vegetation (PFT) constants. - ! - ! !USES: - use clm_varpar , only : mxpft - use shr_kind_mod, only : r8 => shr_kind_r8 - - ! - ! !PUBLIC TYPES: - implicit none - save - private - - !ED specific variables. - type, public :: EDPftvarcon_type - real(r8) :: max_dbh (0:mxpft) ! maximum dbh at which height growth ceases... - real(r8) :: freezetol (0:mxpft) ! minimum temperature tolerance... - real(r8) :: wood_density (0:mxpft) ! wood density g cm^-3 ... - real(r8) :: alpha_stem (0:mxpft) ! live stem turnover rate. y-1 - real(r8) :: hgt_min (0:mxpft) ! sapling height m - real(r8) :: cushion (0:mxpft) ! labile carbon storage target as multiple of leaf pool. - real(r8) :: leaf_stor_priority (0:mxpft) ! leaf turnover vs labile carbon use prioritisation. (1 = lose leaves, 0 = use store). - real(r8) :: leafwatermax (0:mxpft) ! degree to which respiration is limited by btran if btran = 0 - real(r8) :: rootresist (0:mxpft) - real(r8) :: soilbeta (0:mxpft) - real(r8) :: crown (0:mxpft) - real(r8) :: bark_scaler (0:mxpft) - real(r8) :: crown_kill (0:mxpft) - real(r8) :: initd (0:mxpft) - real(r8) :: sd_mort (0:mxpft) - real(r8) :: seed_rain (0:mxpft) - real(r8) :: BB_slope (0:mxpft) - real(r8) :: root_long (0:mxpft) ! root longevity (yrs) - real(r8) :: clone_alloc (0:mxpft) ! fraction of carbon balance allocated to clonal reproduction. - real(r8) :: seed_alloc (0:mxpft) ! fraction of carbon balance allocated to seeds. - real(r8) :: sapwood_ratio (0:mxpft) ! amount of sapwood per unit leaf carbon and m of height. gC/gC/m - real(r8) :: dbh2h_m (0:mxpft) ! allocation parameter m from dbh to height - end type EDPftvarcon_type - - type(EDPftvarcon_type), public :: EDPftvarcon_inst - - ! - ! !PUBLIC MEMBER FUNCTIONS: - public :: EDpftconrd ! Read and initialize vegetation (PFT) constants - !----------------------------------------------------------------------- - -contains - - !----------------------------------------------------------------------- - subroutine EDpftconrd( ncid ) - ! - ! !DESCRIPTION: - ! Read and initialize vegetation (PFT) constants - ! - ! !USES: - use ncdio_pio , only : file_desc_t, ncd_io - use abortutils , only : endrun - ! - ! !ARGUMENTS: - implicit none - ! - type(file_desc_t), intent(inout) :: ncid ! pio netCDF file id - - ! !LOCAL VARIABLES: - - logical :: readv ! read variable in or not - character(len=32) :: subname = 'EDpftconrd' ! subroutine name - - call ncd_io('max_dbh',EDPftvarcon_inst%max_dbh, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('freezetol',EDPftvarcon_inst%freezetol, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('wood_density',EDPftvarcon_inst%wood_density, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('alpha_stem',EDPftvarcon_inst%alpha_stem, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('hgt_min',EDPftvarcon_inst%hgt_min, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('cushion',EDPftvarcon_inst%cushion, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('leaf_stor_priority',EDPftvarcon_inst%leaf_stor_priority, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('leafwatermax',EDPftvarcon_inst%leafwatermax, 'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('rootresist',EDPftvarcon_inst%rootresist,'read', ncid, readvar=readv) - if ( .not. readv ) call endrun( trim(subname)//' ERROR: error in reading in pft data' ) - - call ncd_io('soilbeta',EDPftvarcon_inst%soilbeta,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('crown',EDPftvarcon_inst%crown,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('bark_scaler',EDPftvarcon_inst%bark_scaler,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('crown_kill',EDPftvarcon_inst%crown_kill,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('initd',EDPftvarcon_inst%initd,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('sd_mort',EDPftvarcon_inst%sd_mort,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('seed_rain',EDPftvarcon_inst%seed_rain,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('BB_slope',EDPftvarcon_inst%BB_slope,'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('root_long',EDPftvarcon_inst%root_long, 'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('seed_alloc',EDPftvarcon_inst%seed_alloc, 'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('clone_alloc',EDPftvarcon_inst%clone_alloc, 'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - call ncd_io('sapwood_ratio',EDPftvarcon_inst%sapwood_ratio, 'read', ncid, readvar=readv) - if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - -! HOLDING ON SEW ENSITIVITY-ANALYSIS PARAMETERS UNTIL MACHINE CONFIGS SET RGK/CX -! call ncd_io('dbh2h_m',EDPftvarcon_inst%dbh2h_m, 'read', ncid, readvar=readv) -! if ( .not. readv) call endrun(trim(subname)// ' ERROR : error in reading in pft data') - - end subroutine EDpftconrd - -end module EDPftvarcon - diff --git a/src/ED/main/EDRestVectorMod.F90 b/src/ED/main/EDRestVectorMod.F90 deleted file mode 100755 index a4290e04fd..0000000000 --- a/src/ED/main/EDRestVectorMod.F90 +++ /dev/null @@ -1,2218 +0,0 @@ -module EDRestVectorMod - -#include "shr_assert.h" - - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use shr_sys_mod , only : shr_sys_abort - use clm_varctl , only : iulog - use spmdMod , only : masterproc - use decompMod , only : bounds_type - use pftconMod , only : pftcon - use EDTypesMod , only : area, cohorts_per_col, numpft_ed, numWaterMem, cp_nclmax, numCohortsPerPatch - use EDTypesMod , only : ncwd, invalidValue, cp_nlevcan - use EDTypesMod , only : ed_site_type, ed_patch_type, ed_cohort_type - use abortutils , only : endrun - - ! - implicit none - private - ! - ! integer constants for storing logical data - integer, parameter :: old_cohort = 0 - integer, parameter :: new_cohort = 1 - ! - ! ED cohort data as a type of vectors - ! - type, public :: EDRestartVectorClass - ! - ! for vector start and stop, equivalent to begCohort and endCohort - ! - integer :: vectorLengthStart - integer :: vectorLengthStop - - logical :: DEBUG = .false. - ! - ! add ED vectors that need to be written for Restarts - ! - - ! required to map cohorts and patches to/fro - ! vectors/LinkedLists - integer, pointer :: numPatchesPerCol(:) - integer, pointer :: cohortsPerPatch(:) - ! - ! cohort data - ! - real(r8), pointer :: balive(:) - real(r8), pointer :: bdead(:) - real(r8), pointer :: bl(:) - real(r8), pointer :: br(:) - real(r8), pointer :: bstore(:) - real(r8), pointer :: canopy_layer(:) - real(r8), pointer :: canopy_trim(:) - real(r8), pointer :: dbh(:) - real(r8), pointer :: hite(:) - real(r8), pointer :: laimemory(:) - real(r8), pointer :: leaf_md(:) ! this can probably be removed - real(r8), pointer :: root_md(:) ! this can probably be removed - real(r8), pointer :: n(:) - real(r8), pointer :: gpp_acc(:) - real(r8), pointer :: npp_acc(:) - real(r8), pointer :: gpp(:) - real(r8), pointer :: npp(:) - real(r8), pointer :: npp_leaf(:) - real(r8), pointer :: npp_froot(:) - real(r8), pointer :: npp_bsw(:) - real(r8), pointer :: npp_bdead(:) - real(r8), pointer :: npp_bseed(:) - real(r8), pointer :: npp_store(:) - real(r8), pointer :: bmort(:) - real(r8), pointer :: hmort(:) - real(r8), pointer :: cmort(:) - real(r8), pointer :: imort(:) - real(r8), pointer :: fmort(:) - real(r8), pointer :: ddbhdt(:) - real(r8), pointer :: resp_tstep(:) - integer, pointer :: pft(:) - integer, pointer :: status_coh(:) - integer, pointer :: isnew(:) - ! - ! patch level restart vars - ! indexed by ncwd - ! - real(r8), pointer :: cwd_ag(:) - real(r8), pointer :: cwd_bg(:) - ! - ! indexed by pft - ! - real(r8), pointer :: leaf_litter(:) - real(r8), pointer :: root_litter(:) - real(r8), pointer :: leaf_litter_in(:) - real(r8), pointer :: root_litter_in(:) - real(r8), pointer :: seed_bank(:) - ! - ! indext by nclmax - ! - real(r8), pointer :: spread(:) - ! - ! one per patch - ! - real(r8), pointer :: livegrass(:) ! this can probably be removed - real(r8), pointer :: age(:) - real(r8), pointer :: areaRestart(:) - real(r8), pointer :: f_sun(:) - real(r8), pointer :: fabd_sun_z(:) - real(r8), pointer :: fabi_sun_z(:) - real(r8), pointer :: fabd_sha_z(:) - real(r8), pointer :: fabi_sha_z(:) - ! - ! site level restart vars - ! - real(r8), pointer :: water_memory(:) - real(r8), pointer :: old_stock(:) - real(r8), pointer :: cd_status(:) - real(r8), pointer :: dd_status(:) - real(r8), pointer :: ED_GDD_site(:) - real(r8), pointer :: ncd(:) - real(r8), pointer :: leafondate(:) - real(r8), pointer :: leafoffdate(:) - real(r8), pointer :: dleafondate(:) - real(r8), pointer :: dleafoffdate(:) - real(r8), pointer :: acc_NI(:) - - - contains - ! - ! implement getVector and setVector - ! - procedure :: setVectors - procedure :: getVectors - ! - ! restart calls - ! - procedure :: doVectorIO - ! - ! clean up pointer arrays - ! - procedure :: deleteEDRestartVectorClass - ! - ! utility routines - ! - procedure :: convertCohortListToVector - procedure :: createPatchCohortStructure - procedure :: convertCohortVectorToList - procedure :: printIoInfoLL - procedure :: printDataInfoLL - procedure :: printDataInfoVector - - end type EDRestartVectorClass - - ! Fortran way of getting a user-defined ctor - interface EDRestartVectorClass - module procedure newEDRestartVectorClass - end interface EDRestartVectorClass - - ! - ! non type-bound procedures - ! - public :: EDRest - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - !-------------------------------------------------------------------------------! - -contains - - !--------------------------------------------! - ! Type-Bound Procedures Here: - !--------------------------------------------! - - !-------------------------------------------------------------------------------! - subroutine deleteEDRestartVectorClass( this ) - ! - ! !DESCRIPTION: - ! provide clean-up routine of allocated pointer arrays - ! - ! !USES: - ! - ! !ARGUMENTS: - class(EDRestartVectorClass), intent(inout) :: this - ! - ! !LOCAL VARIABLES: - deallocate(this%numPatchesPerCol ) - deallocate(this%cohortsPerPatch ) - deallocate(this%balive ) - deallocate(this%bdead ) - deallocate(this%bl ) - deallocate(this%br ) - deallocate(this%bstore ) - deallocate(this%canopy_layer ) - deallocate(this%canopy_trim ) - deallocate(this%dbh ) - deallocate(this%hite ) - deallocate(this%laimemory ) - deallocate(this%leaf_md ) - deallocate(this%root_md ) - deallocate(this%n ) - deallocate(this%gpp_acc ) - deallocate(this%npp_acc ) - deallocate(this%gpp ) - deallocate(this%npp ) - deallocate(this%npp_leaf ) - deallocate(this%npp_froot ) - deallocate(this%npp_bsw ) - deallocate(this%npp_bdead ) - deallocate(this%npp_bseed ) - deallocate(this%npp_store ) - deallocate(this%bmort ) - deallocate(this%hmort ) - deallocate(this%cmort ) - deallocate(this%imort ) - deallocate(this%fmort ) - deallocate(this%ddbhdt ) - deallocate(this%resp_tstep ) - deallocate(this%pft ) - deallocate(this%status_coh ) - deallocate(this%isnew ) - deallocate(this%cwd_ag ) - deallocate(this%cwd_bg ) - deallocate(this%leaf_litter ) - deallocate(this%root_litter ) - deallocate(this%leaf_litter_in ) - deallocate(this%root_litter_in ) - deallocate(this%seed_bank ) - deallocate(this%spread ) - deallocate(this%livegrass ) - deallocate(this%age ) - deallocate(this%areaRestart ) - deallocate(this%f_sun ) - deallocate(this%fabd_sun_z ) - deallocate(this%fabi_sun_z ) - deallocate(this%fabd_sha_z ) - deallocate(this%fabi_sha_z ) - deallocate(this%water_memory ) - deallocate(this%old_stock ) - deallocate(this%cd_status ) - deallocate(this%dd_status ) - deallocate(this%ED_GDD_site ) - deallocate(this%ncd ) - deallocate(this%leafondate ) - deallocate(this%leafoffdate ) - deallocate(this%dleafondate ) - deallocate(this%dleafoffdate ) - deallocate(this%acc_NI ) - - end subroutine deleteEDRestartVectorClass - - !-------------------------------------------------------------------------------! - function newEDRestartVectorClass( bounds ) - ! - ! !DESCRIPTION: - ! provide user-defined ctor, with array length argument - ! allocate memory for vector to write - ! - ! !USES: - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds ! bounds - ! - ! !LOCAL VARIABLES: - type(EDRestartVectorClass) :: newEDRestartVectorClass - integer :: retVal = 99 - integer, parameter :: allocOK = 0 - !----------------------------------------------------------------------- - - associate( new => newEDRestartVectorClass) - - ! set class variables - new%vectorLengthStart = bounds%begCohort - new%vectorLengthStop = bounds%endCohort - - ! Column level variables - - allocate(new%numPatchesPerCol & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%numPatchesPerCol(:) = invalidValue - - allocate(new%old_stock & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%old_stock(:) = 0.0_r8 - - allocate(new%cd_status & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%cd_status(:) = 0_r8 - - allocate(new%dd_status & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%dd_status(:) = 0_r8 - - allocate(new%ncd & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%ncd(:) = 0_r8 - - - allocate(new%leafondate & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%leafondate(:) = 0_r8 - - allocate(new%leafoffdate & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%leafoffdate(:) = 0_r8 - - allocate(new%dleafondate & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%dleafondate(:) = 0_r8 - - allocate(new%dleafoffdate & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%dleafoffdate(:) = 0_r8 - - allocate(new%acc_NI & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%acc_NI(:) = 0_r8 - - allocate(new%ED_GDD_site & - (bounds%begc:bounds%endc), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%ED_GDD_site(:) = 0_r8 - - - ! cohort level variables - - - - allocate(new%cohortsPerPatch & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%cohortsPerPatch(:) = invalidValue - - allocate(new%balive & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%balive(:) = 0.0_r8 - - allocate(new%bdead & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%bdead(:) = 0.0_r8 - - allocate(new%bl & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%bl(:) = 0.0_r8 - - allocate(new%br & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%br(:) = 0.0_r8 - - allocate(new%bstore & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%bstore(:) = 0.0_r8 - - allocate(new%canopy_layer & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%canopy_layer(:) = 0.0_r8 - - allocate(new%canopy_trim & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%canopy_trim(:) = 0.0_r8 - - allocate(new%dbh & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%dbh(:) = 0.0_r8 - - allocate(new%hite & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%hite(:) = 0.0_r8 - - allocate(new%laimemory & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%laimemory(:) = 0.0_r8 - - allocate(new%leaf_md & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%leaf_md(:) = 0.0_r8 - - allocate(new%root_md & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%root_md(:) = 0.0_r8 - - allocate(new%n & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%n(:) = 0.0_r8 - - allocate(new%gpp_acc & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%gpp_acc(:) = 0.0_r8 - - allocate(new%npp_acc & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp_acc(:) = 0.0_r8 - - allocate(new%gpp & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%gpp(:) = 0.0_r8 - - allocate(new%npp & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp(:) = 0.0_r8 - - allocate(new%npp_leaf & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp_leaf(:) = 0.0_r8 - - allocate(new%npp_froot & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp_froot(:) = 0.0_r8 - - allocate(new%npp_bsw & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp_bsw(:) = 0.0_r8 - - allocate(new%npp_bdead & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp_bdead(:) = 0.0_r8 - - allocate(new%npp_bseed & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp_bseed(:) = 0.0_r8 - - allocate(new%npp_store & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%npp_store(:) = 0.0_r8 - - allocate(new%bmort & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%bmort(:) = 0.0_r8 - - allocate(new%hmort & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%hmort(:) = 0.0_r8 - - allocate(new%cmort & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%cmort(:) = 0.0_r8 - - allocate(new%imort & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%imort(:) = 0.0_r8 - - allocate(new%fmort & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%fmort(:) = 0.0_r8 - - allocate(new%ddbhdt & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%ddbhdt(:) = 0.0_r8 - - allocate(new%resp_tstep & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%resp_tstep(:) = 0.0_r8 - - allocate(new%pft & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%pft(:) = 0 - - allocate(new%status_coh & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%status_coh(:) = 0 - - allocate(new%isnew & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%isnew(:) = new_cohort - - ! - ! some patch level variables that are required on restart - ! - allocate(new%cwd_ag & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%cwd_ag(:) = 0.0_r8 - - allocate(new%cwd_bg & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%cwd_bg(:) = 0.0_r8 - - allocate(new%leaf_litter & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%leaf_litter(:) = 0.0_r8 - - allocate(new%root_litter & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%root_litter(:) = 0.0_r8 - - allocate(new%leaf_litter_in & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%leaf_litter_in(:) = 0.0_r8 - - allocate(new%root_litter_in & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%root_litter_in(:) = 0.0_r8 - - allocate(new%seed_bank & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%seed_bank(:) = 0.0_r8 - - allocate(new%spread & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%spread(:) = 0.0_r8 - - allocate(new%livegrass & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%livegrass(:) = 0.0_r8 - - allocate(new%age & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%age(:) = 0.0_r8 - - allocate(new%areaRestart & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%areaRestart(:) = 0.0_r8 - - allocate(new%f_sun & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%f_sun(:) = 0.0_r8 - - allocate(new%fabd_sun_z & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%fabd_sun_z(:) = 0.0_r8 - - allocate(new%fabi_sun_z & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%fabi_sun_z(:) = 0.0_r8 - - allocate(new%fabd_sha_z & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%fabd_sha_z(:) = 0.0_r8 - - allocate(new%fabi_sha_z & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%fabi_sha_z(:) = 0.0_r8 - - ! - ! Site level variable stored with cohort indexing - ! (to accomodate the second dimension) - ! - - allocate(new%water_memory & - (new%vectorLengthStart:new%vectorLengthStop), stat=retVal) - SHR_ASSERT(( retVal == allocOK ), errMsg(sourcefile, __LINE__)) - new%water_memory(:) = 0.0_r8 - - - end associate - - end function newEDRestartVectorClass - - !-------------------------------------------------------------------------------! - subroutine setVectors( this, bounds, nsites, sites, fcolumn ) - ! - ! !DESCRIPTION: - ! implement setVectors - ! - ! !USES: - use clm_time_manager , only : get_nstep - ! - ! !ARGUMENTS: - class(EDRestartVectorClass) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(in), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - ! - ! !LOCAL VARIABLES: - !----------------------------------------------------------------------- - - if ( masterproc ) write(iulog,*) 'edtime setVectors ',get_nstep() - - !if (this%DEBUG) then - ! call this%printIoInfoLL ( bounds, sites, nsites ) - ! call this%printDataInfoLL ( bounds, sites, nsites ) - !end if - - call this%convertCohortListToVector ( bounds, nsites, sites, fcolumn ) - - if (this%DEBUG) then - call this%printIoInfoLL ( bounds, nsites, sites, fcolumn ) - call this%printDataInfoLL ( bounds, nsites, sites ) - - ! RGK: Commenting this out because it is calling several - ! variables over the wrong indices -! call this%printDataInfoVector ( ) - end if - - end subroutine setVectors - - !-------------------------------------------------------------------------------! - subroutine getVectors( this, bounds, nsites, sites, fcolumn) - ! - ! !DESCRIPTION: - ! implement getVectors - ! - ! !USES: - use clm_time_manager , only : get_nstep - use EDCLMLinkMod , only : ed_clm_type - use EDMainMod , only : ed_update_site - ! - ! !ARGUMENTS: - class(EDRestartVectorClass) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - ! - ! !LOCAL VARIABLES: - integer :: s - !----------------------------------------------------------------------- - - if (this%DEBUG) then - write(iulog,*) 'edtime getVectors ',get_nstep() - end if - - call this%createPatchCohortStructure ( bounds, nsites, sites, fcolumn ) - - call this%convertCohortVectorToList ( bounds, nsites , sites, fcolumn) - - do s = 1,nsites - call ed_update_site( sites(s) ) - end do - - if (this%DEBUG) then - call this%printIoInfoLL ( bounds, nsites, sites, fcolumn ) - call this%printDataInfoLL ( bounds, nsites, sites ) - call this%printDataInfoVector ( ) - end if - - end subroutine getVectors - - !-------------------------------------------------------------------------------! - subroutine doVectorIO( this, ncid, flag ) - ! - ! !DESCRIPTION: - ! implement VectorIO - ! - ! !USES: - use ncdio_pio , only : file_desc_t, ncd_int, ncd_double - use restUtilMod, only : restartvar - use clm_varcon, only : namec, nameCohort - use spmdMod, only : iam - ! - ! !ARGUMENTS: - class(EDRestartVectorClass), intent(inout) :: this - type(file_desc_t), intent(inout) :: ncid ! netcdf id - character(len=*) , intent(in) :: flag !'read' or 'write' - ! - ! !LOCAL VARIABLES: - logical :: readvar - character(len=16) :: coh_dimName = trim(nameCohort) - character(len=16) :: col_dimName = trim(namec) - !----------------------------------------------------------------------- - - - if(this%DEBUG) then - write(iulog,*) 'flag:',flag - write(iulog,*) 'dimname:',col_dimName - write(iulog,*) 'readvar:',readvar - write(iulog,*) 'associated?',associated(this%numPatchesPerCol) - write(iulog,*) '' - write(iulog,*) 'col size:',size(this%numPatchesPerCol) - write(iulog,*) 'col lbound:',lbound(this%numPatchesPerCol) - write(iulog,*) 'col ubound:',ubound(this%numPatchesPerCol) - - write(iulog,*) 'coh size:',size(this%cohortsPerPatch) - write(iulog,*) 'coh lbound:',lbound(this%cohortsPerPatch) - write(iulog,*) 'coh ubound:',ubound(this%cohortsPerPatch) - write(iulog,*) '' - end if - - call restartvar(ncid=ncid, flag=flag, varname='ed_io_numPatchesPerCol', xtype=ncd_int, & - dim1name=col_dimName, & - long_name='Num patches per column', units='unitless', & - interpinic_flag='interp', data=this%numPatchesPerCol, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_old_stock', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed cohort - old_stock', units='unitless', & - interpinic_flag='interp', data=this%old_stock, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_cd_status', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed cold dec status', units='unitless', & - interpinic_flag='interp', data=this%cd_status, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_dd_status', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed drought dec status', units='unitless', & - interpinic_flag='interp', data=this%dd_status, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_chilling_days', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed chilling day counter', units='unitless', & - interpinic_flag='interp', data=this%ncd, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_leafondate', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed leafondate', units='unitless', & - interpinic_flag='interp', data=this%leafondate, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_leafoffdate', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed leafoffdate', units='unitless', & - interpinic_flag='interp', data=this%leafoffdate, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_dleafondate', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed dleafondate', units='unitless', & - interpinic_flag='interp', data=this%dleafondate, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_dleafoffdate', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed dleafoffdate', units='unitless', & - interpinic_flag='interp', data=this%dleafoffdate, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_acc_NI', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed nesterov index', units='unitless', & - interpinic_flag='interp', data=this%acc_NI, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_gdd_site', xtype=ncd_double, & - dim1name=col_dimName, & - long_name='ed GDD site', units='unitless', & - interpinic_flag='interp', data=this%ED_GDD_site, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_balive', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort ed_balive', units='unitless', & - interpinic_flag='interp', data=this%balive, & - readvar=readvar) - - ! - ! cohort level vars - ! - call restartvar(ncid=ncid, flag=flag, varname='ed_io_cohortsPerPatch', xtype=ncd_int, & - dim1name=coh_dimName, & - long_name='cohorts per patch, indexed by numPatchesPerCol', units='unitless', & - interpinic_flag='interp', data=this%cohortsPerPatch, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_bdead', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - bdead', units='unitless', & - interpinic_flag='interp', data=this%bdead, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_bl', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - bl', units='unitless', & - interpinic_flag='interp', data=this%bl, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_br', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - br', units='unitless', & - interpinic_flag='interp', data=this%br, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_bstore', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - bstore', units='unitless', & - interpinic_flag='interp', data=this%bstore, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_canopy_layer', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - canopy_layer', units='unitless', & - interpinic_flag='interp', data=this%canopy_layer, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_canopy_trim', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - canopy_trim', units='unitless', & - interpinic_flag='interp', data=this%canopy_trim, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_dbh', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - dbh', units='unitless', & - interpinic_flag='interp', data=this%dbh, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_hite', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - hite', units='unitless', & - interpinic_flag='interp', data=this%hite, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_laimemory', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - laimemory', units='unitless', & - interpinic_flag='interp', data=this%laimemory, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_leaf_md', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - leaf_md', units='unitless', & - interpinic_flag='interp', data=this%leaf_md, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_root_md', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - root_md', units='unitless', & - interpinic_flag='interp', data=this%root_md, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_n', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - n', units='unitless', & - interpinic_flag='interp', data=this%n, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_gpp_acc', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - gpp_acc', units='unitless', & - interpinic_flag='interp', data=this%gpp_acc, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp_acc', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp_acc', units='unitless', & - interpinic_flag='interp', data=this%npp_acc, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_gpp', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - gpp', units='unitless', & - interpinic_flag='interp', data=this%gpp, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp', units='unitless', & - interpinic_flag='interp', data=this%npp, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp_leaf', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp_leaf', units='unitless', & - interpinic_flag='interp', data=this%npp_leaf, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp_froot', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp_froot', units='unitless', & - interpinic_flag='interp', data=this%npp_froot, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp_bsw', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp_bsw', units='unitless', & - interpinic_flag='interp', data=this%npp_bsw, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp_bdead', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp_bdead', units='unitless', & - interpinic_flag='interp', data=this%npp_bdead, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp_bseed', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp_bseed', units='unitless', & - interpinic_flag='interp', data=this%npp_bseed, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_npp_store', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - npp_store', units='unitless', & - interpinic_flag='interp', data=this%npp_store, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_bmort', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - bmort', units='unitless', & - interpinic_flag='interp', data=this%bmort, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_hmort', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - hmort', units='unitless', & - interpinic_flag='interp', data=this%hmort, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_cmort', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - cmort', units='unitless', & - interpinic_flag='interp', data=this%cmort, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_imort', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - imort', units='unitless', & - interpinic_flag='interp', data=this%imort, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_fmort', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - fmort', units='unitless', & - interpinic_flag='interp', data=this%fmort, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_ddbhdt', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - ddbhdt', units='unitless', & - interpinic_flag='interp', data=this%ddbhdt, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_resp_tstep', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - resp_tstep', units='unitless', & - interpinic_flag='interp', data=this%resp_tstep, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_pft', xtype=ncd_int, & - dim1name=coh_dimName, & - long_name='ed cohort - pft', units='unitless', & - interpinic_flag='interp', data=this%pft, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_status_coh', xtype=ncd_int, & - dim1name=coh_dimName, & - long_name='ed cohort - status_coh', units='unitless', & - interpinic_flag='interp', data=this%status_coh, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_isnew', xtype=ncd_int, & - dim1name=coh_dimName, & - long_name='ed cohort - isnew', units='unitless', & - interpinic_flag='interp', data=this%isnew, & - readvar=readvar) - - ! - ! patch level vars - ! - - call restartvar(ncid=ncid, flag=flag, varname='ed_cwd_ag', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - cwd_ag', units='unitless', & - interpinic_flag='interp', data=this%cwd_ag, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_cwd_bg', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - cwd_bg', units='unitless', & - interpinic_flag='interp', data=this%cwd_bg, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_leaf_litter', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - leaf_litter', units='unitless', & - interpinic_flag='interp', data=this%leaf_litter, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_root_litter', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - root_litter', units='unitless', & - interpinic_flag='interp', data=this%root_litter, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_leaf_litter_in', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - leaf_litter_in', units='unitless', & - interpinic_flag='interp', data=this%leaf_litter_in, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_root_litter_in', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - root_litter_in', units='unitless', & - interpinic_flag='interp', data=this%root_litter_in, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_seed_bank', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - seed_bank', units='unitless', & - interpinic_flag='interp', data=this%seed_bank, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_spread', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - spread', units='unitless', & - interpinic_flag='interp', data=this%spread, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_livegrass', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - livegrass', units='unitless', & - interpinic_flag='interp', data=this%livegrass, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_age', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - age', units='unitless', & - interpinic_flag='interp', data=this%age, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_area', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - area', units='unitless', & - interpinic_flag='interp', data=this%areaRestart, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_f_sun', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - f_sun', units='unitless', & - interpinic_flag='interp', data=this%f_sun, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_fabd_sun_z', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - fabd_sun_z', units='unitless', & - interpinic_flag='interp', data=this%fabd_sun_z, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_fabi_sun_z', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - fabi_sun_z', units='unitless', & - interpinic_flag='interp', data=this%fabi_sun_z, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_fabd_sha_z', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - fabd_sha_z', units='unitless', & - interpinic_flag='interp', data=this%fabd_sha_z, & - readvar=readvar) - - call restartvar(ncid=ncid, flag=flag, varname='ed_fabi_sha_z', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed patch - fabi_sha_z', units='unitless', & - interpinic_flag='interp', data=this%fabi_sha_z, & - readvar=readvar) - ! - ! site level vars - ! - - call restartvar(ncid=ncid, flag=flag, varname='ed_water_memory', xtype=ncd_double, & - dim1name=coh_dimName, & - long_name='ed cohort - water_memory', units='unitless', & - interpinic_flag='interp', data=this%water_memory, & - readvar=readvar) - - end subroutine doVectorIO - - !-------------------------------------------------------------------------------! - subroutine printDataInfoVector( this ) - ! - ! !DESCRIPTION: - ! - ! !USES: - ! - ! !ARGUMENTS: - class(EDRestartVectorClass), intent(inout) :: this - ! - ! !LOCAL VARIABLES: - character(len=32) :: methodName = 'PDIV ' - integer :: iSta, iSto - !----------------------------------------------------------------------- - - ! RGK: changed the vector end-point on column variables to match the start point - ! this avoids exceeding bounds on the last column of the dataset - - iSta = this%vectorLengthStart - iSto = iSta + 1 - - write(iulog,*) trim(methodName)//' :: this%vectorLengthStart ', & - this%vectorLengthStart - write(iulog,*) trim(methodName)//' :: this%vectorLengthStop ', & - this%vectorLengthStop - - write(iulog,*) ' PDIV chk ',iSta,iSto - write(iulog,*) trim(methodName)//' :: balive ', & - this%balive(iSta:iSto) - write(iulog,*) trim(methodName)//' :: bdead ', & - this%bdead(iSta:iSto) - write(iulog,*) trim(methodName)//' :: bl ', & - this%bl(iSta:iSto) - write(iulog,*) trim(methodName)//' :: br ', & - this%br(iSta:iSto) - write(iulog,*) trim(methodName)//' :: bstore ', & - this%bstore(iSta:iSto) - - write(iulog,*) trim(methodName)//' :: canopy_layer ', & - this%canopy_layer(iSta:iSto) - write(iulog,*) trim(methodName)//' :: canopy_trim ', & - this%canopy_trim(iSta:iSto) - write(iulog,*) trim(methodName)//' :: dbh ', & - this%dbh(iSta:iSto) - - write(iulog,*) trim(methodName)//' :: hite ', & - this%hite(iSta:iSto) - write(iulog,*) trim(methodName)//' :: laimemory ', & - this%laimemory(iSta:iSto) - write(iulog,*) trim(methodName)//' :: leaf_md ', & - this%leaf_md(iSta:iSto) - write(iulog,*) trim(methodName)//' :: root_md ', & - this%root_md(iSta:iSto) - write(iulog,*) trim(methodName)//' :: n ', & - this%n(iSta:iSto) - write(iulog,*) trim(methodName)//' :: gpp_acc ', & - this%gpp_acc(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp_acc ', & - this%npp_acc(iSta:iSto) - write(iulog,*) trim(methodName)//' :: gpp ', & - this%gpp(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp ', & - this%npp(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp_leaf ', & - this%npp_leaf(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp_froot ', & - this%npp_froot(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp_bsw ', & - this%npp_bsw(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp_bdead ', & - this%npp_bdead(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp_bseed ', & - this%npp_bseed(iSta:iSto) - write(iulog,*) trim(methodName)//' :: npp_store ', & - this%npp_store(iSta:iSto) - write(iulog,*) trim(methodName)//' :: bmort ', & - this%bmort(iSta:iSto) - write(iulog,*) trim(methodName)//' :: hmort ', & - this%hmort(iSta:iSto) - write(iulog,*) trim(methodName)//' :: cmort ', & - this%cmort(iSta:iSto) - write(iulog,*) trim(methodName)//' :: imort ', & - this%imort(iSta:iSto) - write(iulog,*) trim(methodName)//' :: fmort ', & - this%fmort(iSta:iSto) - write(iulog,*) trim(methodName)//' :: ddbhdt ', & - this%ddbhdt(iSta:iSto) - write(iulog,*) trim(methodName)//' :: resp_tstep ', & - this%resp_tstep(iSta:iSto) - - write(iulog,*) trim(methodName)//' :: pft ', & - this%pft(iSta:iSto) - write(iulog,*) trim(methodName)//' :: status_coh ', & - this%status_coh(iSta:iSto) - write(iulog,*) trim(methodName)//' :: isnew ', & - this%isnew(iSta:iSto) - - write(iulog,*) trim(methodName)//' :: cwd_ag ', & - this%cwd_ag(iSta:iSto) - write(iulog,*) trim(methodName)//' :: cwd_bg ', & - this%cwd_bg(iSta:iSto) - write(iulog,*) trim(methodName)//' :: leaf_litter ', & - this%leaf_litter(iSta:iSto) - write(iulog,*) trim(methodName)//' :: root_litter ', & - this%root_litter(iSta:iSto) - write(iulog,*) trim(methodName)//' :: leaf_litter_in ', & - this%leaf_litter_in(iSta:iSto) - write(iulog,*) trim(methodName)//' :: root_litter_in ', & - this%root_litter_in(iSta:iSto) - write(iulog,*) trim(methodName)//' :: seed_bank ', & - this%seed_bank(iSta:iSto) - write(iulog,*) trim(methodName)//' :: spread ', & - this%spread(iSta:iSto) - write(iulog,*) trim(methodName)//' :: livegrass ', & - this%livegrass(iSta:iSto) - write(iulog,*) trim(methodName)//' :: age ', & - this%age(iSta:iSto) - write(iulog,*) trim(methodName)//' :: area ', & - this%areaRestart(iSta:iSto) - write(iulog,*) trim(methodName)//' :: f_sun ', & - this%f_sun(iSta:iSto) - write(iulog,*) trim(methodName)//' :: fabd_sun_z ', & - this%fabd_sun_z(iSta:iSto) - write(iulog,*) trim(methodName)//' :: fabi_sun_z ', & - this%fabi_sun_z(iSta:iSto) - write(iulog,*) trim(methodName)//' :: fabd_sha_z ', & - this%fabd_sha_z(iSta:iSto) - write(iulog,*) trim(methodName)//' :: fabi_sha_z ', & - this%fabi_sha_z(iSta:iSto) - write(iulog,*) trim(methodName)//' :: water_memory ', & - this%water_memory(iSta:iSto) - - write(iulog,*) trim(methodName)//' :: old_stock ', & - this%old_stock(iSta:iSta) - write(iulog,*) trim(methodName)//' :: cd_status', & - this%cd_status(iSta:iSta) - write(iulog,*) trim(methodName)//' :: dd_status', & - this%cd_status(iSta:iSto) - write(iulog,*) trim(methodName)//' :: ED_GDD_site', & - this%ED_GDD_site(iSta:iSto) - write(iulog,*) trim(methodName)//' :: ncd', & - this%ncd(iSta:iSta) - write(iulog,*) trim(methodName)//' :: leafondate', & - this%leafondate(iSta:iSta) - write(iulog,*) trim(methodName)//' :: leafoffdate', & - this%leafoffdate(iSta:iSta) - write(iulog,*) trim(methodName)//' :: dleafondate', & - this%dleafondate(iSta:iSta) - write(iulog,*) trim(methodName)//' :: dleafoffdate', & - this%dleafoffdate(iSta:iSta) - write(iulog,*) trim(methodName)//' :: acc_NI', & - this%acc_NI(iSta:iSta) - - end subroutine printDataInfoVector - - !-------------------------------------------------------------------------------! - subroutine printDataInfoLL( this, bounds, nsites, sites ) - ! - ! !DESCRIPTION: - ! counts the total number of cohorts over all p levels (ed_patch_type) so we - ! can allocate vectors, copy from LL -> vector and read/write restarts. - ! - ! !USES: - ! - ! !ARGUMENTS: - class(EDRestartVectorClass) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(in), target :: sites(nsites) - ! - ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort - integer :: s - integer :: totalCohorts - integer :: numCohort - integer :: numPatches,totPatchCount - character(len=32) :: methodName = 'printDataInfoLL ' - !----------------------------------------------------------------------- - - totalCohorts = 0 - totPatchCount = 1 - - write(iulog,*) 'vecLenStart ',this%vectorLengthStart - - do s = 1,nsites - - currentPatch => sites(s)%oldest_patch - - numPatches = 1 - - do while(associated(currentPatch)) - currentCohort => currentPatch%shortest - - numCohort = 0 - - do while(associated(currentCohort)) - - totalCohorts = totalCohorts + 1 - - write(iulog,*) trim(methodName)//' balive ' ,totalCohorts,currentCohort%balive - write(iulog,*) trim(methodName)//' bdead ' ,totalCohorts,currentCohort%bdead - write(iulog,*) trim(methodName)//' bl ' ,totalCohorts,currentCohort%bl - write(iulog,*) trim(methodName)//' br ' ,totalCohorts,currentCohort%br - write(iulog,*) trim(methodName)//' bstore ' ,totalCohorts,currentCohort%bstore - write(iulog,*) trim(methodName)//' canopy_layer ' ,totalCohorts,currentCohort%canopy_layer - write(iulog,*) trim(methodName)//' canopy_trim ' ,totalCohorts,currentCohort%canopy_trim - write(iulog,*) trim(methodName)//' dbh ' ,totalCohorts,currentCohort%dbh - write(iulog,*) trim(methodName)//' hite ' ,totalCohorts,currentCohort%hite - write(iulog,*) trim(methodName)//' laimemory ' ,totalCohorts,currentCohort%laimemory - write(iulog,*) trim(methodName)//' leaf_md ' ,totalCohorts,currentCohort%leaf_md - write(iulog,*) trim(methodName)//' root_md ' ,totalCohorts,currentCohort%root_md - write(iulog,*) trim(methodName)//' n ' ,totalCohorts,currentCohort%n - write(iulog,*) trim(methodName)//' gpp_acc ' ,totalCohorts,currentCohort%gpp_acc - write(iulog,*) trim(methodName)//' npp_acc ' ,totalCohorts,currentCohort%npp_acc - write(iulog,*) trim(methodName)//' gpp ' ,totalCohorts,currentCohort%gpp - write(iulog,*) trim(methodName)//' npp ' ,totalCohorts,currentCohort%npp - write(iulog,*) trim(methodName)//' npp_leaf ' ,totalCohorts,currentCohort%npp_leaf - write(iulog,*) trim(methodName)//' npp_froot ' ,totalCohorts,currentCohort%npp_froot - write(iulog,*) trim(methodName)//' npp_bsw ' ,totalCohorts,currentCohort%npp_bsw - write(iulog,*) trim(methodName)//' npp_bdead ' ,totalCohorts,currentCohort%npp_bdead - write(iulog,*) trim(methodName)//' npp_bseed ' ,totalCohorts,currentCohort%npp_bseed - write(iulog,*) trim(methodName)//' npp_store ' ,totalCohorts,currentCohort%npp_store - write(iulog,*) trim(methodName)//' bmort ' ,totalCohorts,currentCohort%bmort - write(iulog,*) trim(methodName)//' hmort ' ,totalCohorts,currentCohort%hmort - write(iulog,*) trim(methodName)//' cmort ' ,totalCohorts,currentCohort%cmort - write(iulog,*) trim(methodName)//' imort ' ,totalCohorts,currentCohort%imort - write(iulog,*) trim(methodName)//' fmort ' ,totalCohorts,currentCohort%fmort - write(iulog,*) trim(methodName)//' ddbhdt ' ,totalCohorts,currentCohort%ddbhdt - write(iulog,*) trim(methodName)//' resp_tstep ' ,totalCohorts,currentCohort%resp_tstep - write(iulog,*) trim(methodName)//' pft ' ,totalCohorts,currentCohort%pft - write(iulog,*) trim(methodName)//' status_coh ' ,totalCohorts,currentCohort%status_coh - write(iulog,*) trim(methodName)//' isnew ' ,totalCohorts,currentCohort%isnew - - numCohort = numCohort + 1 - - currentCohort => currentCohort%taller - enddo ! currentCohort do while - - write(iulog,*) trim(methodName)//': numpatches for col ',& - numPatches - - write(iulog,*) trim(methodName)//': patches and cohorts ',& - totPatchCount,numCohort - - write(iulog,*) trim(methodName)//' cwd_ag ' ,currentPatch%cwd_ag - write(iulog,*) trim(methodName)//' cwd_bg ' ,currentPatch%cwd_bg - write(iulog,*) trim(methodName)//' leaf_litter ' ,currentPatch%leaf_litter - write(iulog,*) trim(methodName)//' root_litter ' ,currentPatch%root_litter - write(iulog,*) trim(methodName)//' leaf_litter_in ' ,currentPatch%leaf_litter_in - write(iulog,*) trim(methodName)//' root_litter_in ' ,currentPatch%root_litter_in - write(iulog,*) trim(methodName)//' seed_bank ' ,currentPatch%seed_bank - write(iulog,*) trim(methodName)//' spread ' ,currentPatch%spread - write(iulog,*) trim(methodName)//' livegrass ' ,currentPatch%livegrass - write(iulog,*) trim(methodName)//' age ' ,currentPatch%age - write(iulog,*) trim(methodName)//' area ' ,currentPatch%area - write(iulog,*) trim(methodName)//' f_sun (sum) ' ,sum(currentPatch%f_sun) - write(iulog,*) trim(methodName)//' fabd_sun_z (sum) ' ,sum(currentPatch%fabd_sun_z) - write(iulog,*) trim(methodName)//' fabi_sun_z (sum) ' ,sum(currentPatch%fabi_sun_z) - write(iulog,*) trim(methodName)//' fabd_sha_z (sum) ' ,sum(currentPatch%fabd_sha_z) - write(iulog,*) trim(methodName)//' fabi_sha_z (sum) ' ,sum(currentPatch%fabi_sha_z) - - write(iulog,*) trim(methodName)//' old_stock ' ,sites(s)%old_stock - write(iulog,*) trim(methodName)//' cd_status ' ,sites(s)%status - write(iulog,*) trim(methodName)//' dd_status ' ,sites(s)%dstatus - write(iulog,*) trim(methodName)//' ncd ' ,sites(s)%ncd - write(iulog,*) trim(methodName)//' leafondate ' ,sites(s)%leafondate - write(iulog,*) trim(methodName)//' leafoffdate ' ,sites(s)%leafoffdate - write(iulog,*) trim(methodName)//' dleafondate ' ,sites(s)%dleafondate - write(iulog,*) trim(methodName)//' dleafoffdate ' ,sites(s)%dleafoffdate - write(iulog,*) trim(methodName)//' acc_NI' ,sites(s)%acc_NI - write(iulog,*) trim(methodName)//' ED_GDD_site ' ,sites(s)%ED_GDD_site - - currentPatch => currentPatch%younger - - totPatchCount = totPatchCount + 1 - numPatches = numPatches + 1 - enddo ! currentPatch do while - - write(iulog,*) trim(methodName)//' water_memory ',sites(s)%water_memory(1) - - enddo - - write(iulog,*) trim(methodName)//': total cohorts ',totalCohorts - - end subroutine printDataInfoLL - - !-------------------------------------------------------------------------------! - subroutine printIoInfoLL( this, bounds, nsites, sites, fcolumn ) - !! - ! !DESCRIPTION: - ! for debugging. prints some IO info regarding cohorts/patches - ! currently prints cohort level variables - ! - ! !USES: - ! - ! !ARGUMENTS: - class(EDRestartVectorClass) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(in), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - ! - ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort - integer s - integer totalCohorts - integer numCohort - integer numPatches,totPatchCount - character(len=32) :: methodName = 'printIoInfoLL ' - !----------------------------------------------------------------------- - - totalCohorts = 0 - totPatchCount = 1 - - write(iulog,*) 'vecLenStart ',this%vectorLengthStart - - do s = 1,nsites - - currentPatch => sites(s)%oldest_patch - - numPatches = 1 - - do while(associated(currentPatch)) - currentCohort => currentPatch%shortest - - write(iulog,*) trim(methodName)//': found column with patch(s) ',fcolumn(s) - - numCohort = 0 - - do while(associated(currentCohort)) - - totalCohorts = totalCohorts + 1 - numCohort = numCohort + 1 - - write(iulog,*) trim(methodName)//' balive ',numCohort,currentCohort%balive - write(iulog,*) trim(methodName)//' bdead ',currentCohort%bdead - write(iulog,*) trim(methodName)//' bl ',currentCohort%bl - write(iulog,*) trim(methodName)//' br ',currentCohort%br - write(iulog,*) trim(methodName)//' bstore ',currentCohort%bstore - write(iulog,*) trim(methodName)//' canopy_layer ',currentCohort%canopy_layer - write(iulog,*) trim(methodName)//' canopy_trim ',currentCohort%canopy_trim - write(iulog,*) trim(methodName)//' dbh ',currentCohort%dbh - write(iulog,*) trim(methodName)//' hite ',currentCohort%hite - write(iulog,*) trim(methodName)//' laimemory ',currentCohort%laimemory - write(iulog,*) trim(methodName)//' leaf_md ',currentCohort%leaf_md - write(iulog,*) trim(methodName)//' root_md ',currentCohort%root_md - write(iulog,*) trim(methodName)//' n ',currentCohort%n - write(iulog,*) trim(methodName)//' gpp_acc ',currentCohort%gpp_acc - write(iulog,*) trim(methodName)//' npp_acc ',currentCohort%npp_acc - write(iulog,*) trim(methodName)//' gpp ',currentCohort%gpp - write(iulog,*) trim(methodName)//' npp ',currentCohort%npp - write(iulog,*) trim(methodName)//' npp_leaf ',currentCohort%npp_leaf - write(iulog,*) trim(methodName)//' npp_froot ',currentCohort%npp_froot - write(iulog,*) trim(methodName)//' npp_bsw ',currentCohort%npp_bsw - write(iulog,*) trim(methodName)//' npp_bdead ',currentCohort%npp_bdead - write(iulog,*) trim(methodName)//' npp_bseed ',currentCohort%npp_bseed - write(iulog,*) trim(methodName)//' npp_store ',currentCohort%npp_store - write(iulog,*) trim(methodName)//' bmort ',currentCohort%bmort - write(iulog,*) trim(methodName)//' hmort ',currentCohort%hmort - write(iulog,*) trim(methodName)//' cmort ',currentCohort%cmort - write(iulog,*) trim(methodName)//' imort ',currentCohort%imort - write(iulog,*) trim(methodName)//' fmort ',currentCohort%fmort - write(iulog,*) trim(methodName)//' ddbhdt ',currentCohort%ddbhdt - write(iulog,*) trim(methodName)//' resp_tstep ',currentCohort%resp_tstep - write(iulog,*) trim(methodName)//' pft ',currentCohort%pft - write(iulog,*) trim(methodName)//' status_coh ',currentCohort%status_coh - write(iulog,*) trim(methodName)//' isnew ',currentCohort%isnew - - currentCohort => currentCohort%taller - enddo ! currentCohort do while - - write(iulog,*) trim(methodName)//': numpatches for column ',numPatches - write(iulog,*) trim(methodName)//': patches and cohorts ',totPatchCount,numCohort - - currentPatch => currentPatch%younger - - totPatchCount = totPatchCount + 1 - numPatches = numPatches + 1 - enddo ! currentPatch do while - enddo - - return - end subroutine printIoInfoLL - - !-------------------------------------------------------------------------------! - subroutine convertCohortListToVector( this, bounds, nsites, sites, fcolumn ) - ! - ! !DESCRIPTION: - ! counts the total number of cohorts over all p levels (ed_patch_type) so we - ! can allocate vectors, copy from LL -> vector and read/write restarts. - ! - ! !USES: - use EDTypesMod, only : cp_nclmax - ! - ! !ARGUMENTS: - class(EDRestartVectorClass) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(in), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - ! - ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch - type (ed_cohort_type), pointer :: currentCohort - integer :: s, c - integer :: totalCohorts ! number of cohorts starting from 1 - integer :: countCohort ! number of cohorts starting from - ! vectorLengthStart - integer :: numCohort - integer :: numPatches - integer :: totPatchCount, offsetTotPatchCount - integer :: countPft - integer :: countNcwd - integer :: countWaterMem - integer :: countNclmax - integer :: countSunZ - integer :: i,j,k - integer :: incrementOffset - !----------------------------------------------------------------------- - - totalCohorts = 0 - -! if(fcolumn(1).eq.bounds%begc .and. & -! (fcolumn(1)-1)*cohorts_per_col+1.ne.bounds%begCohort) then -! write(iulog,*) 'fcolumn(1) in this clump, points to the first column of the clump' -! write(iulog,*) 'but the assumption on first cohort index does not jive' -! call endrun(msg=errMsg(sourcefile, __LINE__)) -! end if - - - do s = 1,nsites - - ! Calculate the offsets - ! fcolumn is the global column index of the current site. - ! For the first site, if that site aligns with the first column index - ! in the clump, than the offset should be be equal to begCohort - - c = fcolumn(s) - -! incrementOffset = (c-1)*cohorts_per_col + 1 -! countCohort = (c-1)*cohorts_per_col + 1 -! countPft = (c-1)*cohorts_per_col + 1 -! countNcwd = (c-1)*cohorts_per_col + 1 -! countNclmax = (c-1)*cohorts_per_col + 1 -! countWaterMem = (c-1)*cohorts_per_col + 1 -! countSunZ = (c-1)*cohorts_per_col + 1 - - incrementOffset = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countCohort = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countPft = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countNcwd = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countNclmax = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countWaterMem = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countSunZ = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - - currentPatch => sites(s)%oldest_patch - - ! new column, reset num patches - numPatches = 0 - - do while(associated(currentPatch)) - - ! found patch, increment - numPatches = numPatches + 1 - - currentCohort => currentPatch%shortest - - ! new patch, reset num cohorts - numCohort = 0 - - do while(associated(currentCohort)) - - ! found cohort, increment - numCohort = numCohort + 1 - totalCohorts = totalCohorts + 1 - - if (this%DEBUG) then - write(iulog,*) 'CLTV countCohort ', countCohort - write(iulog,*) 'CLTV vecLenStart ', this%vectorLengthStart - write(iulog,*) 'CLTV vecLenStop ', this%vectorLengthStop - endif - - this%balive(countCohort) = currentCohort%balive - this%bdead(countCohort) = currentCohort%bdead - this%bl(countCohort) = currentCohort%bl - this%br(countCohort) = currentCohort%br - this%bstore(countCohort) = currentCohort%bstore - this%canopy_layer(countCohort) = currentCohort%canopy_layer - this%canopy_trim(countCohort) = currentCohort%canopy_trim - this%dbh(countCohort) = currentCohort%dbh - this%hite(countCohort) = currentCohort%hite - this%laimemory(countCohort) = currentCohort%laimemory - this%leaf_md(countCohort) = currentCohort%leaf_md - this%root_md(countCohort) = currentCohort%root_md - this%n(countCohort) = currentCohort%n - this%gpp_acc(countCohort) = currentCohort%gpp_acc - this%npp_acc(countCohort) = currentCohort%npp_acc - this%gpp(countCohort) = currentCohort%gpp - this%npp(countCohort) = currentCohort%npp - this%npp_leaf(countCohort) = currentCohort%npp_leaf - this%npp_froot(countCohort) = currentCohort%npp_froot - this%npp_bsw(countCohort) = currentCohort%npp_bsw - this%npp_bdead(countCohort) = currentCohort%npp_bdead - this%npp_bseed(countCohort) = currentCohort%npp_bseed - this%npp_store(countCohort) = currentCohort%npp_store - this%bmort(countCohort) = currentCohort%bmort - this%hmort(countCohort) = currentCohort%hmort - this%cmort(countCohort) = currentCohort%cmort - this%imort(countCohort) = currentCohort%imort - this%fmort(countCohort) = currentCohort%fmort - this%ddbhdt(countCohort) = currentCohort%ddbhdt - this%resp_tstep(countCohort) = currentCohort%resp_tstep - this%pft(countCohort) = currentCohort%pft - this%status_coh(countCohort) = currentCohort%status_coh - if ( currentCohort%isnew ) then - this%isnew(countCohort) = new_cohort - else - this%isnew(countCohort) = old_cohort - endif - - if (this%DEBUG) then - write(iulog,*) 'CLTV offsetNumCohorts II ',countCohort, & - numCohort - endif - - countCohort = countCohort + 1 - - currentCohort => currentCohort%taller - - enddo ! currentCohort do while - - ! - ! deal with patch level fields here - ! - this%livegrass(incrementOffset) = currentPatch%livegrass - this%age(incrementOffset) = currentPatch%age - this%areaRestart(incrementOffset) = currentPatch%area - - ! set cohorts per patch for IO - this%cohortsPerPatch( incrementOffset ) = numCohort - - if (this%DEBUG) then - write(iulog,*) 'offsetNumCohorts III ' & - ,countCohort,cohorts_per_col, numCohort - endif - ! - ! deal with patch level fields of arrays here - ! - ! these are arrays of length numpft_ed, each patch contains one - ! vector so we increment - do i = 1,numpft_ed - this%leaf_litter(countPft) = currentPatch%leaf_litter(i) - this%root_litter(countPft) = currentPatch%root_litter(i) - this%leaf_litter_in(countPft) = currentPatch%leaf_litter_in(i) - this%root_litter_in(countPft) = currentPatch%root_litter_in(i) - this%seed_bank(countPft) = currentPatch%seed_bank(i) - countPft = countPft + 1 - end do - - do i = 1,ncwd ! ncwd currently 4 - this%cwd_ag(countNcwd) = currentPatch%cwd_ag(i) - this%cwd_bg(countNcwd) = currentPatch%cwd_bg(i) - countNcwd = countNcwd + 1 - end do - - do i = 1,cp_nclmax ! cp_nclmax currently 2 - this%spread(countNclmax) = currentPatch%spread(i) - countNclmax = countNclmax + 1 - end do - - if (this%DEBUG) write(iulog,*) 'CLTV countSunZ 1 ',countSunZ - - if (this%DEBUG) write(iulog,*) 'CLTV 1186 ',cp_nlevcan,numpft_ed,cp_nclmax - - do k = 1,cp_nlevcan ! cp_nlevcan currently 40 - do j = 1,numpft_ed ! numpft_ed currently 2 - do i = 1,cp_nclmax ! cp_nclmax currently 2 - this%f_sun(countSunZ) = currentPatch%f_sun(i,j,k) - this%fabd_sun_z(countSunZ) = currentPatch%fabd_sun_z(i,j,k) - this%fabi_sun_z(countSunZ) = currentPatch%fabi_sun_z(i,j,k) - this%fabd_sha_z(countSunZ) = currentPatch%fabd_sha_z(i,j,k) - this%fabi_sha_z(countSunZ) = currentPatch%fabi_sha_z(i,j,k) - countSunZ = countSunZ + 1 - end do - end do - end do - - if (this%DEBUG) write(iulog,*) 'CLTV countSunZ 2 ',countSunZ - - incrementOffset = incrementOffset + numCohortsPerPatch - - ! reset counters so that they are all advanced evenly. Currently - ! the offset is 10, the max of numpft_ed, ncwd, cp_nclmax, - ! countWaterMem and the number of allowed cohorts per patch - countPft = incrementOffset - countNcwd = incrementOffset - countNclmax = incrementOffset - countCohort = incrementOffset - countSunZ = incrementOffset - - if (this%DEBUG) then - write(iulog,*) 'CLTV incrementOffset ', incrementOffset - write(iulog,*) 'CLTV cohorts_per_col ', cohorts_per_col - write(iulog,*) 'CLTV numCohort ', numCohort - write(iulog,*) 'CLTV totalCohorts ', totalCohorts - end if - - currentPatch => currentPatch%younger - - enddo ! currentPatch do while - - this%old_stock(c) = sites(s)%old_stock - this%cd_status(c) = sites(s)%status - this%dd_status(c) = sites(s)%dstatus - this%ncd(c) = sites(s)%ncd - this%leafondate(c) = sites(s)%leafondate - this%leafoffdate(c) = sites(s)%leafoffdate - this%dleafondate(c) = sites(s)%dleafondate - this%dleafoffdate(c) = sites(s)%dleafoffdate - this%acc_NI(c) = sites(s)%acc_NI - this%ED_GDD_site(c) = sites(s)%ED_GDD_site - - ! set numpatches for this column - this%numPatchesPerCol(c) = numPatches - - do i = 1,numWaterMem ! numWaterMem currently 10 - this%water_memory( countWaterMem ) = sites(s)%water_memory(i) - countWaterMem = countWaterMem + 1 - end do - - enddo - - if (this%DEBUG) then - write(iulog,*) 'CLTV total cohorts ',totalCohorts - end if - - return - end subroutine convertCohortListToVector - - !-------------------------------------------------------------------------------! - subroutine createPatchCohortStructure( this, bounds, nsites, sites, fcolumn ) - ! - ! !DESCRIPTION: - ! counts the total number of cohorts over all p levels (ed_patch_type) so we - ! can allocate vectors, copy from LL -> vector and read/write restarts. - ! - ! !USES: - use EDPatchDynamicsMod , only : zero_patch - use EDGrowthFunctionsMod, only : Dbh - use EDCohortDynamicsMod, only : create_cohort - use EDInitMod , only : zero_site - use EDParamsMod , only : ED_val_maxspread - use EDPatchDynamicsMod , only : create_patch - use GridcellType , only : grc - use ColumnType , only : col - ! - ! !ARGUMENTS: - class(EDRestartVectorClass) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - ! - ! !LOCAL VARIABLES: - type (ed_patch_type) , pointer :: newp - type(ed_cohort_type), allocatable :: temp_cohort - real(r8) :: cwd_ag_local(ncwd),cwd_bg_local(ncwd),spread_local(cp_nclmax) - real(r8) :: leaf_litter_local(numpft_ed),root_litter_local(numpft_ed) - real(r8) :: seed_bank_local(numpft_ed) - real(r8) :: age !notional age of this patch - integer :: cohortstatus - integer :: s ! site index - integer :: c ! column index - integer :: g ! grid index - integer :: patchIdx,currIdx, fto, ft - !----------------------------------------------------------------------- - - - - cwd_ag_local = 0.0_r8 !ED_val_init_litter !arbitrary value for litter pools. kgC m-2 ! - cwd_bg_local = 0.0_r8 !ED_val_init_litter - leaf_litter_local = 0.0_r8 - root_litter_local = 0.0_r8 - age = 0.0_r8 - spread_local = ED_val_maxspread - - ! - ! loop over model grid cells and create patch/cohort structure based on - ! restart data - ! - do s = 1,nsites - - c = fcolumn(s) - if( (s-1) .ne. (c-bounds%begc) ) then - write(iulog,*) 'NAT COLUMNS REALLY ARENT MONOTONICALLY INCREASING' - write(iulog,*) s,c,bounds%begc,s-1,c-bounds%begc - end if - - g = col%gridcell(c) - - currIdx = bounds%begCohort + (c-bounds%begc)*cohorts_per_col + 1 -! currIdx = (c-1)*cohorts_per_col + 1 ! global cohort index at the head of the column - - call zero_site( sites(s) ) - ! - ! set a few items that are necessary on restart for ED but not on the - ! restart file - ! - - sites(s)%lat = grc%latdeg(g) - sites(s)%lon = grc%londeg(g) - sites(s)%ncd = 0.0_r8 - - if (this%numPatchesPerCol(c)<0 .or. this%numPatchesPerCol(c)>10000) then - write(iulog,*) 'a column was expected to contain a valid number of patches' - write(iulog,*) '0 is a valid number, but this column seems uninitialized',this%numPatchesPerCol(c) - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - ! Initialize the site pointers to null - sites(s)%youngest_patch => null() - sites(s)%oldest_patch => null() - - do patchIdx = 1,this%numPatchesPerCol(c) - - if (this%DEBUG) then - write(iulog,*) 'create patch ',patchIdx - write(iulog,*) 'patchIdx 1-numCohorts : ',this%cohortsPerPatch(currIdx) - end if - - ! create patch - allocate(newp) - - ! make new patch - call create_patch(sites(s), newp, age, area, & - spread_local, cwd_ag_local, cwd_bg_local, & - leaf_litter_local, root_litter_local, seed_bank_local) - - newp%siteptr => sites(s) - - ! give this patch a unique patch number - newp%patchno = patchIdx - - do fto = 1, this%cohortsPerPatch(currIdx) - - allocate(temp_cohort) - - temp_cohort%n = 700.0_r8 - temp_cohort%balive = 0.0_r8 - temp_cohort%bdead = 0.0_r8 - temp_cohort%bstore = 0.0_r8 - temp_cohort%laimemory = 0.0_r8 - temp_cohort%canopy_trim = 0.0_r8 - temp_cohort%canopy_layer = 1.0_r8 - - ! set the pft (only 2 used in ed) based on odd/even cohort - ! number - ft=2 - if ((mod(fto, 2) == 0 )) then - ft=1 - endif - - cohortstatus = newp%siteptr%status - - if(pftcon%stress_decid(ft) == 1)then !drought decidous, override status. - cohortstatus = newp%siteptr%dstatus - endif - - temp_cohort%hite = 1.25_r8 - ! the dbh function should only take as an argument, the one - ! item it needs, not the entire cohort...refactor - temp_cohort%dbh = Dbh(temp_cohort) + 0.0001_r8*ft - - write(iulog,*) 'EDRestVectorMod.F90::createPatchCohortStructure call create_cohort ' - - call create_cohort(newp, ft, temp_cohort%n, temp_cohort%hite, temp_cohort%dbh, & - temp_cohort%balive, temp_cohort%bdead, temp_cohort%bstore, & - temp_cohort%laimemory, cohortstatus, temp_cohort%canopy_trim, newp%NCL_p) - - deallocate(temp_cohort) - - enddo ! ends loop over fto - - ! - ! insert this patch with cohorts into the site pointer. At this - ! point just insert the new patch in the youngest position - ! - if (patchIdx == 1) then ! nothing associated yet. first patch is pointed to by youngest and oldest - - if (this%DEBUG) write(iulog,*) 'patchIdx = 1 ',patchIdx - - sites(s)%youngest_patch => newp - sites(s)%oldest_patch => newp - sites(s)%youngest_patch%younger => null() - sites(s)%youngest_patch%older => null() - sites(s)%oldest_patch%younger => null() - sites(s)%oldest_patch%older => null() - - else if (patchIdx == 2) then ! add second patch to list - - if (this%DEBUG) write(iulog,*) 'patchIdx = 2 ',patchIdx - - sites(s)%youngest_patch => newp - sites(s)%youngest_patch%younger => null() - sites(s)%youngest_patch%older => sites(s)%oldest_patch - sites(s)%oldest_patch%younger => sites(s)%youngest_patch - sites(s)%oldest_patch%older => null() - - else ! more than 2 patches, insert patch into youngest slot - - if (this%DEBUG) write(iulog,*) 'patchIdx > 2 ',patchIdx - - newp%older => sites(s)%youngest_patch - sites(s)%youngest_patch%younger => newp - newp%younger => null() - sites(s)%youngest_patch => newp - - endif - - currIdx = currIdx + numCohortsPerPatch - - enddo ! ends loop over patchIdx - - enddo ! ends loop over s - - end subroutine createPatchCohortStructure - - !-------------------------------------------------------------------------------! - subroutine convertCohortVectorToList( this, bounds, nsites, sites, fcolumn ) - ! - ! !DESCRIPTION: - ! counts the total number of cohorts over all p levels (ed_patch_type) so we - ! can allocate vectors, copy from LL -> vector and read/write restarts. - ! - ! !USES: - ! - ! !ARGUMENTS: - class(EDRestartVectorClass) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) - integer , intent(in) :: fcolumn(nsites) - - ! - ! !LOCAL VARIABLES: - type (ed_patch_type), pointer :: currentPatch - type (ed_cohort_type),pointer :: currentCohort - integer :: c, s - integer :: totalCohorts ! number of cohorts starting from 0 - integer :: countCohort ! number of cohorts starting from - ! vectorLengthStart - integer :: numCohort - integer :: numPatches - integer :: countPft - integer :: countNcwd - integer :: countWaterMem - integer :: countNclmax - integer :: countSunZ - integer :: i,j,k - integer :: incrementOffset - !----------------------------------------------------------------------- - - totalCohorts = 0 - - do s = 1,nsites - - c = fcolumn(s) - - incrementOffset = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - - countCohort = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countPft = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countNcwd = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countNclmax = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countWaterMem = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - countSunZ = bounds%begCohort+(c-bounds%begc)*cohorts_per_col + 1 - - currentPatch => sites(s)%oldest_patch - - ! new grid cell, reset num patches - numPatches = 0 - - do while(associated(currentPatch)) - - ! found patch, increment - numPatches = numPatches + 1 - - currentCohort => currentPatch%shortest - - ! new patch, reset num cohorts - numCohort = 0 - - do while(associated(currentCohort)) - - ! found cohort, increment - numCohort = numCohort + 1 - totalCohorts = totalCohorts + 1 - - if (this%DEBUG) then - write(iulog,*) 'CVTL countCohort ',countCohort, this%vectorLengthStart, this%vectorLengthStop - endif - - currentCohort%balive = this%balive(countCohort) - currentCohort%bdead = this%bdead(countCohort) - currentCohort%bl = this%bl(countCohort) - currentCohort%br = this%br(countCohort) - currentCohort%bstore = this%bstore(countCohort) - currentCohort%canopy_layer = this%canopy_layer(countCohort) - currentCohort%canopy_trim = this%canopy_trim(countCohort) - currentCohort%dbh = this%dbh(countCohort) - currentCohort%hite = this%hite(countCohort) - currentCohort%laimemory = this%laimemory(countCohort) - currentCohort%leaf_md = this%leaf_md(countCohort) - currentCohort%root_md = this%root_md(countCohort) - currentCohort%n = this%n(countCohort) - currentCohort%gpp_acc = this%gpp_acc(countCohort) - currentCohort%npp_acc = this%npp_acc(countCohort) - currentCohort%gpp = this%gpp(countCohort) - currentCohort%npp = this%npp(countCohort) - currentCohort%npp_leaf = this%npp_leaf(countCohort) - currentCohort%npp_froot = this%npp_froot(countCohort) - currentCohort%npp_bsw = this%npp_bsw(countCohort) - currentCohort%npp_bdead = this%npp_bdead(countCohort) - currentCohort%npp_bseed = this%npp_bseed(countCohort) - currentCohort%npp_store = this%npp_store(countCohort) - currentCohort%bmort = this%bmort(countCohort) - currentCohort%hmort = this%hmort(countCohort) - currentCohort%cmort = this%cmort(countCohort) - currentCohort%imort = this%imort(countCohort) - currentCohort%fmort = this%fmort(countCohort) - currentCohort%ddbhdt = this%ddbhdt(countCohort) - currentCohort%resp_tstep = this%resp_tstep(countCohort) - currentCohort%pft = this%pft(countCohort) - currentCohort%status_coh = this%status_coh(countCohort) - currentCohort%isnew = ( this%isnew(countCohort) .eq. new_cohort ) - - if (this%DEBUG) then - write(iulog,*) 'CVTL II ',countCohort, & - numCohort - endif - - countCohort = countCohort + 1 - - currentCohort => currentCohort%taller - - enddo ! current cohort do while - - - ! FIX(SPM,032414) move to init if you can...or make a new init function - currentPatch%leaf_litter(:) = 0.0_r8 - currentPatch%root_litter(:) = 0.0_r8 - currentPatch%leaf_litter_in(:) = 0.0_r8 - currentPatch%root_litter_in(:) = 0.0_r8 - currentPatch%seed_bank(:) = 0.0_r8 - currentPatch%spread(:) = 0.0_r8 - - ! - ! deal with patch level fields here - ! - currentPatch%livegrass = this%livegrass(incrementOffset) - currentPatch%age = this%age(incrementOffset) - currentPatch%area = this%areaRestart(incrementOffset) - - - - ! set cohorts per patch for IO - - if (this%DEBUG) then - write(iulog,*) 'CVTL III ' & - ,countCohort,cohorts_per_col, numCohort - endif - ! - ! deal with patch level fields of arrays here - ! - ! these are arrays of length numpft_ed, each patch contains one - ! vector so we increment - do i = 1,numpft_ed ! numpft_ed currently 2 - currentPatch%leaf_litter(i) = this%leaf_litter(countPft) - currentPatch%root_litter(i) = this%root_litter(countPft) - currentPatch%leaf_litter_in(i) = this%leaf_litter_in(countPft) - currentPatch%root_litter_in(i) = this%root_litter_in(countPft) - currentPatch%seed_bank(i) = this%seed_bank(countPft) - countPft = countPft + 1 - end do - - do i = 1,ncwd ! ncwd currently 4 - currentPatch%cwd_ag(i) = this%cwd_ag(countNcwd) - currentPatch%cwd_bg(i) = this%cwd_bg(countNcwd) - countNcwd = countNcwd + 1 - end do - - do i = 1,cp_nclmax ! cp_nclmax currently 2 - currentPatch%spread(i) = this%spread(countNclmax) - countNclmax = countNclmax + 1 - end do - - if (this%DEBUG) write(iulog,*) 'CVTL countSunZ 1 ',countSunZ - - do k = 1,cp_nlevcan ! cp_nlevcan currently 40 - do j = 1,numpft_ed ! numpft_ed currently 2 - do i = 1,cp_nclmax ! cp_nclmax currently 2 - currentPatch%f_sun(i,j,k) = this%f_sun(countSunZ) - currentPatch%fabd_sun_z(i,j,k) = this%fabd_sun_z(countSunZ) - currentPatch%fabi_sun_z(i,j,k) = this%fabi_sun_z(countSunZ) - currentPatch%fabd_sha_z(i,j,k) = this%fabd_sha_z(countSunZ) - currentPatch%fabi_sha_z(i,j,k) = this%fabi_sha_z(countSunZ) - countSunZ = countSunZ + 1 - end do - end do - end do - - if (this%DEBUG) write(iulog,*) 'CVTL countSunZ 2 ',countSunZ - - incrementOffset = incrementOffset + numCohortsPerPatch - - ! and the number of allowed cohorts per patch (currently 200) - countPft = incrementOffset - countNcwd = incrementOffset - countNclmax = incrementOffset - countCohort = incrementOffset - countSunZ = incrementOffset - - if (this%DEBUG) then - write(iulog,*) 'CVTL incrementOffset ', incrementOffset - write(iulog,*) 'CVTL cohorts_per_col ', cohorts_per_col - write(iulog,*) 'CVTL numCohort ', numCohort - write(iulog,*) 'CVTL totalCohorts ', totalCohorts - end if - - currentPatch => currentPatch%younger - - enddo ! currentPatch do while - - do i = 1,numWaterMem - sites(s)%water_memory(i) = this%water_memory( countWaterMem ) - countWaterMem = countWaterMem + 1 - end do - - sites(s)%old_stock = this%old_stock(c) - sites(s)%status = this%cd_status(c) - sites(s)%dstatus = this%dd_status(c) - sites(s)%ncd = this%ncd(c) - sites(s)%leafondate = this%leafondate(c) - sites(s)%leafoffdate = this%leafoffdate(c) - sites(s)%dleafondate = this%dleafondate(c) - sites(s)%dleafoffdate = this%dleafoffdate(c) - sites(s)%acc_NI = this%acc_NI(c) - sites(s)%ED_GDD_site = this%ED_GDD_site(c) - - enddo - - if (this%DEBUG) then - write(iulog,*) 'CVTL total cohorts ',totalCohorts - end if - - end subroutine convertCohortVectorToList - - !--------------------------------------------! - ! Non Type-Bound Procedures Here: - !--------------------------------------------! - - !-------------------------------------------------------------------------------! - subroutine EDRest ( bounds, nsites, sites, fcolumn, ncid, flag ) - ! - ! !DESCRIPTION: - ! Read/write ED restart data - ! EDRest called from restFileMod.F90 - ! - ! !USES: - - use ncdio_pio , only : file_desc_t - use EDCLMLinkMod , only : ed_clm_type - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds ! bounds - type(file_desc_t) , intent(inout) :: ncid ! netcdf id - integer , intent(in) :: nsites - type(ed_site_type) , intent(inout), target :: sites(nsites) ! The site vector - integer , intent(in) :: fcolumn(nsites) - character(len=*) , intent(in) :: flag !'read' or 'write' - ! - ! !LOCAL VARIABLES: - type(EDRestartVectorClass) :: ervc - - !----------------------------------------------------------------------- - ! - ! Note: ed_allsites_inst already exists and is allocated in clm_instInit - ! - - ervc = newEDRestartVectorClass( bounds ) - - if (ervc%DEBUG) then - write(iulog,*) 'EDRestVectorMod:EDRest flag ',flag - end if - - if ( flag == 'write' ) then - call ervc%setVectors( bounds, nsites, sites, fcolumn ) - endif - - call ervc%doVectorIO( ncid, flag ) - - if ( flag == 'read' ) then - call ervc%getVectors( bounds, nsites, sites, fcolumn ) - endif - - call ervc%deleteEDRestartVectorClass () - - end subroutine EDRest - -end module EDRestVectorMod diff --git a/src/ED/main/EDTypesMod.F90 b/src/ED/main/EDTypesMod.F90 deleted file mode 100755 index ca11fa8a32..0000000000 --- a/src/ED/main/EDTypesMod.F90 +++ /dev/null @@ -1,591 +0,0 @@ -module EDTypesMod - - use shr_kind_mod , only : r8 => shr_kind_r8; - use decompMod , only : bounds_type - use clm_varpar , only : nlevgrnd, mxpft - use domainMod , only : domain_type - use shr_sys_mod , only : shr_sys_flush - - implicit none - save - - !SWITCHES THAT ARE READ IN - integer RESTART ! restart flag, 1= read initial system state 0 = bare ground - - ! MODEL PARAMETERS - real(r8) :: timestep_secs ! subdaily timestep in seconds (e.g. 1800 or 3600) - - real(r8), parameter :: AREA = 10000.0_r8 ! Notional area of simulated forest m2 - integer doy - - integer, parameter :: invalidValue = -9999 ! invalid value for gcells, - ! cohorts, and patches - - ! for setting number of patches per gridcell and number of cohorts per patch - ! for I/O and converting to a vector - - integer, parameter :: numPatchesPerCol = 10 ! - integer, parameter :: numCohortsPerPatch = 160 ! - integer, parameter :: cohorts_per_col = 1600 ! This is the max number of individual items one can store per - - ! each grid cell and effects the striding in the ED restart - ! data as some fields are arrays where each array is - ! associated with one cohort - - integer, parameter :: numWaterMem = 10 ! watermemory saved as site level var - - ! BIOLOGY/BIOGEOCHEMISTRY - integer , parameter :: INTERNAL_RECRUITMENT = 1 ! internal recruitment fla 1=yes - integer , parameter :: EXTERNAL_RECRUITMENT = 0 ! external recruitment flag 1=yes - integer , parameter :: SENES = 10 ! Window of time over which we track temp for cold sensecence (days) - real(r8), parameter :: DINC_ED = 1.0_r8 ! size of LAI bins. - integer , parameter :: N_DIST_TYPES = 2 ! number of disturbance types (mortality, fire) - integer , parameter :: numpft_ed = 2 ! number of PFTs used in ED. - integer , parameter :: maxPft = 79 ! max number of PFTs potentially used by CLM - - - ! SPITFIRE - integer , parameter :: NLSC = 6 ! number carbon compartments in above ground litter array - integer , parameter :: NFSC = 6 ! number fuel size classes - integer , parameter :: N_EF = 7 ! number of emission factors. One per trace gas or aerosol species. - integer, parameter :: NCWD = 4 ! number of coarse woody debris pools - integer, parameter :: lg_sf = 6 ! array index of live grass pool for spitfire - integer, parameter :: dg_sf = 1 ! array index of dead grass pool for spitfire - integer, parameter :: tr_sf = 5 ! array index of dead trunk pool for spitfire - integer, parameter :: lb_sf = 4 ! array index of lrge branch pool for spitfire - real(r8), parameter :: fire_threshold = 35.0_r8 ! threshold for fires that spread or go out. KWm-2 - - ! COHORT FUSION - real(r8), parameter :: FUSETOL = 0.6_r8 ! min fractional difference in dbh between cohorts - - ! PATCH FUSION - real(r8), parameter :: NTOL = 0.05_r8 ! min plant density for hgt bin to be used in height profile comparisons - real(r8), parameter :: HITEMAX = 30.0_r8 ! max dbh value used in hgt profile comparison - real(r8), parameter :: DBHMAX = 150.0_r8 ! max dbh value used in hgt profile comparison - integer , parameter :: N_HITE_BINS = 60 ! no. of hite bins used to distribute LAI - integer , parameter :: N_DBH_BINS = 5 ! no. of dbh bins used when comparing patches - - - real(r8), parameter :: min_npm2 = 1.0d-5 ! minimum cohort number density per m2 before termination - real(r8), parameter :: min_patch_area = 0.001_r8 ! smallest allowable patch area before termination - real(r8), parameter :: min_nppatch = 1.0d-8 ! minimum number of cohorts per patch (min_npm2*min_patch_area) - real(r8), parameter :: min_n_safemath = 1.0d-15 ! in some cases, we want to immediately remove super small - ! number densities of cohorts to prevent FPEs, this is usually - ! just relevant in the first day after recruitment - - character*4 yearchar - - !the lower limit of the size classes of ED cohorts - !0-10,10-20... - integer, parameter :: nlevsclass_ed = 13 ! Number of dbh size classes for size structure analysis - ! |0-1,1-2,2-3,3-4,4-5,5-10,10-20,20-30,30-40,40-50,50-60,60-70,70-80,80-90,90-100,100+| -! real(r8), parameter, dimension(16) :: sclass_ed = (/0.0_r8,1.0_r8,2.0_r8,3.0_r8,4.0_r8,5.0_r8,10.0_r8,20.0_r8,30.0_r8,40.0_r8, & -! 50.0_r8,60.0_r8,70.0_r8,80.0_r8,90.0_r8,100.0_r8/) - - real(r8), parameter, dimension(13) :: sclass_ed = (/0.0_r8,5.0_r8,10.0_r8,15.0_r8,20.0_r8,30.0_r8,40.0_r8, & - 50.0_r8,60.0_r8,70.0_r8,80.0_r8,90.0_r8,100.0_r8/) - - - ! integer, parameter :: nlevsclass_ed = 17 - ! real(r8), parameter, dimension(17) :: sclass_ed = (/0.1_r8, 5.0_r8,10.0_r8,15.0_r8,20.0_r8,25.0_r8, & - ! 30.0_r8,35.0_r8,40.0_r8,45.0_r8,50.0_r8,55.0_r8, & - ! 60.0_r8,65.0_r8,70.0_r8,75.0_r8,80.0_r8/) - - integer, parameter :: nlevmclass_ed = 5 ! nlev "mortality" classes in ED - ! Number of ways to die - ! (background,hydraulic,carbon,impact,fire) - - character(len = 10), parameter,dimension(5) :: char_list = (/"background","hydraulic ","carbon ","impact ","fire "/) - - - ! These three vectors are used for history output mapping - real(r8) ,allocatable :: levsclass_ed(:) ! The lower bound on size classes for ED trees. This - ! is used really for IO into the - ! history tapes. It gets copied from - ! the parameter array sclass_ed. - integer , allocatable :: pft_levscpf_ed(:) - integer , allocatable :: scls_levscpf_ed(:) - - - ! Control Parameters (cp_) - ! ------------------------------------------------------------------------------------- - - ! These parameters are dictated by FATES internals - - integer, parameter :: cp_nclmax = 2 ! Maximum number of canopy layers - - integer, parameter :: cp_nlevcan = 40 ! number of leaf layers in canopy layer - - integer, parameter :: cp_maxSWb = 2 ! maximum number of broad-bands in the - ! shortwave spectrum cp_numSWb <= cp_maxSWb - ! this is just for scratch-array purposes - ! if cp_numSWb is larger than this value - ! simply bump this number up as needed - ! These parameters are dictated by the host model or driver - - integer :: cp_numSWb ! Number of broad-bands in the short-wave radiation - ! specturm to track - ! (typically 2 as a default, VIS/NIR, in ED variants <2016) - - - integer :: cp_numlevgrnd ! Number of soil layers - - ! Number of GROUND layers for the purposes of biogeochemistry; can be either 1 - ! or the total number of soil layers (includes bedrock) - integer :: cp_numlevdecomp_full - - ! Number of SOIL layers for the purposes of biogeochemistry; can be either 1 - ! or the total number of soil layers - integer :: cp_numlevdecomp - - - !************************************ - !** COHORT type structure ** - !************************************ - type ed_cohort_type - - ! POINTERS - type (ed_cohort_type) , pointer :: taller => null() ! pointer to next tallest cohort - type (ed_cohort_type) , pointer :: shorter => null() ! pointer to next shorter cohort - type (ed_patch_type) , pointer :: patchptr => null() ! pointer to patch that cohort is in - type (ed_site_type) , pointer :: siteptr => null() ! pointer to site that cohort is in - - ! VEGETATION STRUCTURE - integer :: pft ! pft number - real(r8) :: n ! number of individuals in cohort per 'area' (10000m2 default) - real(r8) :: dbh ! dbh: cm - real(r8) :: hite ! height: meters - integer :: indexnumber ! unique number for each cohort. (within clump?) - real(r8) :: balive ! total living biomass: kGC per indiv - real(r8) :: bdead ! dead biomass: kGC per indiv - real(r8) :: bstore ! stored carbon: kGC per indiv - real(r8) :: laimemory ! target leaf biomass- set from previous year: kGC per indiv - integer :: canopy_layer ! canopy status of cohort (1 = canopy, 2 = understorey, etc.) - real(r8) :: b ! total biomass: kGC per indiv - real(r8) :: bsw ! sapwood in stem and roots: kGC per indiv - real(r8) :: bl ! leaf biomass: kGC per indiv - real(r8) :: br ! fine root biomass: kGC per indiv - real(r8) :: lai ! leaf area index of cohort m2/m2 - real(r8) :: sai ! stem area index of cohort m2/m2 - real(r8) :: gscan ! Stomatal resistance of cohort. - real(r8) :: canopy_trim ! What is the fraction of the maximum leaf biomass that we are targeting? :- - real(r8) :: leaf_cost ! How much does it cost to maintain leaves: kgC/m2/year-1 - real(r8) :: excl_weight ! How much of this cohort is demoted each year, as a proportion of all cohorts:- - real(r8) :: prom_weight ! How much of this cohort is promoted each year, as a proportion of all cohorts:- - integer :: nv ! Number of leaf layers: - - integer :: status_coh ! growth status of plant (2 = leaves on , 1 = leaves off) - real(r8) :: c_area ! areal extent of canopy (m2) - real(r8) :: treelai ! lai of tree (total leaf area (m2) / canopy area (m2) - real(r8) :: treesai ! stem area index of tree (total stem area (m2) / canopy area (m2) - logical :: isnew ! flag to signify a new cohort, new cohorts have not experienced - ! npp or mortality and should therefore not be fused or averaged - - ! CARBON FLUXES - real(r8) :: gpp ! GPP: kgC/indiv/year - real(r8) :: gpp_acc ! GPP: kgC/indiv/day - real(r8) :: gpp_tstep ! GPP: kgC/indiv/timestep - real(r8) :: npp ! NPP: kgC/indiv/year - real(r8) :: npp_acc ! NPP: kgC/indiv/day - real(r8) :: npp_tstep ! NPP: kgC/indiv/timestep - real(r8) :: resp ! Resp: kgC/indiv/year - real(r8) :: resp_acc ! Resp: kgC/indiv/day - real(r8) :: resp_tstep ! Resp: kgC/indiv/timestep - - real(r8) :: npp_leaf ! NPP into leaves (includes replacement of turnover): KgC/indiv/day - real(r8) :: npp_froot ! NPP into fine roots (includes replacement of turnover): KgC/indiv/day - real(r8) :: npp_bsw ! NPP into sapwood: KgC/indiv/day - real(r8) :: npp_bdead ! NPP into deadwood (structure): KgC/indiv/day - real(r8) :: npp_bseed ! NPP into seeds: KgC/indiv/day - real(r8) :: npp_store ! NPP into storage: KgC/indiv/day - - real(r8) :: ts_net_uptake(cp_nlevcan) ! Net uptake of leaf layers: kgC/m2/s - real(r8) :: year_net_uptake(cp_nlevcan) ! Net uptake of leaf layers: kgC/m2/year - - ! RESPIRATION COMPONENTS - real(r8) :: rd ! Dark respiration: umol/indiv/s - real(r8) :: resp_g ! Growth respiration: kgC/indiv/timestep - real(r8) :: resp_m ! Maintenance respiration: kgC/indiv/timestep - real(r8) :: livestem_mr ! Live stem maintenance respiration: kgC/indiv/s - real(r8) :: livecroot_mr ! Live coarse root maintenance respiration: kgC/indiv/s - real(r8) :: froot_mr ! Live fine root maintenance respiration: kgC/indiv/s - - ! ALLOCATION - real(r8) :: md ! plant maintenance demand: kgC/indiv/year - real(r8) :: leaf_md ! leaf maintenance demand: kgC/indiv/year - real(r8) :: root_md ! root maintenance demand: kgC/indiv/year - real(r8) :: carbon_balance ! carbon remaining for growth and storage: kg/indiv/year - real(r8) :: seed_prod ! reproduction seed and clonal: KgC/indiv/year - real(r8) :: leaf_litter ! leaf litter from phenology: KgC/m2 - real(r8) :: woody_turnover ! amount of wood lost each day: kgC/indiv/year. Currently set to zero. - - !MORTALITY - real(r8) :: dmort ! proportional mortality rate. (year-1) - - ! Mortality Rate Partitions - real(r8) :: bmort ! background mortality rate n/year - real(r8) :: cmort ! carbon starvation mortality rate n/year - real(r8) :: hmort ! hydraulic failure mortality rate n/year - real(r8) :: imort ! mortality from impacts by others n/year - real(r8) :: fmort ! fire mortality n/year - - ! NITROGEN POOLS - real(r8) :: livestemn ! live stem nitrogen : KgN/invid - real(r8) :: livecrootn ! live coarse root nitrogen: KgN/invid - real(r8) :: frootn ! fine root nitrogen : KgN/invid - - ! GROWTH DERIVIATIVES - real(r8) :: dndt ! time derivative of cohort size : n/year - real(r8) :: dhdt ! time derivative of height : m/year - real(r8) :: ddbhdt ! time derivative of dbh : cm/year - real(r8) :: dbalivedt ! time derivative of total living biomass : KgC/year - real(r8) :: dbdeaddt ! time derivative of dead biomass : KgC/year - real(r8) :: dbstoredt ! time derivative of stored biomass : KgC/year - real(r8) :: storage_flux ! flux from npp into bstore : KgC/year - - ! FIRE - real(r8) :: cfa ! proportion of crown affected by fire:- - real(r8) :: cambial_mort ! probability that trees dies due to cambial char:- - real(r8) :: crownfire_mort ! probability of tree post-fire mortality due to crown scorch:- - real(r8) :: fire_mort ! post-fire mortality from cambial and crown damage assuming two are independent:- - - end type ed_cohort_type - - !************************************ - !** Patch type structure ** - !************************************ - - type ed_patch_type - - ! POINTERS - type (ed_cohort_type), pointer :: tallest => null() ! pointer to patch's tallest cohort - type (ed_cohort_type), pointer :: shortest => null() ! pointer to patch's shortest cohort - type (ed_patch_type), pointer :: older => null() ! pointer to next older patch - type (ed_patch_type), pointer :: younger => null() ! pointer to next younger patch - type (ed_site_type), pointer :: siteptr => null() ! pointer to the site that the patch is in - - !INDICES - integer :: patchno ! unique number given to each new patch created for tracking - - ! INTERF-TODO: THIS VARIABLE SHOULD BE REMOVED - integer :: clm_pno ! clm patch number (index of p vector) - - ! PATCH INFO - real(r8) :: age ! average patch age: years - real(r8) :: area ! patch area: m2 - integer :: countcohorts ! Number of cohorts in patch - integer :: ncl_p ! Number of occupied canopy layers - - ! LEAF ORGANIZATION - real(r8) :: spread(cp_nclmax) ! dynamic ratio of dbh to canopy area: cm/m2 - real(r8) :: pft_agb_profile(numpft_ed,n_dbh_bins) ! binned above ground biomass, for patch fusion: KgC/m2 - real(r8) :: canopy_layer_lai(cp_nclmax) ! lai that is shading this canopy layer: m2/m2 - real(r8) :: total_canopy_area ! area that is covered by vegetation : m2 - real(r8) :: total_tree_area ! area that is covered by woody vegetation : m2 - real(r8) :: canopy_area ! area that is covered by vegetation : m2 (is this different to total_canopy_area? - real(r8) :: bare_frac_area ! bare soil in this patch expressed as a fraction of the total soil surface. - real(r8) :: lai ! leaf area index of patch - - real(r8) :: tlai_profile(cp_nclmax,numpft_ed,cp_nlevcan) ! total leaf area in each canopy layer, pft, and leaf layer. m2/m2 - real(r8) :: elai_profile(cp_nclmax,numpft_ed,cp_nlevcan) ! exposed leaf area in each canopy layer, pft, and leaf layer. m2/m2 - real(r8) :: tsai_profile(cp_nclmax,numpft_ed,cp_nlevcan) ! total stem area in each canopy layer, pft, and leaf layer. m2/m2 - real(r8) :: esai_profile(cp_nclmax,numpft_ed,cp_nlevcan) ! exposed stem area in each canopy layer, pft, and leaf layer. m2/m2 - real(r8) :: layer_height_profile(cp_nclmax,numpft_ed,cp_nlevcan) - real(r8) :: canopy_area_profile(cp_nclmax,numpft_ed,cp_nlevcan) ! fraction of canopy in each canopy - ! layer, pft, and leaf layer:- - integer :: present(cp_nclmax,numpft_ed) ! is there any of this pft in this canopy layer? - integer :: nrad(cp_nclmax,numpft_ed) ! number of exposed leaf layers for each canopy layer and pft - integer :: ncan(cp_nclmax,numpft_ed) ! number of total leaf layers for each canopy layer and pft - - !RADIATION FLUXES - real(r8) :: fabd_sun_z(cp_nclmax,numpft_ed,cp_nlevcan) ! sun fraction of direct light absorbed by each canopy - ! layer, pft, and leaf layer:- - real(r8) :: fabd_sha_z(cp_nclmax,numpft_ed,cp_nlevcan) ! shade fraction of direct light absorbed by each canopy - ! layer, pft, and leaf layer:- - real(r8) :: fabi_sun_z(cp_nclmax,numpft_ed,cp_nlevcan) ! sun fraction of indirect light absorbed by each canopy - ! layer, pft, and leaf layer:- - real(r8) :: fabi_sha_z(cp_nclmax,numpft_ed,cp_nlevcan) ! shade fraction of indirect light absorbed by each canopy - ! layer, pft, and leaf layer:- - - real(r8) :: ed_laisun_z(cp_nclmax,numpft_ed,cp_nlevcan) ! amount of LAI in the sun in each canopy layer, - ! pft, and leaf layer. m2/m2 - real(r8) :: ed_laisha_z(cp_nclmax,numpft_ed,cp_nlevcan) ! amount of LAI in the shade in each canopy layer, - real(r8) :: ed_parsun_z(cp_nclmax,numpft_ed,cp_nlevcan) ! PAR absorbed in the sun in each canopy layer, - real(r8) :: ed_parsha_z(cp_nclmax,numpft_ed,cp_nlevcan) ! PAR absorbed in the shade in each canopy layer, - real(r8) :: f_sun(cp_nclmax,numpft_ed,cp_nlevcan) ! fraction of leaves in the sun in each canopy layer, pft, - - ! and leaf layer. m2/m2 - real(r8),allocatable :: tr_soil_dir(:) ! fraction of incoming direct radiation that (cm_numSWb) - ! is transmitted to the soil as direct - real(r8),allocatable :: tr_soil_dif(:) ! fraction of incoming diffuse radiation that - ! is transmitted to the soil as diffuse - real(r8),allocatable :: tr_soil_dir_dif(:) ! fraction of incoming direct radiation that - ! is transmitted to the soil as diffuse - real(r8),allocatable :: fab(:) ! fraction of incoming total radiation that is absorbed by the canopy - real(r8),allocatable :: fabd(:) ! fraction of incoming direct radiation that is absorbed by the canopy - real(r8),allocatable :: fabi(:) ! fraction of incoming diffuse radiation that is absorbed by the canopy - real(r8),allocatable :: sabs_dir(:) ! fraction of incoming direct radiation that is absorbed by the canopy - real(r8),allocatable :: sabs_dif(:) ! fraction of incoming diffuse radiation that is absorbed by the canopy - - - !SEED BANK - real(r8) :: seed_bank(numpft_ed) ! seed pool in KgC/m2/year - real(r8) :: seeds_in(numpft_ed) ! seed production KgC/m2/year - real(r8) :: seed_decay(numpft_ed) ! seed decay in KgC/m2/year - real(r8) :: seed_germination(numpft_ed) ! germination rate of seed pool in KgC/m2/year - real(r8) :: dseed_dt(numpft_ed) - real(r8) :: seed_rain_flux(numpft_ed) ! flux of seeds from exterior KgC/m2/year (needed for C balance purposes) - - ! PHOTOSYNTHESIS - real(r8) :: psn_z(cp_nclmax,numpft_ed,cp_nlevcan) ! carbon assimilation in each canopy layer, pft, and leaf layer. umolC/m2/s - real(r8) :: gpp ! total patch gpp: KgC/m2/year - real(r8) :: npp ! total patch npp: KgC/m2/year - - ! ROOTS - real(r8), allocatable :: rootfr_ft(:,:) ! root fraction of each PFT in each soil layer:- - real(r8), allocatable :: rootr_ft(:,:) ! fraction of water taken from each PFT and soil layer:- - real(r8) :: btran_ft(numpft_ed) ! btran calculated seperately for each PFT:- - - ! DISTURBANCE - real(r8) :: disturbance_rates(n_dist_types) ! disturbance rate from 1) mortality and 2) fire: fraction/day - real(r8) :: disturbance_rate ! larger effective disturbance rate: fraction/day - - ! LITTER AND COARSE WOODY DEBRIS - ! Pools of litter (non respiring) - real(r8) :: cwd_ag(ncwd) ! above ground coarse wood debris litter that does not respire. KgC/m2 - real(r8) :: cwd_bg(ncwd) ! below ground coarse wood debris litter that does not respire. KgC/m2 - real(r8) :: leaf_litter(numpft_ed) ! above ground leaf litter that does not respire. KgC/m2 - real(r8) :: root_litter(numpft_ed) ! below ground fine root litter that does not respire. KgC/m2 - - ! Fluxes of litter (non respiring) - real(r8) :: fragmentation_scaler ! Scale rate of litter fragmentation. 0 to 1. - real(r8) :: cwd_ag_in(ncwd) ! Flux into CWD_AG from turnover and mortality KgC/m2/y - real(r8) :: cwd_bg_in(ncwd) ! Flux into cwd_bg from root turnover and mortality KgC/m2/y - real(r8) :: cwd_ag_out(ncwd) ! Flux out of AG CWD into AG litter KgC/m2/y - real(r8) :: cwd_bg_out(ncwd) ! Flux out of BG CWD into BG litter KgC/m2/ - - - real(r8) :: leaf_litter_in(numpft_ed) ! Flux in to AG leaf litter from leaf turnover and mortality KgC/m2/y - real(r8) :: leaf_litter_out(numpft_ed) ! Flux out of AG leaf litter from fragmentation KgC/m2/y - real(r8) :: root_litter_in(numpft_ed) ! Flux in to BG root litter from leaf turnover and mortality KgC/m2/y - real(r8) :: root_litter_out(numpft_ed) ! Flux out of BG root from fragmentation KgC/m2/y - - ! Derivatives of litter (non respiring) - real(r8) :: dcwd_AG_dt(ncwd) ! rate of change of above ground CWD in each size class: KgC/m2/year. - real(r8) :: dcwd_BG_dt(ncwd) ! rate of change of below ground CWD in each size class: KgC/m2/year. - real(r8) :: dleaf_litter_dt(numpft_ed) ! rate of change of leaf litter in each size class: KgC/m2/year. - real(r8) :: droot_litter_dt(numpft_ed) ! rate of change of root litter in each size class: KgC/m2/year. - - real(r8) :: canopy_mortality_woody_litter ! flux of wood litter in to litter pool: KgC/m2/year - real(r8) :: canopy_mortality_leaf_litter(numpft_ed) ! flux in to leaf litter from tree death: KgC/m2/year - real(r8) :: canopy_mortality_root_litter(numpft_ed) ! flux in to froot litter from tree death: KgC/m2/year - - real(r8) :: repro(numpft_ed) ! allocation to reproduction per PFT : KgC/m2 - - !FUEL CHARECTERISTICS - real(r8) :: sum_fuel ! total ground fuel related to ros (omits 1000hr fuels): KgC/m2 - real(r8) :: fuel_frac(ncwd+2) ! fraction of each litter class in the ros_fuel:-. - real(r8) :: livegrass ! total aboveground grass biomass in patch. KgC/m2 - real(r8) :: fuel_bulkd ! average fuel bulk density of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). KgC/m3 - real(r8) :: fuel_sav ! average surface area to volume ratio of the ground fuel - ! (incl. live grasses. omits 1000hr fuels). - real(r8) :: fuel_mef ! average moisture of extinction factor - ! of the ground fuel (incl. live grasses. omits 1000hr fuels). - real(r8) :: fuel_eff_moist ! effective avearage fuel moisture content of the ground fuel - ! (incl. live grasses. omits 1000hr fuels) - real(r8) :: litter_moisture(ncwd+2) - - ! FIRE SPREAD - real(r8) :: ros_front ! rate of forward spread of fire: m/min - real(r8) :: ros_back ! rate of backward spread of fire: m/min - real(r8) :: effect_wspeed ! windspeed modified by fraction of relative grass and tree cover: m/min - real(r8) :: tau_l ! Duration of lethal heating: mins - real(r8) :: fi ! average fire intensity of flaming front: kj/m/s or kw/m - integer :: fire ! Is there a fire? 1=yes 0=no - real(r8) :: fd ! fire duration: mins - real(r8) :: nf ! number of fires initiated daily: n/gridcell/day - real(r8) :: sh ! average scorch height: m - - ! FIRE EFFECTS - real(r8) :: ab ! area burnt: m2/day - real(r8) :: frac_burnt ! fraction burnt: frac gridcell/day - real(r8) :: tfc_ros ! total fuel consumed - no trunks. KgC/m2/day - real(r8) :: burnt_frac_litter(nfsc) ! fraction of each litter pool burned:- - - contains - - procedure, public :: set_root_fraction - - end type ed_patch_type - - !************************************ - !** Site type structure ** - !************************************ - - type ed_site_type - - ! POINTERS - type (ed_patch_type), pointer :: oldest_patch => null() ! pointer to oldest patch at the site - type (ed_patch_type), pointer :: youngest_patch => null() ! pointer to yngest patch at the site - - ! INDICES - real(r8) :: lat ! latitude: degrees - real(r8) :: lon ! longitude: degrees - - ! CARBON BALANCE - real(r8) :: flux_in ! for carbon balance purpose. C coming into biomass pool: KgC/site - real(r8) :: flux_out ! for carbon balance purpose. C leaving ED pools KgC/site - real(r8) :: old_stock ! for accounting purposes, remember biomass stock from last time: KgC/site - - ! DISTURBANCE - real(r8) :: disturbance_mortality ! site level disturbance rates from mortality. - real(r8) :: disturbance_fire ! site level disturbance rates from fire. - integer :: dist_type ! disturbance dist_type id. - real(r8) :: disturbance_rate ! site total dist rate - - ! PHENOLOGY - real(r8) :: ED_GDD_site ! ED Phenology growing degree days. - integer :: status ! are leaves in this pixel on or off for cold decid - integer :: dstatus ! are leaves in this pixel on or off for drought decid - real(r8) :: ncd ! no chilling days:- - real(r8) :: last_n_days(senes) ! record of last 10 days temperature for senescence model. deg C - integer :: leafondate ! doy of leaf on:- - integer :: leafoffdate ! doy of leaf off:- - integer :: dleafondate ! doy of leaf on drought:- - integer :: dleafoffdate ! doy of leaf on drought:- - real(r8) :: water_memory(10) ! last 10 days of soil moisture memory... - - ! FIRE - real(r8) :: acc_ni ! daily nesterov index accumulating over time. - real(r8) :: ab ! daily burnt area: m2 - real(r8) :: frac_burnt ! fraction of soil burnt in this day. - real(r8) :: total_burn_flux_to_atm ! total carbon burnt to the atmosphere in this day. KgC/site - real(r8) :: cwd_ag_burned(ncwd) - real(r8) :: leaf_litter_burned(numpft_ed) - - end type ed_site_type - - !************************************ - !** Userdata type structure ** - !************************************ - - type userdata - integer :: cohort_number ! Counts up the number of cohorts which have been made. - integer :: n_sub ! num of substeps in year - real(r8) :: deltat ! fraction of year used for each timestep (1/N_SUB) - integer :: time_period ! Within year timestep (1:N_SUB) day of year - integer :: restart_year ! Which year of simulation are we starting in? - end type userdata - - - type(userdata), public, target :: udata ! THIS WAS NOT THREADSAFE - !-------------------------------------------------------------------------------------! - - public :: ed_hist_scpfmaps - -contains - - !-------------------------------------------------------------------------------------! - subroutine ed_hist_scpfmaps - ! This subroutine allocates and populates the variables - ! that define the mapping of variables in history files in the "scpf" format - ! back to - ! its respective size-class "sc" and pft "pf" - - integer :: i - integer :: isc - integer :: ipft - - allocate( levsclass_ed(1:nlevsclass_ed )) - allocate( pft_levscpf_ed(1:nlevsclass_ed*mxpft)) - allocate(scls_levscpf_ed(1:nlevsclass_ed*mxpft)) - - ! Fill the IO array of plant size classes - ! For some reason the history files did not like - ! a hard allocation of sclass_ed - levsclass_ed(:) = sclass_ed(:) - - ! Fill the IO arrays that match pft and size class to their combined array - i=0 - do ipft=1,mxpft - do isc=1,nlevsclass_ed - i=i+1 - pft_levscpf_ed(i) = ipft - scls_levscpf_ed(i) = isc - end do - end do - - end subroutine ed_hist_scpfmaps - - !-------------------------------------------------------------------------------------! - function map_clmpatch_to_edpatch(site, clmpatch_number) result(edpatch_pointer) - ! - ! !ARGUMENTS - type(ed_site_type), intent(in), target :: site - integer, intent(in) :: clmpatch_number - ! - ! !LOCAL VARIABLES: - type(ed_patch_type), pointer :: edpatch_pointer - !---------------------------------------------------------------------- - - ! There is a one-to-one mapping between edpatches and clmpatches. To obtain - ! this mapping - the following is computed elsewhere in the code base - ! (1) what is the weight respective to the column of clmpatch? - ! dynEDMod determines this via the following logic - ! if (clm_patch%is_veg(p) .or. clm_patch%is_bareground(p)) then - ! clm_patch%wtcol(p) = clm_patch%wt_ed(p) - ! else - ! clm_patch%wtcol(p) = 0.0_r8 - ! end if - ! (2) is the clmpatch active? - ! subgridWeightsMod uses the following logic (in routine is_active_p) to determine if - ! clmpatch_number is active ( this is a shortened version of the logic to capture - ! only the essential parts relevent here) - ! if (clmpatch%wtcol(p) > 0._r8) is_active_p = .true. - - edpatch_pointer => site%oldest_patch - do while ( clmpatch_number /= edpatch_pointer%clm_pno ) - edpatch_pointer => edpatch_pointer%younger - end do - - end function map_clmpatch_to_edpatch - - !-------------------------------------------------------------------------------------! - subroutine set_root_fraction( this ) - ! - ! !DESCRIPTION: - ! Calculates the fractions of the root biomass in each layer for each pft. - ! - ! !USES: - use PatchType , only : clmpatch => patch - use ColumnType , only : col - use clm_varpar , only : nlevsoi - use pftconMod , only : pftcon - ! - ! !ARGUMENTS - class(ed_patch_type) :: this - ! - ! !LOCAL VARIABLES: - integer :: lev,p,c,ft - !---------------------------------------------------------------------- - - p = this%clm_pno - c = clmpatch%column(p) - - do ft = 1,numpft_ed - do lev = 1, nlevgrnd - this%rootfr_ft(ft,lev) = 0._r8 - enddo - - do lev = 1, nlevsoi-1 - this%rootfr_ft(ft,lev) = .5_r8*( & - exp(-pftcon%roota_par(ft) * col%zi(c,lev-1)) & - + exp(-pftcon%rootb_par(ft) * col%zi(c,lev-1)) & - - exp(-pftcon%roota_par(ft) * col%zi(c,lev)) & - - exp(-pftcon%rootb_par(ft) * col%zi(c,lev))) - end do - end do - - end subroutine set_root_fraction - -end module EDTypesMod diff --git a/src/ED/main/EDVecCohortType.F90 b/src/ED/main/EDVecCohortType.F90 deleted file mode 100644 index feefd13502..0000000000 --- a/src/ED/main/EDVecCohortType.F90 +++ /dev/null @@ -1,42 +0,0 @@ -module EDVecCohortType - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! cohortype. mimics CLM vector subgrid types. For now this holds ED data that is - ! necessary in the rest of CLM - ! - ! !USES: - - ! !PUBLIC TYPES: - implicit none - public - ! - type, public :: ed_vec_cohort_type - integer :: cohorts_per_column - integer , pointer :: column(:) !index into column level quantities - contains - procedure, public :: Init - end type ed_vec_cohort_type - - type(ed_vec_cohort_type), public :: ed_vec_cohort - !------------------------------------------------------------------------ - -contains - - !------------------------------------------------------------------------ - subroutine Init(this, beg, end) - ! - ! !USES: - ! - ! !ARGUMENTS: - class(ed_vec_cohort_type) :: this - integer, intent(in) :: beg, end - !------------------------------------------------------------------------ - - ! FIX(SPM,032414) pull this out and put in own ED source - - allocate(this%column(beg:end)) - - end subroutine Init - -end module EDVecCohortType diff --git a/src/ED/main/FatesGlobals.F90 b/src/ED/main/FatesGlobals.F90 deleted file mode 100644 index 9ae06e207c..0000000000 --- a/src/ED/main/FatesGlobals.F90 +++ /dev/null @@ -1,38 +0,0 @@ -module FatesGlobals - ! NOTE(bja, 201608) This is a temporary hack module to store global - ! data used inside fates. It's main use it to explicitly call out - ! global data that needs to be dealt with, but doesn't have an - ! immediately obvious home. - - implicit none - - integer, private :: fates_log_ - logical, private :: fates_global_verbose_ - - public :: FatesGlobalsInit - public :: fates_log - public :: fates_global_verbose - -contains - - subroutine FatesGlobalsInit(log_unit, global_verbose) - - implicit none - - integer, intent(in) :: log_unit - logical, intent(in) :: global_verbose - - fates_log_ = log_unit - fates_global_verbose_ = global_verbose - - end subroutine FatesGlobalsInit - - integer function fates_log() - fates_log = fates_log_ - end function fates_log - - logical function fates_global_verbose() - fates_global_verbose = fates_global_verbose_ - end function fates_global_verbose - -end module FatesGlobals diff --git a/src/ED/main/FatesInterfaceMod.F90 b/src/ED/main/FatesInterfaceMod.F90 deleted file mode 100644 index 776e4cdc25..0000000000 --- a/src/ED/main/FatesInterfaceMod.F90 +++ /dev/null @@ -1,593 +0,0 @@ -module FatesInterfaceMod - - ! ------------------------------------------------------------------------------------ - ! This is the FATES public API - ! A host land model has defined and allocated a structure "fates" as - ! defined by fates_interface_type - ! - ! It is also likely/possible that this type is defined as a vector - ! which is allocated by thread - ! ------------------------------------------------------------------------------------ - - ! ------------------------------------------------------------------------------------ - ! Used CLM Modules - ! INTERF-TODO: NO CLM MODULES SHOULD BE ACCESSIBLE BY THE FATES - ! PUBLIC API!!!! - ! ------------------------------------------------------------------------------------ - - use EDtypesMod , only : ed_site_type, & - numPatchesPerCol, & - cp_nclmax, & - cp_numSWb, & - cp_numlevgrnd, & - cp_maxSWb, & - cp_numlevdecomp, & - cp_numlevdecomp_full - - use shr_kind_mod , only : r8 => shr_kind_r8 ! INTERF-TODO: REMOVE THIS - - - - ! ------------------------------------------------------------------------------------ - ! Notes on types - ! For floating point arrays, it is sometimes the convention to define the arrays as - ! POINTER instead of ALLOCATABLE. This usually achieves the same result with subtle - ! differences. POINTER arrays can point to scalar values, discontinuous array slices - ! or alias other variables, ALLOCATABLES cannnot. According to S. Lionel - ! (Intel-Forum Post), ALLOCATABLES are better perfomance wise as long as they point - ! to contiguous memory spaces and do not alias other variables, the case here. - ! Naming conventions: _gl means ground layer dimensions - ! _pa means patch dimensions - ! _rb means radiation band - ! ------------------------------------------------------------------------------------ - - type, public :: bc_in_type - - ! The actual number of FATES' ED patches - integer :: npatches - - ! Radiation variables for calculating sun/shade fractions - ! --------------------------------------------------------------------------------- - - ! Downwelling direct beam radiation (patch,radiation-band) [W/m2] - real(r8), allocatable :: solad_parb(:,:) - - ! Downwelling diffuse (I-ndirect) radiation (patch,radiation-band) [W/m2] - real(r8), allocatable :: solai_parb(:,:) - - ! Hydrology variables for BTRAN - ! --------------------------------------------------------------------------------- - - ! Soil suction potential of layers in each site, negative, [mm] - real(r8), allocatable :: smp_gl(:) - - ! Effective porosity = porosity - vol_ic, of layers in each site [-] - real(r8), allocatable :: eff_porosity_gl(:) - - ! volumetric soil water at saturation (porosity) - real(r8), allocatable :: watsat_gl(:) - - ! Temperature of ground layers [K] - real(r8), allocatable :: tempk_gl(:) - - ! Liquid volume in ground layer - real(r8), allocatable :: h2o_liqvol_gl(:) - - ! Site level filter for uptake response functions - logical :: filter_btran - - ! Photosynthesis variables - ! --------------------------------------------------------------------------------- - - ! Patch level filter flag for photosynthesis calculations - ! has a short memory, flags: - ! 1 = patch has not been called - ! 2 = patch is currently marked for photosynthesis - ! 3 = patch has been called for photosynthesis at least once - integer, allocatable :: filter_photo_pa(:) - - ! atmospheric pressure (Pa) - real(r8) :: forc_pbot - - ! daylength scaling factor (0-1) - real(r8), allocatable :: dayl_factor_pa(:) - - ! saturation vapor pressure at t_veg (Pa) - real(r8), allocatable :: esat_tv_pa(:) - - ! vapor pressure of canopy air (Pa) - real(r8), allocatable :: eair_pa(:) - - ! Atmospheric O2 partial pressure (Pa) - real(r8), allocatable :: oair_pa(:) - - ! Atmospheric CO2 partial pressure (Pa) - real(r8), allocatable :: cair_pa(:) - - ! boundary layer resistance (s/m) - real(r8), allocatable :: rb_pa(:) - - ! vegetation temperature (Kelvin) - real(r8), allocatable :: t_veg_pa(:) - - ! air temperature at agcm reference height (kelvin) - real(r8), allocatable :: tgcm_pa(:) - - ! soil temperature (Kelvin) - real(r8), allocatable :: t_soisno_gl(:) - - ! Canopy Radiation Boundaries - ! --------------------------------------------------------------------------------- - - ! Filter for vegetation patches with a positive zenith angle (daylight) - logical, allocatable :: filter_vegzen_pa(:) - - ! Cosine of the zenith angle (0-1), by patch - ! Note RGK: It does not seem like the code would currently generate - ! different zenith angles for different patches (nor should it) - ! I am leaving it at this scale for simplicity. Patches should - ! have no spacially variable information - real(r8), allocatable :: coszen_pa(:) - - ! Abledo of the ground for direct radiation, by site broadband (0-1) - real(r8), allocatable :: albgr_dir_rb(:) - - ! Albedo of the ground for diffuse radiation, by site broadband (0-1) - real(r8), allocatable :: albgr_dif_rb(:) - - ! LitterFlux Boundaries - ! the index of the deepest model soil level where roots may be - ! due to permafrost or bedrock constraints - integer :: max_rooting_depth_index_col - - - end type bc_in_type - - - type, public :: bc_out_type - - ! Sunlit fraction of the canopy for this patch [0-1] - real(r8),allocatable :: fsun_pa(:) - - ! Sunlit canopy LAI - real(r8),allocatable :: laisun_pa(:) - - ! Shaded canopy LAI - real(r8),allocatable :: laisha_pa(:) - - ! Logical stating whether a ground layer can have water uptake by plants - ! The only condition right now is that liquid water exists - ! The name (suction) is used to indicate that soil suction should be calculated - logical, allocatable :: active_suction_gl(:) - - ! Effective fraction of roots in each soil layer - real(r8), allocatable :: rootr_pagl(:,:) - - ! Integrated (vertically) transpiration wetness factor (0 to 1) - ! (diagnostic, should not be used by HLM) - real(r8), allocatable :: btran_pa(:) - - ! Sunlit canopy resistance [s/m] - real(r8), allocatable :: rssun_pa(:) - - ! Shaded canopy resistance [s/m] - real(r8), allocatable :: rssha_pa(:) - - ! Canopy conductance [mmol m-2 s-1] - real(r8), allocatable :: gccanopy_pa(:) - - ! patch sunlit leaf photosynthesis (umol CO2 /m**2/ s) - real(r8), allocatable :: psncanopy_pa(:) - - ! patch sunlit leaf maintenance respiration rate (umol CO2/m**2/s) - real(r8), allocatable :: lmrcanopy_pa(:) - - ! Canopy Radiation Boundaries - ! --------------------------------------------------------------------------------- - - ! Surface albedo (direct) (HLMs use this for atm coupling and balance checks) - real(r8), allocatable :: albd_parb(:,:) - - ! Surface albedo (diffuse) (HLMs use this for atm coupling and balance checks) - real(r8), allocatable :: albi_parb(:,:) - - ! Flux absorbed by canopy per unit direct flux (HLMs use this for balance checks) - real(r8), allocatable :: fabd_parb(:,:) - - ! Flux absorbed by canopy per unit diffuse flux (HLMs use this for balance checks) - real(r8), allocatable :: fabi_parb(:,:) - - ! Down direct flux below canopy per unit direct flx (HLMs use this for balance checks) - real(r8), allocatable :: ftdd_parb(:,:) - - ! Down diffuse flux below canopy per unit direct flx (HLMs use this for balance checks) - real(r8), allocatable :: ftid_parb(:,:) - - ! Down diffuse flux below canopy per unit diffuse flx (HLMs use this for balance checks) - real(r8), allocatable :: ftii_parb(:,:) - - - ! litterfall fluxes of C from FATES patches to BGC columns - - ! total labile litter coming from ED. gC/m3/s - real(r8), allocatable :: FATES_c_to_litr_lab_c_col(:) - - !total cellulose litter coming from ED. gC/m3/s - real(r8), allocatable :: FATES_c_to_litr_cel_c_col(:) - - !total lignin litter coming from ED. gC/m3/s - real(r8), allocatable :: FATES_c_to_litr_lig_c_col(:) - - - end type bc_out_type - - - type, public :: fates_interface_type - - ! This is the root of the ED/FATES hierarchy of instantaneous state variables - ! ie the root of the linked lists. Each path list is currently associated with a - ! grid-cell, this is intended to be migrated to columns - - integer :: nsites - - type(ed_site_type), pointer :: sites(:) - - ! These are boundary conditions that the FATES models are required to be filled. - ! These values are filled by the driver or HLM. Once filled, these have an - ! intent(in) status. Each site has a derived type structure, which may include - ! a scalar for site level data, a patch vector, potentially cohort vectors (but - ! not yet atm) and other dimensions such as soil-depth or pft. These vectors - ! are initialized by maximums, and the allocations are static in time to avoid - ! having to allocate/de-allocate memory - - type(bc_in_type), allocatable :: bc_in(:) - - ! These are the boundary conditions that the FATES model returns to its HLM or - ! driver. It has the same allocation strategy and similar vector types. - - type(bc_out_type), allocatable :: bc_out(:) - - contains - - procedure, public :: zero_bcs - - end type fates_interface_type - - public :: FatesInterfaceInit - public :: set_fates_ctrlparms - - -contains - - ! ==================================================================================== - subroutine FatesInterfaceInit(log_unit, global_verbose) - - use FatesGlobals, only : FatesGlobalsInit - - implicit none - - integer, intent(in) :: log_unit - logical, intent(in) :: global_verbose - - call FatesGlobalsInit(log_unit, global_verbose) - - end subroutine FatesInterfaceInit - - ! ==================================================================================== - - ! INTERF-TODO: THIS IS A PLACE-HOLDER ROUTINE, NOT CALLED YET... - subroutine fates_clean(this) - - implicit none - - ! Input Arguments - class(fates_interface_type), intent(inout) :: this - - ! Incrementally walk through linked list and deallocate - - - - ! Deallocate the site list - deallocate (this%sites) - - return - end subroutine fates_clean - - - ! ==================================================================================== - - - subroutine allocate_bcin(bc_in) - - ! --------------------------------------------------------------------------------- - ! Allocate and Initialze the FATES boundary condition vectors - ! --------------------------------------------------------------------------------- - - implicit none - type(bc_in_type), intent(inout) :: bc_in - - ! Allocate input boundaries - - ! Radiation - allocate(bc_in%solad_parb(numPatchesPerCol,cp_numSWb)) - allocate(bc_in%solai_parb(numPatchesPerCol,cp_numSWb)) - - ! Hydrology - allocate(bc_in%smp_gl(cp_numlevgrnd)) - allocate(bc_in%eff_porosity_gl(cp_numlevgrnd)) - allocate(bc_in%watsat_gl(cp_numlevgrnd)) - allocate(bc_in%tempk_gl(cp_numlevgrnd)) - allocate(bc_in%h2o_liqvol_gl(cp_numlevgrnd)) - - ! Photosynthesis - allocate(bc_in%filter_photo_pa(numPatchesPerCol)) - allocate(bc_in%dayl_factor_pa(numPatchesPerCol)) - allocate(bc_in%esat_tv_pa(numPatchesPerCol)) - allocate(bc_in%eair_pa(numPatchesPerCol)) - allocate(bc_in%oair_pa(numPatchesPerCol)) - allocate(bc_in%cair_pa(numPatchesPerCol)) - allocate(bc_in%rb_pa(numPatchesPerCol)) - allocate(bc_in%t_veg_pa(numPatchesPerCol)) - allocate(bc_in%tgcm_pa(numPatchesPerCol)) - allocate(bc_in%t_soisno_gl(cp_numlevgrnd)) - - ! Canopy Radiation - allocate(bc_in%filter_vegzen_pa(numPatchesPerCol)) - allocate(bc_in%coszen_pa(numPatchesPerCol)) - allocate(bc_in%albgr_dir_rb(cp_numSWb)) - allocate(bc_in%albgr_dif_rb(cp_numSWb)) - - return - end subroutine allocate_bcin - - subroutine allocate_bcout(bc_out) - - ! --------------------------------------------------------------------------------- - ! Allocate and Initialze the FATES boundary condition vectors - ! --------------------------------------------------------------------------------- - - implicit none - type(bc_out_type), intent(inout) :: bc_out - - - ! Radiation - allocate(bc_out%fsun_pa(numPatchesPerCol)) - allocate(bc_out%laisun_pa(numPatchesPerCol)) - allocate(bc_out%laisha_pa(numPatchesPerCol)) - - ! Hydrology - allocate(bc_out%active_suction_gl(cp_numlevgrnd)) - allocate(bc_out%rootr_pagl(numPatchesPerCol,cp_numlevgrnd)) - allocate(bc_out%btran_pa(numPatchesPerCol)) - - ! Photosynthesis - allocate(bc_out%rssun_pa(numPatchesPerCol)) - allocate(bc_out%rssha_pa(numPatchesPerCol)) - allocate(bc_out%gccanopy_pa(numPatchesPerCol)) - allocate(bc_out%lmrcanopy_pa(numPatchesPerCol)) - allocate(bc_out%psncanopy_pa(numPatchesPerCol)) - - ! Canopy Radiation - allocate(bc_out%albd_parb(numPatchesPerCol,cp_numSWb)) - allocate(bc_out%albi_parb(numPatchesPerCol,cp_numSWb)) - allocate(bc_out%fabd_parb(numPatchesPerCol,cp_numSWb)) - allocate(bc_out%fabi_parb(numPatchesPerCol,cp_numSWb)) - allocate(bc_out%ftdd_parb(numPatchesPerCol,cp_numSWb)) - allocate(bc_out%ftid_parb(numPatchesPerCol,cp_numSWb)) - allocate(bc_out%ftii_parb(numPatchesPerCol,cp_numSWb)) - - ! biogeochemistry - allocate(bc_out%FATES_c_to_litr_lab_c_col(cp_numlevdecomp_full)) - allocate(bc_out%FATES_c_to_litr_cel_c_col(cp_numlevdecomp_full)) - allocate(bc_out%FATES_c_to_litr_lig_c_col(cp_numlevdecomp_full)) - - return - end subroutine allocate_bcout - - ! ==================================================================================== - - subroutine zero_bcs(this,s) - - implicit none - class(fates_interface_type), intent(inout) :: this - integer, intent(in) :: s - - ! Input boundaries - - this%bc_in(s)%solad_parb(:,:) = 0.0_r8 - this%bc_in(s)%solai_parb(:,:) = 0.0_r8 - this%bc_in(s)%smp_gl(:) = 0.0_r8 - this%bc_in(s)%eff_porosity_gl(:) = 0.0_r8 - this%bc_in(s)%watsat_gl(:) = 0.0_r8 - this%bc_in(s)%tempk_gl(:) = 0.0_r8 - this%bc_in(s)%h2o_liqvol_gl(:) = 0.0_r8 - this%bc_in(s)%filter_vegzen_pa(:) = .false. - this%bc_in(s)%coszen_pa(:) = 0.0_r8 - this%bc_in(s)%albgr_dir_rb(:) = 0.0_r8 - this%bc_in(s)%albgr_dif_rb(:) = 0.0_r8 - this%bc_in(s)%max_rooting_depth_index_col = 0 - - - ! Output boundaries - this%bc_out(s)%active_suction_gl(:) = .false. - this%bc_out(s)%fsun_pa(:) = 0.0_r8 - this%bc_out(s)%laisun_pa(:) = 0.0_r8 - this%bc_out(s)%laisha_pa(:) = 0.0_r8 - this%bc_out(s)%rootr_pagl(:,:) = 0.0_r8 - this%bc_out(s)%btran_pa(:) = 0.0_r8 - - this%bc_out(s)%FATES_c_to_litr_lab_c_col(:) = 0.0_r8 - this%bc_out(s)%FATES_c_to_litr_cel_c_col(:) = 0.0_r8 - this%bc_out(s)%FATES_c_to_litr_lig_c_col(:) = 0.0_r8 - - this%bc_out(s)%rssun_pa(:) = 0.0_r8 - this%bc_out(s)%rssha_pa(:) = 0.0_r8 - this%bc_out(s)%gccanopy_pa(:) = 0.0_r8 - this%bc_out(s)%psncanopy_pa(:) = 0.0_r8 - this%bc_out(s)%lmrcanopy_pa(:) = 0.0_r8 - - this%bc_out(s)%albd_parb(:,:) = 0.0_r8 - this%bc_out(s)%albi_parb(:,:) = 0.0_r8 - this%bc_out(s)%fabd_parb(:,:) = 0.0_r8 - this%bc_out(s)%fabi_parb(:,:) = 0.0_r8 - this%bc_out(s)%ftdd_parb(:,:) = 0.0_r8 - this%bc_out(s)%ftid_parb(:,:) = 0.0_r8 - this%bc_out(s)%ftii_parb(:,:) = 0.0_r8 - - return - end subroutine zero_bcs - - ! ==================================================================================== - - subroutine set_fates_ctrlparms(tag,dimval) - - ! --------------------------------------------------------------------------------- - ! INTERF-TODO: NEED ALLOWANCES FOR REAL AND CHARACTER ARGS.. - ! Certain model control parameters and dimensions used by FATES are dictated by - ! the the driver or the host mode. To see which parameters should be filled here - ! please also look at the ctrl_parms_type in FATESTYpeMod, in the section listing - ! components dictated by the host model. - ! - ! Some important points: - ! 1. Calls to this function are likely from the clm_fates module in the HLM. - ! 2. The calls should be preceeded by a flush function. - ! 3. All values in ctrl_parm (FATESTypesMod.F90) that are classified as - ! 'dictated by the HLM' must be listed in this subroutine - ! 4. Should look like this: - ! - ! call set_fates_ctrlparms('flush_to_unset') - ! call set_fates_ctrlparms('num_sw_bbands',numrad) ! or other variable - ! ... - ! call set_fates_ctrlparms('num_lev_ground',nlevgrnd) ! or other variable - ! call set_fates_ctrlparms('check_allset') - ! - ! RGK-2016 - ! --------------------------------------------------------------------------------- - use FatesGlobals, only : fates_log, fates_global_verbose - - ! Arguments - integer, optional, intent(in) :: dimval - character(len=*),intent(in) :: tag - - ! local variables - logical :: all_set - integer, parameter :: unset_int = -999 - real(r8), parameter :: unset_double = -999.9 - - select case (trim(tag)) - case('flush_to_unset') - if (fates_global_verbose()) then - write(fates_log(), *) 'Flushing FATES control parameters prior to transfer from host' - end if - cp_numSwb = unset_int - cp_numlevgrnd = unset_int - cp_numlevdecomp_full = unset_int - cp_numlevdecomp = unset_int - - - case('check_allset') - - if(cp_numSWb .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES dimension/parameter unset: num_sw_rad_bbands' - end if - ! INTERF-TODO: FATES NEEDS INTERNAL end_run - ! end_run('MESSAGE') - end if - - if(cp_numSWb > cp_maxSWb) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES sets a maximum number of shortwave bands' - write(fates_log(), *) 'for some scratch-space, cp_maxSWb' - write(fates_log(), *) 'it defaults to 2, but can be increased as needed' - write(fates_log(), *) 'your driver or host model is intending to drive' - write(fates_log(), *) 'FATES with:',cp_numSWb,' bands.' - write(fates_log(), *) 'please increase cp_maxSWb in EDTypes to match' - write(fates_log(), *) 'or exceed this value' - end if - ! end_run('MESSAGE') - end if - - if(cp_numlevgrnd .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES dimension/parameter unset: numlevground' - end if - ! INTERF-TODO: FATES NEEDS INTERNAL end_run - ! end_run('MESSAGE') - end if - - if(cp_numlevdecomp_full .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES dimension/parameter unset: numlevdecomp_full' - end if - ! INTERF-TODO: FATES NEEDS INTERNAL end_run - ! end_run('MESSAGE') - end if - - if(cp_numlevdecomp .eq. unset_int) then - if (fates_global_verbose()) then - write(fates_log(), *) 'FATES dimension/parameter unset: numlevdecomp' - end if - ! INTERF-TODO: FATES NEEDS INTERNAL end_run - ! end_run('MESSAGE') - end if - - if (fates_global_verbose()) then - write(fates_log(), *) 'Checked. All control parameters sent to FATES.' - end if - - case default - - if(present(dimval))then - select case (trim(tag)) - - case('num_sw_bbands') - - cp_numSwb = dimval - if (fates_global_verbose()) then - write(fates_log(), *) 'Transfering num_sw_bbands = ',dimval,' to FATES' - end if - - case('num_lev_ground') - - cp_numlevgrnd = dimval - if (fates_global_verbose()) then - - write(fates_log(), *) 'Transfering num_lev_ground = ',dimval,' to FATES' - end if - - case('num_levdecomp_full') - - cp_numlevdecomp_full = dimval - if (fates_global_verbose()) then - write(fates_log(), *) 'Transfering num_levdecomp_full = ',dimval,' to FATES' - end if - - case('num_levdecomp') - - cp_numlevdecomp = dimval - if (fates_global_verbose()) then - write(fates_log(), *) 'Transfering num_levdecomp = ',dimval,' to FATES' - end if - - case default - if (fates_global_verbose()) then - write(fates_log(), *) 'tag not recognized:',trim(tag) - end if - ! end_run - end select - else - if (fates_global_verbose()) then - write(fates_log(), *) 'no value was provided for the tag' - end if - end if - - end select - - - return - end subroutine set_fates_ctrlparms - - - -end module FatesInterfaceMod diff --git a/src/README.unit_testing b/src/README.unit_testing index dfaaceeb5d..60dd187364 100644 --- a/src/README.unit_testing +++ b/src/README.unit_testing @@ -1,24 +1,12 @@ -# To run all CIME unit tests on caldera, run the following command: -# (Note that this must be done from an interactive caldera session, not from yellowstone) -# (One way to do that is to prepend with the "execca" utility that sends the resulting command to caldera) -execca ../../../cime/tools/unit_testing/run_tests.py --test-spec-dir=. --compiler=intel --mpilib=mpich2 \ ---mpirun-command=mpirun.lsf --cmake-args=-DPAPI_LIB=/glade/apps/opt/papi/5.3.0/intel/12.1.5/lib64 & - -# The inclusion of PAPI_LIB is needed above since config_compilers includes: -# -Wl,-rpath ${PAPI_LIB} -L${PAPI_LIB} -lpapi -# On a different machine besides yellowstone the path would obviously be different +# To run all CLM unit tests on caldera, run the following command: +# +# Note that, on yellowstone/caldera, this requires 'module load all-python-libs' # +# The creation of a temporary directory ensures that you are doing a completely +# clean build of the unit tests. (The use of the --clean flag to run_tests.py +# cleans most, but not all of the files created by the unit test build.) For +# rerunning the tests after an incremental change, you can instead use an +# existing build directory. -# NOTE: If the above fails with something like... -Running make for __command_line_test__/__command_line_test__. -================================================== -make: *** No targets specified and no makefile found. Stop. -Traceback (most recent call last): -. -. -. -# Then your build directory has issues and you need to start the build over fresh. -# Delete the "__command_line_test__" directory as follows... -# \rm -rf __command_line_test__/ -# See bugzilla bug 2257 for more on this +../../../cime/scripts/fortran_unit_testing/run_tests.py --build-dir `mktemp -d --tmpdir=. unit_tests.XXXXXXXX` diff --git a/src/biogeochem/C14BompbSpikeMod.F90 b/src/biogeochem/C14BompbSpikeMod.F90 deleted file mode 100644 index 69449748b1..0000000000 --- a/src/biogeochem/C14BompbSpikeMod.F90 +++ /dev/null @@ -1,137 +0,0 @@ -module C14BombSpikeMod - - !----------------------------------------------------------------------- - ! Module for transient pulse simulation - ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_time_manager , only : get_curr_date,get_days_per_year - use clm_varcon , only : c14ratio, secspday - ! - implicit none - private - ! - ! !PUBLIC MEMBER FUNCTIONS: - public:: C14BombSpike - public:: C14_init_BombSpike - - ! !PUBLIC TYPES: - logical , public :: use_c14_bombspike = .false. ! do we use time-varying atmospheric C14? - character(len=256) , public :: atm_c14_filename = ' ' ! file name of C14 input data - - ! !PRIVATE TYPES: - real(r8), allocatable, private :: atm_c14file_time(:) - real(r8), allocatable, private :: atm_delta_c14(:) - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - !----------------------------------------------------------------------- - -contains - - !----------------------------------------------------------------------- - subroutine C14BombSpike( rc14_atm ) - ! - ! !DESCRIPTION: - ! for transient pulse simulation, impose a simplified bomb spike - ! - ! !ARGUMENTS: - real(r8), intent(out) :: rc14_atm - ! - ! !LOCAL VARIABLES: - integer :: yr, mon, day, tod, offset - real(r8) :: dateyear - real(r8) :: delc14o2_atm - real(r8) :: days_per_year ! days per year - integer :: fp, p, nt - integer :: ind_below - integer :: ntim_atm_ts - real(r8) :: twt_1, twt_2 ! weighting fractions for interpolating - !----------------------------------------------------------------------- - - ! get current date - call get_curr_date(yr, mon, day, tod, offset) - days_per_year = get_days_per_year() - dateyear = real(yr) + real(mon)/12._r8 + real(day)/days_per_year + real(tod)/(secspday*days_per_year) - - ! find points in atm timeseries to interpolate between - ntim_atm_ts = size(atm_c14file_time) - ind_below = 0 - do nt = 1, ntim_atm_ts - if (dateyear >= atm_c14file_time(nt) ) then - ind_below = ind_below+1 - endif - end do - - ! interpolate between nearest two points in atm c14 timeseries - if (ind_below .eq. 0 ) then - delc14o2_atm = atm_delta_c14(1) - elseif (ind_below .eq. ntim_atm_ts ) then - delc14o2_atm = atm_delta_c14(ntim_atm_ts) - else - twt_2 = min(1._r8, max(0._r8,(dateyear-atm_c14file_time(ind_below)) & - / (atm_c14file_time(ind_below+1)-atm_c14file_time(ind_below)))) - twt_1 = 1._r8 - twt_2 - delc14o2_atm = atm_delta_c14(ind_below) * twt_1 + atm_delta_c14(ind_below+1) * twt_2 - endif - - ! change delta units to ratio, put on patch loop - - rc14_atm = (delc14o2_atm * 1.e-3_r8 + 1._r8) * c14ratio - - end subroutine C14BombSpike - - !----------------------------------------------------------------------- - subroutine C14_init_BombSpike() - ! - ! !DESCRIPTION: - ! read netcdf file containing a timeseries of atmospheric delta C14 values; save in module-level array - ! - ! !USES: - use ncdio_pio - use fileutils , only : getfil - use abortutils , only : endrun - use clm_varctl , only : iulog - use spmdMod , only : masterproc - use shr_log_mod , only : errMsg => shr_log_errMsg - ! - ! !LOCAL VARIABLES: - character(len=256) :: locfn ! local file name - type(file_desc_t) :: ncid ! netcdf id - integer :: dimid,varid ! input netCDF id's - integer :: ntim ! number of input data time samples - integer :: t - !----------------------------------------------------------------------- - - if ( masterproc ) then - write(iulog, *) 'C14_init_BombSpike: preparing to open file:' - write(iulog, *) trim(locfn) - endif - - call getfil(atm_c14_filename, locfn, 0) - - call ncd_pio_openfile (ncid, trim(locfn), 0) - - call ncd_inqdlen(ncid,dimid,ntim,'time') - - !! allocate arrays based on size of netcdf timeseries - allocate(atm_c14file_time(ntim)) - allocate(atm_delta_c14(ntim)) - - call ncd_io(ncid=ncid, varname='time', flag='read', data=atm_c14file_time) - - call ncd_io(ncid=ncid, varname='atm_delta_c14', flag='read', data=atm_delta_c14) - - call ncd_pio_closefile(ncid) - - ! check to make sure that time dimension is well behaved - do t = 2, ntim - if ( atm_c14file_time(t) - atm_c14file_time(t-1) <= 0._r8 ) then - write(iulog, *) 'C14_init_BombSpike: error. time axis must be monotonically increasing' - call endrun(msg=errMsg(sourcefile, __LINE__)) - endif - end do - - end subroutine C14_init_BombSpike - -end module C14BombSpikeMod diff --git a/src/biogeochem/CNAnnualUpdateMod.F90 b/src/biogeochem/CNAnnualUpdateMod.F90 index f26fdeadec..508b7cf08e 100644 --- a/src/biogeochem/CNAnnualUpdateMod.F90 +++ b/src/biogeochem/CNAnnualUpdateMod.F90 @@ -8,6 +8,8 @@ module CNAnnualUpdateMod use decompMod , only : bounds_type use CNVegCarbonFluxType , only : cnveg_carbonflux_type use CNvegStateType , only : cnveg_state_type + use PatchType , only : patch + use filterColMod , only : filter_col_type, col_filter_from_filter_and_logical_array ! implicit none private @@ -42,67 +44,69 @@ subroutine CNAnnualUpdate(bounds, num_soilc, filter_soilc, num_soilp, filter_soi ! !LOCAL VARIABLES: integer :: c,p ! indices integer :: fp,fc ! lake filter indices + real(r8):: secspyear real(r8):: dt ! radiation time step (seconds) + logical :: end_of_year(bounds%begc:bounds%endc) ! whether each column has reached the end of the year, according to its own annsum_counter + type(filter_col_type) :: filter_endofyear_c !----------------------------------------------------------------------- - ! set time steps dt = real( get_step_size(), r8 ) + secspyear = get_days_per_year() * secspday - ! column loop do fc = 1,num_soilc c = filter_soilc(fc) cnveg_state_inst%annsum_counter_col(c) = cnveg_state_inst%annsum_counter_col(c) + dt + if (cnveg_state_inst%annsum_counter_col(c) >= secspyear) then + end_of_year(c) = .true. + cnveg_state_inst%annsum_counter_col(c) = 0._r8 + else + end_of_year(c) = .false. + end if end do - if (num_soilc > 0) then - - if (cnveg_state_inst%annsum_counter_col(filter_soilc(1)) >= get_days_per_year() * secspday) then + do fp = 1,num_soilp + p = filter_soilp(fp) + c = patch%column(p) - ! patch loop - do fp = 1,num_soilp - p = filter_soilp(fp) + if (end_of_year(c)) then - ! update annual plant ndemand accumulator - cnveg_state_inst%annsum_potential_gpp_patch(p) = cnveg_state_inst%tempsum_potential_gpp_patch(p) - cnveg_state_inst%tempsum_potential_gpp_patch(p) = 0._r8 + ! update annual plant ndemand accumulator + cnveg_state_inst%annsum_potential_gpp_patch(p) = cnveg_state_inst%tempsum_potential_gpp_patch(p) + cnveg_state_inst%tempsum_potential_gpp_patch(p) = 0._r8 - ! update annual total N retranslocation accumulator - cnveg_state_inst%annmax_retransn_patch(p) = cnveg_state_inst%tempmax_retransn_patch(p) - cnveg_state_inst%tempmax_retransn_patch(p) = 0._r8 + ! update annual total N retranslocation accumulator + cnveg_state_inst%annmax_retransn_patch(p) = cnveg_state_inst%tempmax_retransn_patch(p) + cnveg_state_inst%tempmax_retransn_patch(p) = 0._r8 - ! update annual average 2m air temperature accumulator - cnveg_state_inst%annavg_t2m_patch(p) = cnveg_state_inst%tempavg_t2m_patch(p) - cnveg_state_inst%tempavg_t2m_patch(p) = 0._r8 + ! update annual average 2m air temperature accumulator + cnveg_state_inst%annavg_t2m_patch(p) = cnveg_state_inst%tempavg_t2m_patch(p) + cnveg_state_inst%tempavg_t2m_patch(p) = 0._r8 - ! update annual NPP accumulator, convert to annual total - cnveg_carbonflux_inst%annsum_npp_patch(p) = cnveg_carbonflux_inst%tempsum_npp_patch(p) * dt - cnveg_carbonflux_inst%tempsum_npp_patch(p) = 0._r8 + ! update annual NPP accumulator, convert to annual total + cnveg_carbonflux_inst%annsum_npp_patch(p) = cnveg_carbonflux_inst%tempsum_npp_patch(p) * dt + cnveg_carbonflux_inst%tempsum_npp_patch(p) = 0._r8 - ! update annual litfall accumulator, convert to annual total - cnveg_carbonflux_inst%annsum_litfall_patch(p) = cnveg_carbonflux_inst%tempsum_litfall_patch(p) * dt - cnveg_carbonflux_inst%tempsum_litfall_patch(p) = 0._r8 - end do + ! update annual litfall accumulator, convert to annual total + cnveg_carbonflux_inst%annsum_litfall_patch(p) = cnveg_carbonflux_inst%tempsum_litfall_patch(p) * dt + cnveg_carbonflux_inst%tempsum_litfall_patch(p) = 0._r8 - ! use p2c routine to get selected column-average patch-level fluxes and states - - call p2c(bounds, num_soilc, filter_soilc, & - cnveg_carbonflux_inst%annsum_npp_patch(bounds%begp:bounds%endp), & - cnveg_carbonflux_inst%annsum_npp_col(bounds%begc:bounds%endc)) - - call p2c(bounds, num_soilc, filter_soilc, & - cnveg_state_inst%annavg_t2m_patch(bounds%begp:bounds%endp), & - cnveg_state_inst%annavg_t2m_col(bounds%begc:bounds%endc)) end if + end do - end if + ! Get column-level averages, just for the columns that have reached their personal end-of-year + filter_endofyear_c = col_filter_from_filter_and_logical_array( & + bounds = bounds, & + num_orig = num_soilc, & + filter_orig = filter_soilc, & + logical_col = end_of_year(bounds%begc:bounds%endc)) - ! column loop - do fc = 1,num_soilc - c = filter_soilc(fc) - if (cnveg_state_inst%annsum_counter_col(c) >= get_days_per_year() * secspday) then - cnveg_state_inst%annsum_counter_col(c) = 0._r8 - end if - end do + call p2c(bounds, filter_endofyear_c%num, filter_endofyear_c%indices, & + cnveg_carbonflux_inst%annsum_npp_patch(bounds%begp:bounds%endp), & + cnveg_carbonflux_inst%annsum_npp_col(bounds%begc:bounds%endc)) + + call p2c(bounds, filter_endofyear_c%num, filter_endofyear_c%indices, & + cnveg_state_inst%annavg_t2m_patch(bounds%begp:bounds%endp), & + cnveg_state_inst%annavg_t2m_col(bounds%begc:bounds%endc)) end subroutine CNAnnualUpdate diff --git a/src/biogeochem/CNBalanceCheckMod.F90 b/src/biogeochem/CNBalanceCheckMod.F90 index eda78e20aa..f2811d290a 100644 --- a/src/biogeochem/CNBalanceCheckMod.F90 +++ b/src/biogeochem/CNBalanceCheckMod.F90 @@ -186,11 +186,11 @@ subroutine CBalanceCheck(this, bounds, num_soilc, filter_soilc, & (col_endcb(c) - col_begcb(c)) ! check for significant errors - if (abs(col_errcb(c)) > 1e-8_r8) then + if (abs(col_errcb(c)) > 1e-7_r8) then err_found = .true. err_index = c end if - if (abs(col_errcb(c)) > 1e-9_r8) then + if (abs(col_errcb(c)) > 1e-8_r8) then write(iulog,*) 'cbalance warning',c,col_errcb(c),col_endcb(c) end if @@ -320,12 +320,12 @@ subroutine NBalanceCheck(this, bounds, num_soilc, filter_soilc, & col_errnb(c) = (col_ninputs(c) - col_noutputs(c))*dt - & (col_endnb(c) - col_begnb(c)) - if (abs(col_errnb(c)) > 1e-4_r8) then + if (abs(col_errnb(c)) > 1e-3_r8) then err_found = .true. err_index = c end if - if (abs(col_errnb(c)) > 1e-8_r8) then + if (abs(col_errnb(c)) > 1e-7_r8) then write(iulog,*) 'nbalance warning',c,col_errnb(c),col_endnb(c) write(iulog,*)'inputs,ffix,nfix,ndep = ',ffix_to_sminn(c)*dt,nfix_to_sminn(c)*dt,ndep_to_sminn(c)*dt write(iulog,*)'outputs,lch,roff,dnit = ',smin_no3_leached(c)*dt, smin_no3_runoff(c)*dt,f_n2o_nit(c)*dt diff --git a/src/biogeochem/CNCIsoAtmTimeSeriesReadMod.F90 b/src/biogeochem/CNCIsoAtmTimeSeriesReadMod.F90 new file mode 100644 index 0000000000..5330dd9ba6 --- /dev/null +++ b/src/biogeochem/CNCIsoAtmTimeSeriesReadMod.F90 @@ -0,0 +1,319 @@ +module CIsoAtmTimeseriesMod + + !----------------------------------------------------------------------- + ! Module for transient atmospheric boundary to the c13 and c14 codes + ! + ! !USES: + use shr_kind_mod , only : r8 => shr_kind_r8 + use clm_time_manager , only : get_curr_date,get_days_per_year, get_curr_yearfrac + use clm_varcon , only : c14ratio, secspday + use shr_const_mod , only : SHR_CONST_PDB ! Ratio of C13/C12 + use clm_varctl , only : iulog + use abortutils , only : endrun + use spmdMod , only : masterproc + use shr_log_mod , only : errMsg => shr_log_errMsg + ! + implicit none + private + ! + ! !PUBLIC MEMBER FUNCTIONS: + public:: C14BombSpike ! Time series for C14 data + public:: C14_init_BombSpike ! Initialize C14 data series and read data in + public:: C13Timeseries ! Time series for C13 data + public:: C13_init_Timeseries ! Initialize C13 data series and read data in + + ! !PUBLIC TYPES: + logical , public :: use_c14_bombspike = .false. ! do we use time-varying atmospheric C14? + character(len=256) , public :: atm_c14_filename = ' ' ! file name of C14 input data + logical , public :: use_c13_timeseries = .false. ! do we use time-varying atmospheric C13? + character(len=256) , public :: atm_c13_filename = ' ' ! file name of C13 input data + integer, parameter , public :: nsectors_c14 = 3 ! Number of latitude sectors the C14 data has + + ! + ! !PRIVATE MEMBER FUNCTIONS: + private:: check_units ! Check the units of the data on the input file + + ! !PRIVATE TYPES: + real(r8), allocatable, private :: atm_c14file_time(:) ! time for C14 data + real(r8), allocatable, private :: atm_delta_c14(:,:) ! Delta C14 data + real(r8), allocatable, private :: atm_c13file_time(:) ! time for C13 data + real(r8), allocatable, private :: atm_delta_c13(:) ! Delta C13 data + real(r8), parameter :: time_axis_offset = 1850.0_r8 ! Offset in years of time on file + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + !----------------------------------------------------------------------- + +contains + + !----------------------------------------------------------------------- + subroutine C14BombSpike( rc14_atm ) + ! + ! !DESCRIPTION: + ! for transient simulation, read in an atmospheric timeseries file to impose bomb spike + ! + ! !ARGUMENTS: + implicit none + real(r8), intent(out) :: rc14_atm(nsectors_c14) ! Ratio of C14 to C12 + ! + ! !LOCAL VARIABLES: + integer :: yr, mon, day, tod, offset ! year, month, day, time-of-day, offset in secons + real(r8) :: dateyear ! Date converted to year + real(r8) :: delc14o2_atm(nsectors_c14) ! C14 delta units + integer :: fp, p, nt ! Indices + integer :: ind_below ! Time index below current time + integer :: ntim_atm_ts ! Number of times on file + real(r8) :: twt_1, twt_2 ! weighting fractions for interpolating + integer :: l ! Loop index of sectors + !----------------------------------------------------------------------- + + ! get current date + call get_curr_date(yr, mon, day, tod, offset) + dateyear = real(yr) + get_curr_yearfrac() + + ! find points in atm timeseries to interpolate between + ntim_atm_ts = size(atm_c14file_time) + ind_below = 0 + do nt = 1, ntim_atm_ts + if ((dateyear - time_axis_offset) >= atm_c14file_time(nt) ) then + ind_below = ind_below+1 + endif + end do + + ! loop over lat bands to pass all three to photosynthesis + do l = 1,nsectors_c14 + ! interpolate between nearest two points in atm c14 timeseries + if (ind_below .eq. 0 ) then + delc14o2_atm(l) = atm_delta_c14(l,1) + elseif (ind_below .eq. ntim_atm_ts ) then + delc14o2_atm(l) = atm_delta_c14(l,ntim_atm_ts) + else + twt_2 = min(1._r8, max(0._r8,((dateyear - time_axis_offset)-atm_c14file_time(ind_below)) & + / (atm_c14file_time(ind_below+1)-atm_c14file_time(ind_below)))) + twt_1 = 1._r8 - twt_2 + delc14o2_atm(l) = atm_delta_c14(l,ind_below) * twt_1 + atm_delta_c14(l,ind_below+1) * twt_2 + endif + + ! change delta units to ratio + rc14_atm(l) = (delc14o2_atm(l) * 1.e-3_r8 + 1._r8) * c14ratio + end do + + end subroutine C14BombSpike + + !----------------------------------------------------------------------- + subroutine C14_init_BombSpike() + ! + ! !DESCRIPTION: + ! read netcdf file containing a timeseries of atmospheric delta C14 values; save in module-level array + ! + ! !USES: + use ncdio_pio , only : ncd_pio_openfile, ncd_pio_closefile, file_desc_t, ncd_inqdlen, ncd_io + use fileutils , only : getfil + ! + ! !LOCAL VARIABLES: + implicit none + character(len=256) :: locfn ! local file name + type(file_desc_t) :: ncid ! netcdf id + integer :: dimid,varid ! input netCDF id's + integer :: ntim ! number of input data time samples + integer :: nsec ! number of input data sectors + integer :: t ! time index + logical :: readvar ! if variable read or not + character(len=*), parameter :: vname = 'Delta14co2_in_air' ! Variable name on file + !----------------------------------------------------------------------- + + if ( masterproc ) then + write(iulog, *) 'C14_init_BombSpike: preparing to open file:' + write(iulog, *) trim(locfn) + endif + + call getfil(atm_c14_filename, locfn, 0) + + call ncd_pio_openfile (ncid, trim(locfn), 0) + + call ncd_inqdlen(ncid,dimid,ntim,'time') + call ncd_inqdlen(ncid,dimid,nsec,'sector') + if ( nsec /= nsectors_c14 )then + call endrun(msg="ERROR: number of sectors on file not what's expected"//errMsg(sourcefile, __LINE__)) + end if + + !! allocate arrays based on size of netcdf timeseries + allocate(atm_c14file_time(ntim)) + allocate(atm_delta_c14(nsectors_c14,ntim)) + atm_delta_c14(:,:) = 0.0_r8 + + call ncd_io(ncid=ncid, varname='time', flag='read', data=atm_c14file_time, & + readvar=readvar) + if ( .not. readvar ) then + call endrun(msg="ERROR: time not on file"//errMsg(sourcefile, __LINE__)) + end if + + call ncd_io(ncid=ncid, varname=vname, flag='read', data=atm_delta_c14, & + readvar=readvar) + if ( .not. readvar ) then + call endrun(msg="ERROR: '//vname//' not on file"//errMsg(sourcefile, __LINE__)) + end if + ! Check units + call check_units( ncid, vname, "Modern" ) + call ncd_pio_closefile(ncid) + + ! check to make sure that time dimension is well behaved + do t = 2, ntim + if ( atm_c14file_time(t) - atm_c14file_time(t-1) <= 0._r8 ) then + write(iulog, *) 'C14_init_BombSpike: error. time axis must be monotonically increasing' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + end do + + end subroutine C14_init_BombSpike + + + !----------------------------------------------------------------------- + subroutine C13TimeSeries( rc13_atm ) + ! + ! !DESCRIPTION: + ! for transient pulse simulation, impose a time-varying atm boundary condition + ! + ! !ARGUMENTS: + implicit none + real(r8), intent(out) :: rc13_atm ! Ratio of C13 to C12 + ! + ! !LOCAL VARIABLES: + integer :: yr, mon, day, tod, offset ! year, month, day, time-of-day, and offset in seconds + real(r8) :: dateyear ! date translated to year + real(r8) :: delc13o2_atm ! Delta C13 + integer :: fp, p, nt ! Indices + integer :: ind_below ! Index of time in file before current time + integer :: ntim_atm_ts ! Number of times on file + real(r8) :: twt_1, twt_2 ! weighting fractions for interpolating + !----------------------------------------------------------------------- + + ! get current date + call get_curr_date(yr, mon, day, tod, offset) + dateyear = real(yr) + get_curr_yearfrac() + + ! find points in atm timeseries to interpolate between + ntim_atm_ts = size(atm_c13file_time) + ind_below = 0 + do nt = 1, ntim_atm_ts + if ((dateyear - time_axis_offset) >= atm_c13file_time(nt) ) then + ind_below = ind_below+1 + endif + end do + + ! interpolate between nearest two points in atm c13 timeseries + ! cdknotes. for now and for simplicity, just use the northern hemisphere values (sector 1) + if (ind_below .eq. 0 ) then + delc13o2_atm = atm_delta_c13(1) + elseif (ind_below .eq. ntim_atm_ts ) then + delc13o2_atm = atm_delta_c13(ntim_atm_ts) + else + twt_2 = min(1._r8, max(0._r8,((dateyear - time_axis_offset)-atm_c13file_time(ind_below)) & + / (atm_c13file_time(ind_below+1)-atm_c13file_time(ind_below)))) + twt_1 = 1._r8 - twt_2 + delc13o2_atm = atm_delta_c13(ind_below) * twt_1 + atm_delta_c13(ind_below+1) * twt_2 + endif + + ! change delta units to ratio, put on patch loop + + rc13_atm = (delc13o2_atm * 1.e-3_r8 + 1._r8) * SHR_CONST_PDB + + end subroutine C13TimeSeries + + !----------------------------------------------------------------------- + subroutine C13_init_TimeSeries() + ! + ! !DESCRIPTION: + ! read netcdf file containing a timeseries of atmospheric delta C13 values; save in module-level array + ! + ! !USES: + use ncdio_pio , only : ncd_pio_openfile, ncd_pio_closefile, file_desc_t, ncd_inqdlen, ncd_io + use fileutils , only : getfil + ! + ! !LOCAL VARIABLES: + implicit none + character(len=256) :: locfn ! local file name + type(file_desc_t) :: ncid ! netcdf id + integer :: dimid,varid ! input netCDF id's + integer :: ntim ! number of input data time samples + integer :: t ! Time index + logical :: readvar ! if variable read or not + character(len=*), parameter :: vname = 'delta13co2_in_air' ! Variable name on file + !----------------------------------------------------------------------- + + if ( masterproc ) then + write(iulog, *) 'C13_init_TimeSeries: preparing to open file:' + write(iulog, *) trim(locfn) + endif + + call getfil(atm_c13_filename, locfn, 0) + + call ncd_pio_openfile (ncid, trim(locfn), 0) + + call ncd_inqdlen(ncid,dimid,ntim,'time') + + !! allocate arrays based on size of netcdf timeseries + allocate(atm_c13file_time(ntim)) + allocate(atm_delta_c13(ntim)) + + call ncd_io(ncid=ncid, varname='time', flag='read', data=atm_c13file_time, & + readvar=readvar) + if ( .not. readvar ) then + call endrun(msg="ERROR: time not on file"//errMsg(sourcefile, __LINE__)) + end if + + call ncd_io(ncid=ncid, varname=vname, flag='read', data=atm_delta_c13, & + readvar=readvar) + if ( .not. readvar ) then + call endrun(msg="ERROR: '//vname//' not on file"//errMsg(sourcefile, __LINE__)) + end if + + ! Check units + call check_units( ncid, vname, "VPDB" ) + call ncd_pio_closefile(ncid) + + ! check to make sure that time dimension is well behaved + do t = 2, ntim + if ( atm_c13file_time(t) - atm_c13file_time(t-1) <= 0._r8 ) then + write(iulog, *) 'C13_init_TimeSeries: error. time axis must be monotonically increasing' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + end do + + end subroutine C13_init_TimeSeries + + !----------------------------------------------------------------------- + subroutine check_units( ncid, vname, relativeto ) + ! + ! !DESCRIPTION: + ! check that time and data units are what's expected or else abort + ! + ! !USES: + use ncdio_pio, only : file_desc_t, ncd_inqvid, ncd_getatt, var_desc_t + ! !ARGUMENTS: + implicit none + type(file_desc_t), intent(inout) :: ncid ! netcdf id + character(len=*), intent(in) :: vname ! Variable name + character(len=*), intent(in) :: relativeto ! What are data units relative to + ! + ! !LOCAL VARIABLES: + type(var_desc_t) :: vardesc ! variable descriptor + integer :: varid ! variable index + character(len=50) :: units ! Data units + character(len=50) :: t_units_expected ! Time units to expect + + call ncd_inqvid( ncid, 'time', varid, vardesc ) + call ncd_getatt( ncid, varid, "units", units ) + write(t_units_expected,'("years since", I5, "-01-01 0:0:0.0")' ) nint(time_axis_offset) + if ( trim(units) /= t_units_expected )then + call endrun(msg="ERROR: time units on file are NOT what's expected"//errMsg(sourcefile, __LINE__)) + end if + call ncd_inqvid( ncid, vname, varid, vardesc ) + call ncd_getatt( ncid, varid, "units", units ) + if ( trim(units) /= "per mil, relative to "//relativeto )then + call endrun(msg="ERROR: units on file for "//vname//" are NOT what's expected"//errMsg(sourcefile, __LINE__)) + end if + end subroutine check_units + + +end module CIsoAtmTimeseriesMod diff --git a/src/biogeochem/CNCIsoFluxMod.F90 b/src/biogeochem/CNCIsoFluxMod.F90 index 0194eebbca..a92ab44e47 100644 --- a/src/biogeochem/CNCIsoFluxMod.F90 +++ b/src/biogeochem/CNCIsoFluxMod.F90 @@ -18,6 +18,8 @@ module CNCIsoFluxMod use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type use ColumnType , only : col use PatchType , only : patch + use clm_varctl , only : use_crop + use clm_varctl , only : use_grainproduct ! implicit none private @@ -70,7 +72,7 @@ subroutine CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & character(len=*) , intent(in) :: isotope ! 'c13' or 'c14' ! ! !LOCAL VARIABLES: - integer :: fp,pi,l,fc,cc,j + integer :: fp,pi,l,fc,cc,j,p integer :: cdp !----------------------------------------------------------------------- @@ -93,7 +95,7 @@ subroutine CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & ! of each argument, these bounds will need to be passed in, and - importantly for ! threading to work properly - the subroutine calls will need to be changed so that ! instead of 'call CIsoFluxCalc(foo, ...)' we have 'call CIsoFluxCalc(foo(begp:endp), ...)'. - + call CIsoFluxCalc(& iso_cnveg_cf%leafc_xfer_to_leafc_patch , cnveg_cf%leafc_xfer_to_leafc_patch, & iso_cnveg_cs%leafc_xfer_patch , cnveg_cs%leafc_xfer_patch, & @@ -379,6 +381,93 @@ subroutine CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & iso_cnveg_cs%gresp_storage_patch , cnveg_cs%gresp_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) + call CIsoFluxCalc(& + iso_cnveg_cf%soilc_change_patch , cnveg_cf%soilc_change_patch, & + iso_cnveg_cs%cpool_patch , cnveg_cs%cpool_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + ! Note that cpool_to_resp_patch is a diagnostic flux and therefore this Iso flux calculation + ! not strictly required. + call CIsoFluxCalc(& + iso_cnveg_cf%cpool_to_resp_patch , cnveg_cf%cpool_to_resp_patch, & + iso_cnveg_cs%cpool_patch , cnveg_cs%cpool_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + if ( use_crop )then + call CIsoFluxCalc(& + iso_cnveg_cf%grainc_xfer_to_grainc_patch , cnveg_cf%grainc_xfer_to_grainc_patch, & + iso_cnveg_cs%grainc_xfer_patch , cnveg_cs%grainc_xfer_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%grainc_to_food_patch , cnveg_cf%grainc_to_food_patch, & + iso_cnveg_cs%grainc_patch , cnveg_cs%grainc_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%grainc_to_seed_patch , cnveg_cf%grainc_to_seed_patch, & + iso_cnveg_cs%grainc_patch , cnveg_cs%grainc_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%crop_seedc_to_leaf_patch , cnveg_cf%crop_seedc_to_leaf_patch, & + iso_cnveg_cs%totvegc_patch , cnveg_cs%totvegc_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%grain_curmr_patch , cnveg_cf%grain_curmr_patch, & + iso_cnveg_cs%cpool_patch , cnveg_cs%cpool_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%grain_xsmr_patch , cnveg_cf%grain_xsmr_patch, & + iso_cnveg_cs%totvegc_patch , cnveg_cs%totvegc_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%cpool_grain_gr_patch , cnveg_cf%cpool_grain_gr_patch, & + iso_cnveg_cs%cpool_patch , cnveg_cs%cpool_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%cpool_to_grainc_patch , cnveg_cf%cpool_to_grainc_patch, & + iso_cnveg_cs%cpool_patch , cnveg_cs%cpool_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%cpool_to_grainc_storage_patch , cnveg_cf%cpool_to_grainc_storage_patch, & + iso_cnveg_cs%cpool_patch , cnveg_cs%cpool_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%transfer_grain_gr_patch , cnveg_cf%transfer_grain_gr_patch, & + iso_cnveg_cs%gresp_xfer_patch , cnveg_cs%gresp_xfer_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%cpool_grain_storage_gr_patch , cnveg_cf%cpool_grain_storage_gr_patch, & + iso_cnveg_cs%cpool_patch , cnveg_cs%cpool_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%grainc_storage_to_xfer_patch , cnveg_cf%grainc_storage_to_xfer_patch, & + iso_cnveg_cs%grainc_storage_patch , cnveg_cs%grainc_storage_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + call CIsoFluxCalc(& + iso_cnveg_cf%livestemc_to_litter_patch , cnveg_cf%livestemc_to_litter_patch, & + iso_cnveg_cs%livestemc_patch , cnveg_cs%livestemc_patch, & + num_soilp , filter_soilp, 1._r8, 0, isotope) + + if (use_grainproduct) then + do fp = 1,num_soilp + p = filter_soilp(fp) + iso_cnveg_cf%grainc_to_cropprodc_patch(p) = iso_cnveg_cf%grainc_to_food_patch(p) + iso_cnveg_cf%grain_mr_patch(p) = iso_cnveg_cf%grain_xsmr_patch(p) + iso_cnveg_cf%grain_curmr_patch(p) + end do + endif + end if + ! call routine to shift patch-level litterfall fluxes to column, for isotopes ! the non-isotope version of this routine is called in CNPhenologyMod.F90 ! For later clean-up, it would be possible to generalize this function to operate on a single @@ -446,6 +535,7 @@ subroutine CIsoFlux2(num_soilc, filter_soilc, num_soilp , filter_soilp, & type(cnveg_carbonflux_type) , intent(inout) :: iso_cnveg_carbonflux_inst type(cnveg_carbonstate_type) , intent(in) :: iso_cnveg_carbonstate_inst character(len=*) , intent(in) :: isotope ! 'c13' or 'c14' + ! ! !LOCAL VARIABLES: integer :: fp,pi @@ -459,12 +549,10 @@ subroutine CIsoFlux2(num_soilc, filter_soilc, num_soilp , filter_soilp, & ) ! patch-level gap mortality fluxes - call CIsoFluxCalc(& iso_cnveg_cf%m_leafc_to_litter_patch , cnveg_cf%m_leafc_to_litter_patch, & iso_cnveg_cs%leafc_patch , cnveg_cs%leafc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - call CIsoFluxCalc(& iso_cnveg_cf%m_leafc_storage_to_litter_patch , cnveg_cf%m_leafc_storage_to_litter_patch, & iso_cnveg_cs%leafc_storage_patch , cnveg_cs%leafc_storage_patch, & @@ -589,6 +677,7 @@ subroutine CIsoFlux2h(num_soilc , filter_soilc, num_soilp , filter_soilp, & type(cnveg_carbonflux_type) , intent(inout) :: iso_cnveg_carbonflux_inst type(cnveg_carbonstate_type) , intent(in) :: iso_cnveg_carbonstate_inst character(len=*) , intent(in) :: isotope ! 'c13' or 'c14' + !----------------------------------------------------------------------- associate( & @@ -599,7 +688,7 @@ subroutine CIsoFlux2h(num_soilc , filter_soilc, num_soilp , filter_soilp, & ) ! patch-level gap mortality fluxes - + call CIsoFluxCalc(& iso_cnveg_cf%hrv_leafc_to_litter_patch , cnveg_cf%hrv_leafc_to_litter_patch, & iso_cnveg_cs%leafc_patch , cnveg_cs%leafc_patch, & @@ -700,9 +789,9 @@ subroutine CIsoFlux2h(num_soilc , filter_soilc, num_soilp , filter_soilp, & iso_cnveg_cs%gresp_xfer_patch , cnveg_cs%gresp_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - call CIsoFluxCalc(& + call CIsoFluxCalc(& iso_cnveg_cf%hrv_xsmrpool_to_atm_patch , cnveg_cf%hrv_xsmrpool_to_atm_patch, & - cnveg_cs%totvegc_patch , cnveg_cs%totvegc_patch, & + iso_cnveg_cs%totvegc_patch , cnveg_cs%totvegc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) ! call routine to shift patch-level gap mortality fluxes to column, @@ -875,102 +964,101 @@ subroutine CIsoFlux3(num_soilc , filter_soilc, num_soilp , filter_soilp, & iso_cnveg_cs%gresp_xfer_patch , cnveg_cs%gresp_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - call CIsoFluxCalc(& iso_cnveg_cf%m_leafc_to_litter_fire_patch , cnveg_cf%m_leafc_to_litter_fire_patch, & iso_cnveg_cs%leafc_patch , cnveg_cs%leafc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_leafc_storage_to_litter_fire_patch, cnveg_cf%m_leafc_storage_to_litter_fire_patch, & - iso_cnveg_cs%leafc_patch , cnveg_cs%leafc_patch, & + iso_cnveg_cs%leafc_storage_patch , cnveg_cs%leafc_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_leafc_xfer_to_litter_fire_patch , cnveg_cf%m_leafc_xfer_to_litter_fire_patch, & - iso_cnveg_cs%leafc_patch , cnveg_cs%leafc_patch, & + iso_cnveg_cs%leafc_xfer_patch , cnveg_cs%leafc_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livestemc_to_litter_fire_patch , cnveg_cf%m_livestemc_to_litter_fire_patch, & iso_cnveg_cs%livestemc_patch , cnveg_cs%livestemc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livestemc_storage_to_litter_fire_patch, cnveg_cf%m_livestemc_storage_to_litter_fire_patch, & iso_cnveg_cs%livestemc_storage_patch , cnveg_cs%livestemc_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livestemc_xfer_to_litter_fire_patch, cnveg_cf%m_livestemc_xfer_to_litter_fire_patch, & iso_cnveg_cs%livestemc_xfer_patch , cnveg_cs%livestemc_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livestemc_to_deadstemc_fire_patch, cnveg_cf%m_livestemc_to_deadstemc_fire_patch, & iso_cnveg_cs%livestemc_patch , cnveg_cs%livestemc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_deadstemc_storage_to_litter_fire_patch, cnveg_cf%m_deadstemc_storage_to_litter_fire_patch, & iso_cnveg_cs%deadstemc_storage_patch , cnveg_cs%deadstemc_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_deadstemc_xfer_to_litter_fire_patch, cnveg_cf%m_deadstemc_xfer_to_litter_fire_patch, & iso_cnveg_cs%deadstemc_xfer_patch , cnveg_cs%deadstemc_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_frootc_to_litter_fire_patch , cnveg_cf%m_frootc_to_litter_fire_patch, & iso_cnveg_cs%frootc_patch , cnveg_cs%frootc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_frootc_storage_to_litter_fire_patch, cnveg_cf%m_frootc_storage_to_litter_fire_patch, & iso_cnveg_cs%frootc_storage_patch , cnveg_cs%frootc_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_frootc_xfer_to_litter_fire_patch , cnveg_cf%m_frootc_xfer_to_litter_fire_patch, & iso_cnveg_cs%frootc_xfer_patch , cnveg_cs%frootc_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livecrootc_to_litter_fire_patch , cnveg_cf%m_livecrootc_to_litter_fire_patch, & iso_cnveg_cs%livecrootc_patch , cnveg_cs%livecrootc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livecrootc_storage_to_litter_fire_patch, cnveg_cf%m_livecrootc_storage_to_litter_fire_patch, & iso_cnveg_cs%livecrootc_storage_patch , cnveg_cs%livecrootc_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livecrootc_xfer_to_litter_fire_patch, cnveg_cf%m_livecrootc_xfer_to_litter_fire_patch, & iso_cnveg_cs%livecrootc_xfer_patch , cnveg_cs%livecrootc_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_livecrootc_to_deadcrootc_fire_patch, cnveg_cf%m_livecrootc_to_deadcrootc_fire_patch, & iso_cnveg_cs%livecrootc_patch , cnveg_cs%livecrootc_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_deadcrootc_storage_to_litter_fire_patch, cnveg_cf%m_deadcrootc_storage_to_litter_fire_patch, & iso_cnveg_cs%deadcrootc_storage_patch , cnveg_cs%deadcrootc_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_deadcrootc_xfer_to_litter_fire_patch, cnveg_cf%m_deadcrootc_xfer_to_litter_fire_patch, & iso_cnveg_cs%deadcrootc_xfer_patch , cnveg_cs%deadcrootc_xfer_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_gresp_storage_to_litter_fire_patch, cnveg_cf%m_gresp_storage_to_litter_fire_patch, & iso_cnveg_cs%gresp_storage_patch , cnveg_cs%gresp_storage_patch, & num_soilp , filter_soilp, 1._r8, 0, isotope) - + call CIsoFluxCalc(& iso_cnveg_cf%m_gresp_xfer_to_litter_fire_patch , cnveg_cf%m_gresp_xfer_to_litter_fire_patch, & iso_cnveg_cs%gresp_xfer_patch , cnveg_cs%gresp_xfer_patch, & @@ -1070,6 +1158,12 @@ subroutine CNCIsoLitterToColumn (num_soilc, filter_soilc, & ! called at the end of cn_phenology to gather all patch-level litterfall fluxes ! to the column level and assign them to the three litter pools ! + ! !USES: +!DML + use pftconMod , only : npcropmin + use clm_varctl , only : use_grainproduct +!DML + ! !ARGUMENTS: integer , intent(in) :: num_soilc ! number of soil columns in filter integer , intent(in) :: filter_soilc(:) ! filter for soil columns @@ -1092,10 +1186,14 @@ subroutine CNCIsoLitterToColumn (num_soilc, filter_soilc, & fr_flig => pftcon%fr_flig , & ! Input: fine root litter lignin fraction leaf_prof => soilbiogeochem_state_inst%leaf_prof_patch , & ! Input: [real(r8) (:,:) ] (1/m) profile of leaves - froot_prof => soilbiogeochem_state_inst%froot_prof_patch , & ! Input: [real(r8) (:,:) ] (1/m) profile of fine roots + froot_prof => soilbiogeochem_state_inst%froot_prof_patch , & ! Input: [real(r8) (:,:) ] (1/m) profile of fine roots - leafc_to_litter => iso_cnveg_carbonflux_inst%leafc_to_litter_patch , & ! Input: [real(r8) (:) ] - frootc_to_litter => iso_cnveg_carbonflux_inst%frootc_to_litter_patch , & ! Input: [real(r8) (:) ] + leafc_to_litter => iso_cnveg_carbonflux_inst%leafc_to_litter_patch , & ! Input: [real(r8) (:) ] + frootc_to_litter => iso_cnveg_carbonflux_inst%frootc_to_litter_patch , & ! Input: [real(r8) (:) ] +!DML + livestemc_to_litter => iso_cnveg_carbonflux_inst%livestemc_to_litter_patch , & ! Input: [real(r8) (:) ] + grainc_to_food => iso_cnveg_carbonflux_inst%grainc_to_food_patch , & ! Input: [real(r8) (:) ] +!DML phenology_c_to_litr_met_c => iso_cnveg_carbonflux_inst%phenology_c_to_litr_met_c_col , & ! InOut: [real(r8) (:,:) ] C fluxes associated with phenology (litterfall and crop) to litter metabolic pool (gC/m3/s) phenology_c_to_litr_cel_c => iso_cnveg_carbonflux_inst%phenology_c_to_litr_cel_c_col , & ! InOut: [real(r8) (:,:) ] C fluxes associated with phenology (litterfall and crop) to litter cellulose pool (gC/m3/s) phenology_c_to_litr_lig_c => iso_cnveg_carbonflux_inst%phenology_c_to_litr_lig_c_col & ! InOut: [real(r8) (:,:) ] C fluxes associated with phenology (litterfall and crop) to litter lignin pool (gC/m3/s) @@ -1124,6 +1222,29 @@ subroutine CNCIsoLitterToColumn (num_soilc, filter_soilc, & + frootc_to_litter(p) * fr_fcel(ivt(p)) * wtcol(p) * froot_prof(p,j) phenology_c_to_litr_lig_c(c,j) = phenology_c_to_litr_lig_c(c,j) & + frootc_to_litter(p) * fr_flig(ivt(p)) * wtcol(p) * froot_prof(p,j) + +!DML + if (ivt(p) >= npcropmin) then ! add livestemc to litter + ! stem litter carbon fluxes + phenology_c_to_litr_met_c(c,j) = phenology_c_to_litr_met_c(c,j) & + + livestemc_to_litter(p) * lf_flab(ivt(p)) * wtcol(p) * leaf_prof(p,j) + phenology_c_to_litr_cel_c(c,j) = phenology_c_to_litr_cel_c(c,j) & + + livestemc_to_litter(p) * lf_fcel(ivt(p)) * wtcol(p) * leaf_prof(p,j) + phenology_c_to_litr_lig_c(c,j) = phenology_c_to_litr_lig_c(c,j) & + + livestemc_to_litter(p) * lf_flig(ivt(p)) * wtcol(p) * leaf_prof(p,j) + + if (.not. use_grainproduct) then + ! grain litter carbon fluxes + phenology_c_to_litr_met_c(c,j) = phenology_c_to_litr_met_c(c,j) & + + grainc_to_food(p) * lf_flab(ivt(p)) * wtcol(p) * leaf_prof(p,j) + phenology_c_to_litr_cel_c(c,j) = phenology_c_to_litr_cel_c(c,j) & + + grainc_to_food(p) * lf_fcel(ivt(p)) * wtcol(p) * leaf_prof(p,j) + phenology_c_to_litr_lig_c(c,j) = phenology_c_to_litr_lig_c(c,j) & + + grainc_to_food(p) * lf_flig(ivt(p)) * wtcol(p) * leaf_prof(p,j) + end if + + end if +!DML end if end if @@ -1469,7 +1590,7 @@ subroutine CIsoFluxCalc(& ! loop over the supplied filter do f = 1,num i = filter(f) - if (ctot_state(i) /= 0._r8) then + if (ctot_state(i) /= 0._r8 .and. ciso_state(i) /= 0._r8) then ciso_flux(i) = ctot_flux(i) * (ciso_state(i)/ctot_state(i)) * frax else ciso_flux(i) = 0._r8 diff --git a/src/biogeochem/CNCStateUpdate1Mod.F90 b/src/biogeochem/CNCStateUpdate1Mod.F90 index 38d2678d8a..ac7cb89162 100644 --- a/src/biogeochem/CNCStateUpdate1Mod.F90 +++ b/src/biogeochem/CNCStateUpdate1Mod.F90 @@ -19,7 +19,7 @@ module CNCStateUpdate1Mod use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type use SoilBiogeochemCarbonStateType , only : soilbiogeochem_carbonstate_type use PatchType , only : patch - use clm_varctl , only : use_ed, use_cn, iulog + use clm_varctl , only : use_fates, use_cn, iulog ! implicit none private @@ -65,7 +65,7 @@ subroutine CStateUpdateDynPatch(bounds, num_soilc_with_inactive, filter_soilc_wi dt = get_step_size_real() - if (.not. use_ed) then + if (.not. use_fates) then do j = 1,nlevdecomp do fc = 1, num_soilc_with_inactive c = filter_soilc_with_inactive(fc) @@ -88,7 +88,7 @@ subroutine CStateUpdateDynPatch(bounds, num_soilc_with_inactive, filter_soilc_wi end if ! TODO(wjs, 2017-01-02) Do we need to move some of the FATES fluxes into here (from - ! CStateUpdate1) if use_ed is true? Specifically, some portion or all of the fluxes + ! CStateUpdate1) if use_fates is true? Specifically, some portion or all of the fluxes ! from these updates in CStateUpdate1: ! cf_soil%decomp_cpools_sourcesink_col(c,j,i_met_lit) = cf_soil%FATES_c_to_litr_lab_c_col(c,j) * dt ! cf_soil%decomp_cpools_sourcesink_col(c,j,i_cel_lit) = cf_soil%FATES_c_to_litr_cel_c_col(c,j) * dt @@ -130,7 +130,6 @@ subroutine CStateUpdate0(num_soilp, filter_soilp, & ! gross photosynthesis fluxes do fp = 1,num_soilp p = filter_soilp(fp) - cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) + cf_veg%psnsun_to_cpool_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) + cf_veg%psnshade_to_cpool_patch(p)*dt end do @@ -189,7 +188,7 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! Below is the input into the soil biogeochemistry model ! plant to litter fluxes - if (.not. use_ed) then + if (.not. use_fates) then do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) @@ -207,8 +206,8 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cf_soil%decomp_cpools_sourcesink_col(c,j,i_cwd) = 0._r8 end do end do - else !use_ed - ! here add all ed litterfall and CWD breakdown to litter fluxes + else !use_fates + ! here add all fates litterfall and CWD breakdown to litter fluxes do j = 1,nlevdecomp do fc = 1,num_soilc c = filter_soilc(fc) @@ -245,7 +244,7 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end if end do - if (.not. use_ed) then + if (.not. use_fates) then do fp = 1,num_soilp p = filter_soilp(fp) c = patch%column(p) @@ -300,6 +299,7 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cpool_delta = cs_veg%cpool_patch(p) ! maintenance respiration fluxes from cpool + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_xsmrpool_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%leaf_curmr_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%froot_curmr_patch(p)*dt @@ -326,16 +326,6 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%livestem_xsmr_patch(p)*dt cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%livecroot_xsmr_patch(p)*dt end if - if (ivt(p) >= npcropmin) then ! skip 2 generic crops - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%livestem_xsmr_patch(p)*dt - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%grain_xsmr_patch(p)*dt - if (harvdate(p) < 999) then ! beginning at harvest, send to atm - ! TODO (mv, 11-02-2014) the following line is why the cf_veg is an intent(inout) - ! fluxes should not be updated in this module - not sure where this belongs - cf_veg%xsmrpool_to_atm_patch(p) = cf_veg%xsmrpool_to_atm_patch(p) + cs_veg%xsmrpool_patch(p)/dt - cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%xsmrpool_to_atm_patch(p)*dt - end if - end if ! allocation fluxes if (carbon_resp_opt == 1) then @@ -353,6 +343,7 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_frootc_patch(p)*dt cs_veg%frootc_patch(p) = cs_veg%frootc_patch(p) + cf_veg%cpool_to_frootc_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_to_frootc_storage_patch(p)*dt + cs_veg%frootc_storage_patch(p) = cs_veg%frootc_storage_patch(p) + cf_veg%cpool_to_frootc_storage_patch(p)*dt if (woody(ivt(p)) == 1._r8) then if (carbon_resp_opt == 1) then @@ -396,10 +387,10 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%grainc_storage_patch(p) = cs_veg%grainc_storage_patch(p) + cf_veg%cpool_to_grainc_storage_patch(p)*dt end if - ! growth respiration fluxes for current growth cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_leaf_gr_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_froot_gr_patch(p)*dt + if (woody(ivt(p)) == 1._r8) then cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_livestem_gr_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_deadstem_gr_patch(p)*dt @@ -428,6 +419,7 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & ! growth respiration at time of storage cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_leaf_storage_gr_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_froot_storage_gr_patch(p)*dt + if (woody(ivt(p)) == 1._r8) then cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_livestem_storage_gr_patch(p)*dt cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_deadstem_storage_gr_patch(p)*dt @@ -436,7 +428,9 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & end if if (ivt(p) >= npcropmin) then ! skip 2 generic crops cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_livestem_storage_gr_patch(p)*dt + cs_veg%cpool_patch(p) = cs_veg%cpool_patch(p) - cf_veg%cpool_grain_storage_gr_patch(p)*dt + end if ! growth respiration stored for release during transfer growth @@ -467,6 +461,31 @@ subroutine CStateUpdate1( num_soilc, filter_soilc, num_soilp, filter_soilp, & cs_veg%grainc_storage_patch(p) = cs_veg%grainc_storage_patch(p) - cf_veg%grainc_storage_to_xfer_patch(p)*dt cs_veg%grainc_xfer_patch(p) = cs_veg%grainc_xfer_patch(p) + cf_veg%grainc_storage_to_xfer_patch(p)*dt end if + + if (ivt(p) >= npcropmin) then ! skip 2 generic crops + cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%livestem_xsmr_patch(p)*dt + cs_veg%xsmrpool_patch(p) = cs_veg%xsmrpool_patch(p) - cf_veg%grain_xsmr_patch(p)*dt + if (harvdate(p) < 999) then ! beginning at harvest, send to atm + ! TODO (mv, 11-02-2014) the following lines are why the cf_veg is + ! an intent(inout) + ! fluxes should not be updated in this module - not sure where + ! this belongs + ! DML (06-20-2017) While debugging crop isotope code, found that cpool_patch and frootc_patch + ! could occasionally be very small but nonzero numbers after crop harvest, which persists + ! through to next planting and for reasons that could not 100% + ! isolate, caused C12/C13 ratios to occasionally go out of + ! bounds. Zeroing out these small pools and putting them into the flux to the + ! atmosphere solved many of the crop isotope problems + + cf_veg%xsmrpool_to_atm_patch(p) = cf_veg%xsmrpool_to_atm_patch(p) + cs_veg%xsmrpool_patch(p)/dt + cs_veg%xsmrpool_patch(p) = 0._r8 + cf_veg%xsmrpool_to_atm_patch(p) = cf_veg%xsmrpool_to_atm_patch(p) + cs_veg%cpool_patch(p)/dt + cs_veg%cpool_patch(p) = 0._r8 + cf_veg%xsmrpool_to_atm_patch(p) = cf_veg%xsmrpool_to_atm_patch(p) + cs_veg%frootc_patch(p)/dt + cs_veg%frootc_patch(p) = 0._r8 + end if + end if + end do ! end of patch loop end if diff --git a/src/biogeochem/CNDVEstablishmentMod.F90 b/src/biogeochem/CNDVEstablishmentMod.F90 index 555c8e902c..a387417da9 100644 --- a/src/biogeochem/CNDVEstablishmentMod.F90 +++ b/src/biogeochem/CNDVEstablishmentMod.F90 @@ -52,7 +52,7 @@ subroutine Establishment(bounds, & type(dgvs_type) , intent(inout) :: dgvs_inst ! ! !LOCAL VARIABLES: - integer :: g,l,p,m ! indices + integer :: g,l,c,p,m ! indices integer :: fn, filterg(bounds%begg-bounds%endg+1) ! local gridcell filter for error check ! ! gridcell level variables @@ -108,7 +108,7 @@ subroutine Establishment(bounds, & tcmin => dgv_ecophyscon%tcmin , & ! Input: [real(r8) (:) ] ecophys const - minimum coldest monthly mean temperature gddmin => dgv_ecophyscon%gddmin , & ! Input: [real(r8) (:) ] ecophys const - minimum growing degree days (at or above 5 C) - prec365 => atm2lnd_inst%prec365_patch , & ! Input: [real(r8) (:) ] 365-day running mean of tot. precipitation + prec365 => atm2lnd_inst%prec365_col , & ! Input: [real(r8) (:) ] 365-day running mean of tot. precipitation agddtw => dgvs_inst%agddtw_patch , & ! Input: [real(r8) (:) ] accumulated growing degree days above twmax agdd20 => dgvs_inst%agdd20_patch , & ! Input: [real(r8) (:) ] 20-yr running mean of agdd @@ -187,6 +187,7 @@ subroutine Establishment(bounds, & end do do p = bounds%begp,bounds%endp + c = patch%column(p) l = patch%landunit(p) ! Case 1 -- patch ceases to exist -kill patches not adapted to current climate @@ -200,7 +201,7 @@ subroutine Establishment(bounds, & ! Case 2 -- patch begins to exist - introduce newly "adapted" patches if (lun%itype(l) == istsoil) then - if (.not. present(p) .and. prec365(p) >= prec_min_estab .and. estab(p)) then + if (.not. present(p) .and. prec365(c) >= prec_min_estab .and. estab(p)) then if (twmax(ivt(p)) > 999._r8 .or. agddtw(p) == 0._r8) then present(p) = .true. diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90 index ee61d7f8ee..a8ed44cd97 100644 --- a/src/biogeochem/CNDriverMod.F90 +++ b/src/biogeochem/CNDriverMod.F90 @@ -6,12 +6,13 @@ module CNDriverMod ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : use_c13, use_c14, use_ed, use_dynroot + use clm_varctl , only : use_c13, use_c14, use_fates, use_dynroot use dynSubgridControlMod , only : get_do_harvest use decompMod , only : bounds_type use perf_mod , only : t_startf, t_stopf use clm_varctl , only : use_century_decomp, use_nitrif_denitrif, use_nguardrail use clm_varctl , only : use_crop + use CNSharedParamsMod , only : use_fun use CNVegStateType , only : cnveg_state_type use CNVegCarbonStateType , only : cnveg_carbonstate_type use CNVegCarbonFluxType , only : cnveg_carbonflux_type @@ -281,9 +282,11 @@ subroutine CNDriverNoLeaching(bounds, call CNNFert(bounds, num_soilc,filter_soilc, & cnveg_nitrogenflux_inst, soilbiogeochem_nitrogenflux_inst) - call CNSoyfix (bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & - waterstate_inst, crop_inst, cnveg_state_inst, cnveg_nitrogenflux_inst , & - soilbiogeochem_state_inst, soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) + if (.not. use_fun) then ! if FUN is active, then soy fixation handled by FUN + call CNSoyfix (bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & + waterstate_inst, crop_inst, cnveg_state_inst, cnveg_nitrogenflux_inst , & + soilbiogeochem_state_inst, soilbiogeochem_nitrogenstate_inst, soilbiogeochem_nitrogenflux_inst) + end if end if call t_startf('CNMResp') @@ -350,8 +353,10 @@ subroutine CNDriverNoLeaching(bounds, crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & - froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), phase=1) + froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & + phase=1) call t_stopf('CNPhenology_phase1') call t_startf('CNFUNInit') @@ -443,8 +448,10 @@ subroutine CNDriverNoLeaching(bounds, crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & - froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), phase=1) + froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & + phase=1) end if call CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & filter_soilp, num_pcropp, filter_pcropp, & @@ -452,8 +459,10 @@ subroutine CNDriverNoLeaching(bounds, crop_inst, canopystate_inst, soilstate_inst, dgvs_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & leaf_prof_patch=soilbiogeochem_state_inst%leaf_prof_patch(begp:endp,1:nlevdecomp_full), & - froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), phase=2) + froot_prof_patch=soilbiogeochem_state_inst%froot_prof_patch(begp:endp,1:nlevdecomp_full), & + phase=2) call t_stopf('CNPhenology') @@ -518,6 +527,7 @@ subroutine CNDriverNoLeaching(bounds, ! Set the carbon isotopic flux variables (except for gap-phase mortality and fire fluxes) if ( use_c13 ) then + call CIsoFlux1(num_soilc, filter_soilc, num_soilp, filter_soilp, & soilbiogeochem_state_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & diff --git a/src/biogeochem/CNFUNMod.F90 b/src/biogeochem/CNFUNMod.F90 index fa49290bd4..98adfc36e2 100644 --- a/src/biogeochem/CNFUNMod.F90 +++ b/src/biogeochem/CNFUNMod.F90 @@ -1472,7 +1472,6 @@ subroutine CNFUN(bounds,num_soilc, filter_soilc,num_soilp& Nactive_no3(p) = n_active_no3_acc_total(p)/dt + n_active_no3_retrans_total(p)/dt Nactive_nh4(p) = n_active_nh4_acc_total(p)/dt + n_active_nh4_retrans_total(p)/dt - Nactive(p) = Nactive_no3(p) + Nactive_nh4(p) + Nnonmyc_no3(p) + Nnonmyc_nh4(p) @@ -1489,6 +1488,7 @@ subroutine CNFUN(bounds,num_soilc, filter_soilc,num_soilp& Nuptake(p) = Nactive_no3(p) + Nactive_nh4(p) + Nnonmyc_no3(p) & + Nnonmyc_nh4(p) + Nfix(p) + Npassive(p) + & retransn_to_npool(p)+free_retransn_to_npool(p) + Nactive(p) = Nactive_no3(p) + Nactive_nh4(p) + Nnonmyc_no3(p) + Nnonmyc_nh4(p) ! free N goes straight to the npool, not throught Nuptake... sminn_to_plant_fun(p) = Nactive_no3(p) + Nactive_nh4(p) + Nnonmyc_no3(p) + Nnonmyc_nh4(p) + Nfix(p) + Npassive(p) diff --git a/src/biogeochem/CNFireBaseMod.F90 b/src/biogeochem/CNFireBaseMod.F90 index 60a2244038..04c3e232ed 100644 --- a/src/biogeochem/CNFireBaseMod.F90 +++ b/src/biogeochem/CNFireBaseMod.F90 @@ -49,11 +49,14 @@ module CNFireBaseMod ! !PUBLIC TYPES: public :: cnfire_base_type + integer, private, parameter :: num_fp = 2 ! Number of pools relevent for fire + integer, private, parameter :: lit_fp = 1 ! Pool for liter + integer, private, parameter :: cwd_fp = 2 ! Pool for CWD Course woody debris type, public :: cnfire_const_type ! !PRIVATE MEMBER DATA: real(r8) :: borealat = 40._r8 ! Latitude for boreal peat fires real(r8) :: lfuel=75._r8 ! lower threshold of fuel mass (gC/m2) for ignition, Li et al.(2014) - real(r8) :: ufuel=1050._r8 ! upper threshold of fuel mass(gC/m2) for ignition + real(r8) :: ufuel=650._r8 ! upper threshold of fuel mass(gC/m2) for ignition real(r8) :: g0=0.05_r8 ! g(W) when W=0 m/s real(r8) :: rh_low=30.0_r8 ! Relative humidty low (%) real(r8) :: rh_hgh=80.0_r8 ! Relative humidty high (%) @@ -65,6 +68,8 @@ module CNFireBaseMod real(r8) :: non_boreal_peatfire_c = 0.001_r8 ! c parameter for non-boreal peatland fire in Li et. al. (2013) (/hr) real(r8) :: cropfire_a1 = 0.3_r8 ! a1 parameter for cropland fire in (Li et. al., 2014) (/hr) real(r8) :: occur_hi_gdp_tree = 0.39_r8 ! fire occurance for high GDP areas that are tree dominated (fraction) + + real(r8) :: cmb_cmplt_fact(num_fp) = (/ 0.5_r8, 0.25_r8 /) ! combustion completion factor (unitless) end type ! @@ -157,13 +162,15 @@ subroutine CNFireReadNML( this, NLFilename ) character(len=*), parameter :: subname = 'CNFireReadNML' character(len=*), parameter :: nmlname = 'lifire_inparm' !----------------------------------------------------------------------- - real(r8) :: cli_scale, boreal_peatfire_c, pot_hmn_ign_counts_alpha, & - non_boreal_peatfire_c, cropfire_a1, & - rh_low, rh_hgh, bt_min, bt_max, occur_hi_gdp_tree + real(r8) :: cli_scale, boreal_peatfire_c, pot_hmn_ign_counts_alpha + real(r8) :: non_boreal_peatfire_c, cropfire_a1 + real(r8) :: rh_low, rh_hgh, bt_min, bt_max, occur_hi_gdp_tree + real(r8) :: lfuel, ufuel, cmb_cmplt_fact(num_fp) namelist /lifire_inparm/ cli_scale, boreal_peatfire_c, pot_hmn_ign_counts_alpha, & non_boreal_peatfire_c, cropfire_a1, & - rh_low, rh_hgh, bt_min, bt_max, occur_hi_gdp_tree + rh_low, rh_hgh, bt_min, bt_max, occur_hi_gdp_tree, & + lfuel, ufuel, cmb_cmplt_fact if ( this%need_lightning_and_popdens ) then cli_scale = cnfire_const%cli_scale @@ -173,9 +180,12 @@ subroutine CNFireReadNML( this, NLFilename ) cropfire_a1 = cnfire_const%cropfire_a1 rh_low = cnfire_const%rh_low rh_hgh = cnfire_const%rh_hgh + lfuel = cnfire_const%lfuel + ufuel = cnfire_const%ufuel bt_min = cnfire_const%bt_min bt_max = cnfire_const%bt_max occur_hi_gdp_tree = cnfire_const%occur_hi_gdp_tree + cmb_cmplt_fact(:) = cnfire_const%cmb_cmplt_fact(:) ! Initialize options to default values, in case they are not specified in ! the namelist @@ -202,9 +212,12 @@ subroutine CNFireReadNML( this, NLFilename ) call shr_mpi_bcast (cropfire_a1 , mpicom) call shr_mpi_bcast (rh_low , mpicom) call shr_mpi_bcast (rh_hgh , mpicom) + call shr_mpi_bcast (lfuel , mpicom) + call shr_mpi_bcast (ufuel , mpicom) call shr_mpi_bcast (bt_min , mpicom) call shr_mpi_bcast (bt_max , mpicom) call shr_mpi_bcast (occur_hi_gdp_tree , mpicom) + call shr_mpi_bcast (cmb_cmplt_fact , mpicom) cnfire_const%cli_scale = cli_scale cnfire_const%boreal_peatfire_c = boreal_peatfire_c @@ -213,9 +226,12 @@ subroutine CNFireReadNML( this, NLFilename ) cnfire_const%cropfire_a1 = cropfire_a1 cnfire_const%rh_low = rh_low cnfire_const%rh_hgh = rh_hgh + cnfire_const%lfuel = lfuel + cnfire_const%ufuel = ufuel cnfire_const%bt_min = bt_min cnfire_const%bt_max = bt_max cnfire_const%occur_hi_gdp_tree = occur_hi_gdp_tree + cnfire_const%cmb_cmplt_fact(:) = cmb_cmplt_fact(:) if (masterproc) then write(iulog,*) ' ' @@ -386,6 +402,8 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte fr_flab => pftcon%fr_flab , & ! Input: fr_fcel => pftcon%fr_fcel , & ! Input: fr_flig => pftcon%fr_flig , & ! Input: + + cmb_cmplt_fact => cnfire_const%cmb_cmplt_fact , & ! Input: [real(r8) (:) ] Combustion completion factor (unitless) nind => dgvs_inst%nind_patch , & ! Input: [real(r8) (:) ] number of individuals (#/m2) @@ -630,6 +648,8 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte m_leafc_xfer_to_litter_fire(p) = leafc_xfer(p) * f * & (1._r8 - cc_other(patch%itype(p))) * & fm_other(patch%itype(p)) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent fraction of transport from livestem/livecroot to litter + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 (stem and root live or dead assumed to have the same transport) m_livestemc_to_litter_fire(p) = livestemc(p) * f * & (1._r8 - cc_lstem(patch%itype(p))) * & fm_droot(patch%itype(p)) @@ -639,9 +659,13 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte m_livestemc_xfer_to_litter_fire(p) = livestemc_xfer(p) * f * & (1._r8 - cc_other(patch%itype(p))) * & fm_other(patch%itype(p)) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent the fraction of plant-tissue mortality for deadstem/deadcroot + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 m_livestemc_to_deadstemc_fire(p) = livestemc(p) * f * & (1._r8 - cc_lstem(patch%itype(p))) * & (fm_lstem(patch%itype(p))-fm_droot(patch%itype(p))) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent fraction of transport from deadstem/deadcroot to litter + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 (stem and root live or dead assumed to have the same transport) m_deadstemc_to_litter_fire(p) = deadstemc(p) * f * m * & (1._r8 - cc_dstem(patch%itype(p))) * & fm_droot(patch%itype(p)) @@ -659,6 +683,8 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte m_frootc_xfer_to_litter_fire(p) = frootc_xfer(p) * f * & (1._r8- cc_other(patch%itype(p))) * & fm_other(patch%itype(p)) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent fraction of transport from livestem/livecroot to litter + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 (stem and root live or dead assumed to have the same transport) m_livecrootc_to_litter_fire(p) = livecrootc(p) * f * & fm_droot(patch%itype(p)) m_livecrootc_storage_to_litter_fire(p) = livecrootc_storage(p) * f * & @@ -695,6 +721,8 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte m_leafn_xfer_to_litter_fire(p) = leafn_xfer(p) * f * & (1._r8 - cc_other(patch%itype(p))) * & fm_other(patch%itype(p)) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent fraction of transport from livestem/livecroot to litter + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 (stem and root live or dead assumed to have the same transport) m_livestemn_to_litter_fire(p) = livestemn(p) * f * & (1._r8 - cc_lstem(patch%itype(p))) * & fm_droot(patch%itype(p)) @@ -704,9 +732,13 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte m_livestemn_xfer_to_litter_fire(p) = livestemn_xfer(p) * f * & (1._r8 - cc_other(patch%itype(p))) * & fm_other(patch%itype(p)) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent the fraction of plant-tissue mortality for deadstem/deadcroot + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 m_livestemn_to_deadstemn_fire(p) = livestemn(p) * f * & (1._r8 - cc_lstem(patch%itype(p))) * & (fm_lstem(patch%itype(p))-fm_droot(patch%itype(p))) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent fraction of transport from deadstem/deadcroot to litter + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 (stem and root live or dead assumed to have the same transport) m_deadstemn_to_litter_fire(p) = deadstemn(p) * f * m * & (1._r8 - cc_dstem(patch%itype(p))) * & fm_droot(patch%itype(p)) @@ -724,6 +756,8 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte m_frootn_xfer_to_litter_fire(p) = frootn_xfer(p) * f * & (1._r8 - cc_other(patch%itype(p))) * & fm_other(patch%itype(p)) + ! NOTE: It looks incorrect to use fm_droot here, but it's used to represent fraction of transport from livestem/livecroot to litter + ! EBK Oct/06/2017 see bug 2516 http://bugs.cgd.ucar.edu/show_bug.cgi?id=2516 (stem and root live or dead assumed to have the same transport) m_livecrootn_to_litter_fire(p) = livecrootn(p) * f * & fm_droot(patch%itype(p)) m_livecrootn_storage_to_litter_fire(p) = livecrootn_storage(p) * f * & @@ -849,28 +883,28 @@ subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filte f = farea_burned(c) - ! change CC for litter from 0.4_r8 to 0.5_r8 and CC for CWD from 0.2_r8 - ! to 0.25_r8 according to Li et al.(2014) do j = 1, nlevdecomp ! carbon fluxes do l = 1, ndecomp_pools if ( is_litter(l) ) then - m_decomp_cpools_to_fire_vr(c,j,l) = decomp_cpools_vr(c,j,l) * f * 0.5_r8 + m_decomp_cpools_to_fire_vr(c,j,l) = decomp_cpools_vr(c,j,l) * f * & + cmb_cmplt_fact(lit_fp) end if if ( is_cwd(l) ) then m_decomp_cpools_to_fire_vr(c,j,l) = decomp_cpools_vr(c,j,l) * & - (f-baf_crop(c)) * 0.25_r8 + (f-baf_crop(c)) * cmb_cmplt_fact(cwd_fp) end if end do ! nitrogen fluxes do l = 1, ndecomp_pools if ( is_litter(l) ) then - m_decomp_npools_to_fire_vr(c,j,l) = decomp_npools_vr(c,j,l) * f * 0.5_r8 + m_decomp_npools_to_fire_vr(c,j,l) = decomp_npools_vr(c,j,l) * f * & + cmb_cmplt_fact(lit_fp) end if if ( is_cwd(l) ) then m_decomp_npools_to_fire_vr(c,j,l) = decomp_npools_vr(c,j,l) * & - (f-baf_crop(c)) * 0.25_r8 + (f-baf_crop(c)) * cmb_cmplt_fact(cwd_fp) end if end do diff --git a/src/biogeochem/CNFireLi2016Mod.F90 b/src/biogeochem/CNFireLi2016Mod.F90 index ae3b64e0d5..e108462244 100644 --- a/src/biogeochem/CNFireLi2016Mod.F90 +++ b/src/biogeochem/CNFireLi2016Mod.F90 @@ -597,7 +597,7 @@ subroutine CNFireArea (this, bounds, num_soilc, filter_soilc, num_soilp, filter_ afuel =min(1._r8,max(0._r8,(fuelc(c)-2500._r8)/(5000._r8-2500._r8))) arh=1._r8-max(0._r8, min(1._r8,(forc_rh(g)-rh_low)/(rh_hgh-rh_low))) arh30=1._r8-max(0.7_r8, min(1._r8,rh30_col(c)/90._r8)) - if (forc_rh(g) < rh_hgh.and. wtlf(c) > 0._r8 .and. forc_t(c)> SHR_CONST_TKFRZ)then + if (forc_rh(g) < rh_hgh.and. wtlf(c) > 0._r8 .and. tsoi17(c)> SHR_CONST_TKFRZ)then fire_m = ((afuel*arh30+(1._r8-afuel)*arh)**1.5_r8)*((1._r8 -max(0._r8,& min(1._r8,(btran_col(c)/wtlf(c)-bt_min)/(bt_max-bt_min))))**0.5_r8) else diff --git a/src/biogeochem/CNMRespMod.F90 b/src/biogeochem/CNMRespMod.F90 index e407aa6f0c..3a7052d0bb 100644 --- a/src/biogeochem/CNMRespMod.F90 +++ b/src/biogeochem/CNMRespMod.F90 @@ -137,7 +137,7 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - ! FIX(SPM,032414) this shouldn't even be called with ED on. + ! FIX(SPM,032414) this shouldn't even be called with fates on. ! subroutine CNMResp(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, & canopystate_inst, soilstate_inst, temperature_inst, photosyns_inst, & diff --git a/src/biogeochem/CNPhenologyMod.F90 b/src/biogeochem/CNPhenologyMod.F90 index a216477530..9d66373085 100644 --- a/src/biogeochem/CNPhenologyMod.F90 +++ b/src/biogeochem/CNPhenologyMod.F90 @@ -92,7 +92,6 @@ module CNPhenologyMod integer :: jdayyrstart(inSH) ! julian day of start of year real(r8), private :: initial_seed_at_planting = 3._r8 ! Initial seed at planting - logical, private :: subtract_cropseed = .true. character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -123,7 +122,7 @@ subroutine CNPhenologyReadNML( NLFilename ) character(len=*), parameter :: subname = 'CNPhenologyReadNML' character(len=*), parameter :: nmlname = 'cnphenology' !----------------------------------------------------------------------- - namelist /cnphenology/ initial_seed_at_planting, subtract_cropseed + namelist /cnphenology/ initial_seed_at_planting ! Initialize options to default values, in case they are not specified in ! the namelist @@ -145,7 +144,6 @@ subroutine CNPhenologyReadNML( NLFilename ) end if call shr_mpi_bcast (initial_seed_at_planting, mpicom) - if ( initial_seed_at_planting == 1._r8 ) subtract_cropseed = .false. if (masterproc) then write(iulog,*) ' ' @@ -245,8 +243,9 @@ subroutine CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & doalb, waterstate_inst, temperature_inst, atm2lnd_inst, crop_inst, & canopystate_inst, soilstate_inst, dgvs_inst, & cnveg_state_inst, cnveg_carbonstate_inst, cnveg_carbonflux_inst, & - cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, leaf_prof_patch, & - froot_prof_patch, phase) + cnveg_nitrogenstate_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst, & + leaf_prof_patch, froot_prof_patch, phase) ! !USES: use CNSharedParamsMod, only: use_fun ! @@ -275,6 +274,8 @@ subroutine CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst + type(cnveg_carbonstate_type) , intent(inout) :: c13_cnveg_carbonstate_inst + type(cnveg_carbonstate_type) , intent(inout) :: c14_cnveg_carbonstate_inst real(r8) , intent(in) :: leaf_prof_patch(bounds%begp:,1:) real(r8) , intent(in) :: froot_prof_patch(bounds%begp:,1:) integer , intent(in) :: phase @@ -286,6 +287,7 @@ subroutine CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & ! each of the following phenology type routines includes a filter ! to operate only on the relevant patches + if ( phase == 1 ) then call CNPhenologyClimate(num_soilp, filter_soilp, num_pcropp, filter_pcropp, & temperature_inst, cnveg_state_inst, crop_inst) @@ -304,7 +306,8 @@ subroutine CNPhenology (bounds, num_soilc, filter_soilc, num_soilp, & if (doalb .and. num_pcropp > 0 ) then call CropPhenology(num_pcropp, filter_pcropp, & waterstate_inst, temperature_inst, crop_inst, canopystate_inst, cnveg_state_inst, & - cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) + cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst, & + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst) end if else if ( phase == 2 ) then ! the same onset and offset routines are called regardless of @@ -1416,14 +1419,15 @@ end subroutine CNStressDecidPhenology !----------------------------------------------------------------------- subroutine CropPhenology(num_pcropp, filter_pcropp , & waterstate_inst, temperature_inst, crop_inst, canopystate_inst, cnveg_state_inst , & - cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst) + cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, cnveg_nitrogenflux_inst,& + c13_cnveg_carbonstate_inst, c14_cnveg_carbonstate_inst) ! !DESCRIPTION: ! Code from AgroIBIS to determine crop phenology and code from CN to ! handle CN fluxes during the phenological onset & offset periods. ! !USES: - use clm_time_manager , only : get_curr_date, get_curr_calday, get_days_per_year + use clm_time_manager , only : get_curr_date, get_curr_calday, get_days_per_year, get_rad_step_size use pftconMod , only : ntmp_corn, nswheat, nwwheat, ntmp_soybean use pftconMod , only : nirrig_tmp_corn, nirrig_swheat, nirrig_wwheat, nirrig_tmp_soybean use pftconMod , only : ntrp_corn, nsugarcane, ntrp_soybean, ncotton, nrice @@ -1431,6 +1435,8 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & use pftconMod , only : nirrig_cotton, nirrig_rice use clm_varcon , only : spval, secspday use clm_varctl , only : use_fertilizer + use clm_varctl , only : use_c13, use_c14 + use clm_varcon , only : c13ratio, c14ratio ! ! !ARGUMENTS: integer , intent(in) :: num_pcropp ! number of prog crop patches in filter @@ -1444,6 +1450,8 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & type(cnveg_nitrogenstate_type) , intent(inout) :: cnveg_nitrogenstate_inst type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_nitrogenflux_type) , intent(inout) :: cnveg_nitrogenflux_inst + type(cnveg_carbonstate_type) , intent(inout) :: c13_cnveg_carbonstate_inst + type(cnveg_carbonstate_type) , intent(inout) :: c14_cnveg_carbonstate_inst ! ! LOCAL VARAIBLES: integer kyr ! current year @@ -1456,6 +1464,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & integer g ! gridcell indices integer h ! hemisphere indices integer idpp ! number of days past planting + real(r8) :: dtrad ! radiation time step delta t (seconds) real(r8) dayspyr ! days per year real(r8) crmcorn ! comparitive relative maturity for corn real(r8) ndays_on ! number of days to fertilize @@ -1490,7 +1499,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & croplive => crop_inst%croplive_patch , & ! Output: [logical (:) ] Flag, true if planted, not harvested cropplant => crop_inst%cropplant_patch , & ! Output: [logical (:) ] Flag, true if crop may be planted vf => crop_inst%vf_patch , & ! Output: [real(r8) (:) ] vernalization factor - + peaklai => cnveg_state_inst%peaklai_patch , & ! Output: [integer (:) ] 1: max allowed lai; 0: not at max tlai => canopystate_inst%tlai_patch , & ! Input: [real(r8) (:) ] one-sided leaf area index, no burying by snow idop => cnveg_state_inst%idop_patch , & ! Output: [integer (:) ] date of planting @@ -1522,6 +1531,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & dayspyr = get_days_per_year() jday = get_curr_calday() call get_curr_date(kyr, kmo, kda, mcsec) + dtrad = real( get_rad_step_size(), r8 ) if (use_fertilizer) then ndays_on = 20._r8 ! number of days to fertilize @@ -1629,6 +1639,25 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & crop_seedc_to_leaf(p) = leafc_xfer(p)/dt crop_seedn_to_leaf(p) = leafn_xfer(p)/dt + ! because leafc_xfer is set above rather than incremneted through the normal process, must also set its isotope + ! pools here. use totvegc_patch as the closest analogue if nonzero, and use initial value otherwise + if (use_c13) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c13_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c13ratio + endif + endif + if (use_c14) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c14_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c14ratio + endif + endif + ! latest possible date to plant winter cereal and after all other ! crops were harvested for that year @@ -1648,6 +1677,25 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & leafn_xfer(p) = leafc_xfer(p) / leafcn(ivt(p)) ! with onset crop_seedc_to_leaf(p) = leafc_xfer(p)/dt crop_seedn_to_leaf(p) = leafn_xfer(p)/dt + + ! because leafc_xfer is set above rather than incremneted through the normal process, must also set its isotope + ! pools here. use totvegc_patch as the closest analogue if nonzero, and use initial value otherwise + if (use_c13) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c13_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c13ratio + endif + endif + if (use_c14) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c14_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c14ratio + endif + endif else gddmaturity(p) = 0._r8 end if @@ -1694,6 +1742,26 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & crop_seedc_to_leaf(p) = leafc_xfer(p)/dt crop_seedn_to_leaf(p) = leafn_xfer(p)/dt + ! because leafc_xfer is set above rather than incremneted through the normal process, must also set its isotope + ! pools here. use totvegc_patch as the closest analogue if nonzero, and use initial value otherwise + if (use_c13) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c13_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c13ratio + endif + endif + if (use_c14) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c14_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c14ratio + endif + endif + + ! If hit the max planting julian day -- go ahead and plant else if (jday == maxplantjday(ivt(p),h) .and. gdd820(p) > 0._r8 .and. & gdd820(p) /= spval ) then @@ -1722,6 +1790,25 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & crop_seedc_to_leaf(p) = leafc_xfer(p)/dt crop_seedn_to_leaf(p) = leafn_xfer(p)/dt + ! because leafc_xfer is set above rather than incremneted through the normal process, must also set its isotope + ! pools here. use totvegc_patch as the closest analogue if nonzero, and use initial value otherwise + if (use_c13) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c13_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c13ratio + endif + endif + if (use_c14) then + if ( cnveg_carbonstate_inst%totvegc_patch(p) .gt. 0._r8) then + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * & + c14_cnveg_carbonstate_inst%totvegc_patch(p) / cnveg_carbonstate_inst%totvegc_patch(p) + else + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = leafc_xfer(p) * c14ratio + endif + endif + else gddmaturity(p) = 0._r8 end if @@ -1842,20 +1929,20 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & ! enter phase 2 onset for one time step: ! transfer seed carbon to leaf emergence + if (peaklai(p) >= 1) then + hui(p) = max(hui(p),huigrain(p)) + endif + if (leafout(p) >= huileaf(p) .and. hui(p) < huigrain(p) .and. idpp < mxmat(ivt(p))) then cphase(p) = 2._r8 if (abs(onset_counter(p)) > 1.e-6_r8) then onset_flag(p) = 1._r8 onset_counter(p) = dt fert_counter(p) = ndays_on * secspday - if ( subtract_cropseed ) then - if (ndays_on .gt. 0) then - fert(p) = (manunitro(ivt(p)) * 1000._r8 + fertnitro(p))/ fert_counter(p) - else - fert(p) = 0._r8 - end if - else + if (ndays_on .gt. 0) then fert(p) = (manunitro(ivt(p)) * 1000._r8 + fertnitro(p))/ fert_counter(p) + else + fert(p) = 0._r8 end if else ! this ensures no re-entry to onset of phase2 @@ -1889,6 +1976,13 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & crop_seedn_to_leaf(p) = crop_seedn_to_leaf(p) - leafn_xfer(p)/dt leafc_xfer(p) = 0._r8 leafn_xfer(p) = leafc_xfer(p) / leafcn(ivt(p)) + if (use_c13) then + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = 0._r8 + endif + if (use_c14) then + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = 0._r8 + endif + end if ! enter phase 3 while previous criteria fail and next is true; @@ -1908,7 +2002,7 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & if (fert_counter(p) <= 0._r8) then fert(p) = 0._r8 else ! continue same fert application every timestep - fert_counter(p) = fert_counter(p) - dt + fert_counter(p) = fert_counter(p) - dtrad end if else ! crop not live @@ -1922,6 +2016,12 @@ subroutine CropPhenology(num_pcropp, filter_pcropp , & onset_counter(p) = 0._r8 leafc_xfer(p) = 0._r8 leafn_xfer(p) = leafc_xfer(p) / leafcn(ivt(p)) + if (use_c13) then + c13_cnveg_carbonstate_inst%leafc_xfer_patch(p) = 0._r8 + endif + if (use_c14) then + c14_cnveg_carbonstate_inst%leafc_xfer_patch(p) = 0._r8 + endif end if ! croplive end do ! prognostic crops loop @@ -2354,18 +2454,12 @@ subroutine CNOffsetLitterfall (num_soilp, filter_soilp, & ! this assumes that offset_counter == dt for crops ! if this were ever changed, we'd need to add code to the "else" if (ivt(p) >= npcropmin) then - if ( subtract_cropseed ) then - ! Replenish the seed deficits from grain, if there is enough - ! available grain. (If there is not enough available grain, the seed - ! deficits will accumulate until there is eventually enough grain to - ! replenish them.) - grainc_to_seed(p) = t1 * min(-cropseedc_deficit(p), grainc(p)) - grainn_to_seed(p) = t1 * min(-cropseedn_deficit(p), grainn(p)) - else - ! It's not necessary to explicitly 0 these, but we do it to be clear - grainc_to_seed(p) = 0._r8 - grainn_to_seed(p) = 0._r8 - end if + ! Replenish the seed deficits from grain, if there is enough + ! available grain. (If there is not enough available grain, the seed + ! deficits will accumulate until there is eventually enough grain to + ! replenish them.) + grainc_to_seed(p) = t1 * min(-cropseedc_deficit(p), grainc(p)) + grainn_to_seed(p) = t1 * min(-cropseedn_deficit(p), grainn(p)) ! Send the remaining grain to the food product pool grainc_to_food(p) = t1 * grainc(p) + cpool_to_grainc(p) - grainc_to_seed(p) grainn_to_food(p) = t1 * grainn(p) + npool_to_grainn(p) - grainn_to_seed(p) diff --git a/src/biogeochem/CNPrecisionControlMod.F90 b/src/biogeochem/CNPrecisionControlMod.F90 index bb1a1580d0..818e8eabca 100644 --- a/src/biogeochem/CNPrecisionControlMod.F90 +++ b/src/biogeochem/CNPrecisionControlMod.F90 @@ -246,17 +246,28 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & ! grain C and N call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%grainc_patch(bounds%begp:bounds%endp), & ns%grainn_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & - croponly=.true. ) + c13=c13cs%grainc_patch, c14=c14cs%grainc_patch, & + pc13=pc13(bounds%begp:), pc14=pc14(bounds%begp:), croponly=.true. ) ! grain storage C and N call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%grainc_storage_patch(bounds%begp:bounds%endp), & ns%grainn_storage_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), & - __LINE__, croponly=.true. ) + __LINE__, c13=c13cs%grainc_storage_patch, c14=c14cs%grainc_storage_patch, & + pc13=pc13(bounds%begp:), pc14=pc14(bounds%begp:), croponly=.true. ) ! grain transfer C and N call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%grainc_xfer_patch(bounds%begp:bounds%endp), & ns%grainn_xfer_patch(bounds%begp:bounds%endp), pc(bounds%begp:), pn(bounds%begp:), __LINE__, & - croponly=.true. ) + c13=c13cs%grainc_xfer_patch, c14=c14cs%grainc_xfer_patch, & + pc13=pc13(bounds%begp:), pc14=pc14(bounds%begp:), croponly=.true. ) + + ! grain transfer C and N + call TruncateCandNStates( bounds, filter_soilp, num_soilp, cs%cropseedc_deficit_patch(bounds%begp:bounds%endp), & + ns%cropseedn_deficit_patch(bounds%begp:bounds%endp), pc(bounds%begp:), & + pn(bounds%begp:), __LINE__, & + c13=c13cs%cropseedc_deficit_patch, c14=c14cs%cropseedc_deficit_patch, & + pc13=pc13(bounds%begp:), pc14=pc14(bounds%begp:), allowneg=.true., croponly=.true. ) + end if ! livestem C and N @@ -353,7 +364,9 @@ subroutine CNPrecisionControl(bounds, num_soilp, filter_soilp, & ! xsmr is a pool to balance the budget and as such can be freely negative call TruncateCStates( bounds, filter_soilp, num_soilp, cs%xsmrpool_patch(bounds%begp:bounds%endp), & pc(bounds%begp:), __LINE__, & - allowneg=.true., croponly=.true. ) + c13=c13cs%xsmrpool_patch, c14=c14cs%xsmrpool_patch, & + pc13=pc13(bounds%begp:), pc14=pc14(bounds%begp:), allowneg=.true., croponly=.true. ) + end if ! retransn (N only) diff --git a/src/biogeochem/CNProductsMod.F90 b/src/biogeochem/CNProductsMod.F90 index 89e5404f28..59891ba330 100644 --- a/src/biogeochem/CNProductsMod.F90 +++ b/src/biogeochem/CNProductsMod.F90 @@ -41,6 +41,7 @@ module CNProductsMod ! Fluxes: gains real(r8), pointer :: dwt_prod10_gain_grc(:) ! (g[C or N]/m2/s) dynamic landcover addition to 10-year wood product pool real(r8), pointer :: dwt_prod100_gain_grc(:) ! (g[C or N]/m2/s) dynamic landcover addition to 100-year wood product pool + real(r8), pointer :: dwt_woodprod_gain_grc(:) ! (g[C or N]/m2/s) dynamic landcover addition to wood product pools real(r8), pointer :: dwt_cropprod1_gain_grc(:) ! (g[C or N]/m2/s) dynamic landcover addition to 1-year crop product pool real(r8), pointer :: hrv_deadstem_to_prod10_patch(:) ! (g[C or N]/m2/s) dead stem harvest to 10-year wood product pool real(r8), pointer :: hrv_deadstem_to_prod10_grc(:) ! (g[C or N]/m2/s) dead stem harvest to 10-year wood product pool @@ -128,6 +129,8 @@ subroutine InitAllocate(this, bounds) allocate(this%dwt_prod10_gain_grc(begg:endg)) ; this%dwt_prod10_gain_grc(:) = nan allocate(this%dwt_prod100_gain_grc(begg:endg)) ; this%dwt_prod100_gain_grc(:) = nan + allocate(this%dwt_woodprod_gain_grc(begg:endg)) ; this%dwt_woodprod_gain_grc(:) = nan + allocate(this%dwt_cropprod1_gain_grc(begg:endg)) ; this%dwt_cropprod1_gain_grc(:) = nan allocate(this%hrv_deadstem_to_prod10_patch(begp:endp)) ; this%hrv_deadstem_to_prod10_patch(:) = nan @@ -180,7 +183,7 @@ subroutine InitHistory(this, bounds) units = 'g' // this%species%get_species() // '/m^2', & avgflag = 'A', & long_name = '10-yr wood product ' // this%species%get_species(), & - ptr_gcell = this%prod10_grc) + ptr_gcell = this%prod10_grc, default='inactive') this%prod100_grc(begg:endg) = spval call hist_addfld1d( & @@ -188,7 +191,7 @@ subroutine InitHistory(this, bounds) units = 'g' // this%species%get_species() // '/m^2', & avgflag = 'A', & long_name = '100-yr wood product ' // this%species%get_species(), & - ptr_gcell = this%prod100_grc) + ptr_gcell = this%prod100_grc, default='inactive') this%tot_woodprod_grc(begg:endg) = spval call hist_addfld1d( & @@ -204,7 +207,7 @@ subroutine InitHistory(this, bounds) units = 'g' // this%species%get_species() // '/m^2/s', & avgflag = 'A', & long_name = 'landcover change-driven addition to 10-yr wood product pool', & - ptr_gcell = this%dwt_prod10_gain_grc) + ptr_gcell = this%dwt_prod10_gain_grc, default='inactive') this%dwt_prod100_gain_grc(begg:endg) = spval call hist_addfld1d( & @@ -212,7 +215,15 @@ subroutine InitHistory(this, bounds) units = 'g' // this%species%get_species() // '/m^2/s', & avgflag = 'A', & long_name = 'landcover change-driven addition to 100-yr wood product pool', & - ptr_gcell = this%dwt_prod100_gain_grc) + ptr_gcell = this%dwt_prod100_gain_grc, default='inactive') + + this%dwt_woodprod_gain_grc(begg:endg) = spval + call hist_addfld1d( & + fname = this%species%hist_fname('DWT_WOODPROD', suffix='_GAIN'), & + units = 'g' // this%species%get_species() // '/m^2/s', & + avgflag = 'A', & + long_name = 'landcover change-driven addition to wood product pools', & + ptr_gcell = this%dwt_woodprod_gain_grc) this%dwt_cropprod1_gain_grc(begg:endg) = spval call hist_addfld1d( & @@ -236,7 +247,7 @@ subroutine InitHistory(this, bounds) units = 'g' // this%species%get_species() // '/m^2/s', & avgflag = 'A', & long_name = 'loss from 10-yr wood product pool', & - ptr_gcell = this%prod10_loss_grc) + ptr_gcell = this%prod10_loss_grc, default='inactive') this%prod100_loss_grc(begg:endg) = spval call hist_addfld1d( & @@ -244,7 +255,7 @@ subroutine InitHistory(this, bounds) units = 'g' // this%species%get_species() // '/m^2/s', & avgflag = 'A', & long_name = 'loss from 100-yr wood product pool', & - ptr_gcell = this%prod100_loss_grc) + ptr_gcell = this%prod100_loss_grc, default='inactive') this%tot_woodprod_loss_grc(begg:endg) = spval call hist_addfld1d( & @@ -718,6 +729,10 @@ subroutine ComputeSummaryVars(this, bounds) this%cropprod1_loss_grc(g) + & this%prod10_loss_grc(g) + & this%prod100_loss_grc(g) + + this%dwt_woodprod_gain_grc(g) = & + this%dwt_prod100_gain_grc(g) + & + this%dwt_prod10_gain_grc(g) end do end subroutine ComputeSummaryVars diff --git a/src/biogeochem/CNSharedParamsMod.F90 b/src/biogeochem/CNSharedParamsMod.F90 index a5cd5d8057..42156b1158 100644 --- a/src/biogeochem/CNSharedParamsMod.F90 +++ b/src/biogeochem/CNSharedParamsMod.F90 @@ -117,6 +117,7 @@ subroutine CNParamsReadShared_namelist(namelist_file) use shr_log_mod , only : errMsg => shr_log_errMsg use clm_varctl , only : iulog use abortutils , only : endrun + use shr_mpi_mod , only : shr_mpi_bcast ! implicit none @@ -168,8 +169,8 @@ subroutine CNParamsReadShared_namelist(namelist_file) end if ! masterproc ! Broadcast the parameters from master - call mpi_bcast ( decomp_depth_efolding, 1 , MPI_REAL8, 0, mpicom, ierr ) - call mpi_bcast ( constrain_stress_deciduous_onset, 1 , MPI_LOGICAL, 0, mpicom, ierr ) + call shr_mpi_bcast ( decomp_depth_efolding, mpicom ) + call shr_mpi_bcast ( constrain_stress_deciduous_onset, mpicom ) ! Save the parameter to the instance CNParamsShareInst%decomp_depth_efolding = decomp_depth_efolding diff --git a/src/biogeochem/CNVegCarbonFluxType.F90 b/src/biogeochem/CNVegCarbonFluxType.F90 index 8e8ecc174b..57cee383d5 100644 --- a/src/biogeochem/CNVegCarbonFluxType.F90 +++ b/src/biogeochem/CNVegCarbonFluxType.F90 @@ -263,6 +263,7 @@ module CNVegCarbonFluxType real(r8), pointer :: dwt_conv_cflux_dribbled_grc (:) ! (gC/m2/s) dwt_conv_cflux_grc dribbled evenly throughout the year real(r8), pointer :: dwt_wood_productc_gain_patch (:) ! (gC/m2/s) addition to wood product pools from landcover change; although this is a patch-level flux, it is expressed per unit GRIDCELL area real(r8), pointer :: dwt_crop_productc_gain_patch (:) ! (gC/m2/s) addition to crop product pools from landcover change; although this is a patch-level flux, it is expressed per unit GRIDCELL area + real(r8), pointer :: dwt_slash_cflux_col (:) ! (gC/m2/s) conversion slash flux due to landcover change real(r8), pointer :: dwt_frootc_to_litr_met_c_col (:,:) ! (gC/m3/s) fine root to litter due to landcover change real(r8), pointer :: dwt_frootc_to_litr_cel_c_col (:,:) ! (gC/m3/s) fine root to litter due to landcover change real(r8), pointer :: dwt_frootc_to_litr_lig_c_col (:,:) ! (gC/m3/s) fine root to litter due to landcover change @@ -310,6 +311,7 @@ module CNVegCarbonFluxType real(r8), pointer :: litfall_patch (:) ! (gC/m2/s) patch litterfall (leaves and fine roots) real(r8), pointer :: wood_harvestc_patch (:) ! (gC/m2/s) patch-level wood harvest (to product pools) real(r8), pointer :: wood_harvestc_col (:) ! (gC/m2/s) column-level wood harvest (to product pools) (p2c) + real(r8), pointer :: slash_harvestc_patch (:) ! (gC/m2/s) patch-level slash from harvest (to litter) real(r8), pointer :: cinputs_patch (:) ! (gC/m2/s) patch-level carbon inputs (for balance checking) real(r8), pointer :: coutputs_patch (:) ! (gC/m2/s) patch-level carbon outputs (for balance checking) real(r8), pointer :: sr_col (:) ! (gC/m2/s) total soil respiration (HR + root resp) @@ -627,6 +629,7 @@ subroutine InitAllocate(this, bounds, carbon_type) allocate(this%harvest_c_to_litr_lig_c_col (begc:endc,1:nlevdecomp_full)); this%harvest_c_to_litr_lig_c_col (:,:)=nan allocate(this%harvest_c_to_cwdc_col (begc:endc,1:nlevdecomp_full)); this%harvest_c_to_cwdc_col (:,:)=nan + allocate(this%dwt_slash_cflux_col (begc:endc)) ; this%dwt_slash_cflux_col (:) =nan allocate(this%dwt_frootc_to_litr_met_c_col (begc:endc,1:nlevdecomp_full)); this%dwt_frootc_to_litr_met_c_col (:,:)=nan allocate(this%dwt_frootc_to_litr_cel_c_col (begc:endc,1:nlevdecomp_full)); this%dwt_frootc_to_litr_cel_c_col (:,:)=nan allocate(this%dwt_frootc_to_litr_lig_c_col (begc:endc,1:nlevdecomp_full)); this%dwt_frootc_to_litr_lig_c_col (:,:)=nan @@ -676,6 +679,7 @@ subroutine InitAllocate(this, bounds, carbon_type) allocate(this%bgnpp_patch (begp:endp)) ; this%bgnpp_patch (:) = nan allocate(this%litfall_patch (begp:endp)) ; this%litfall_patch (:) = nan allocate(this%wood_harvestc_patch (begp:endp)) ; this%wood_harvestc_patch (:) = nan + allocate(this%slash_harvestc_patch (begp:endp)) ; this%slash_harvestc_patch (:) = nan allocate(this%cinputs_patch (begp:endp)) ; this%cinputs_patch (:) = nan allocate(this%coutputs_patch (begp:endp)) ; this%coutputs_patch (:) = nan allocate(this%gpp_patch (begp:endp)) ; this%gpp_patch (:) = nan @@ -1563,6 +1567,11 @@ subroutine InitHistory(this, bounds, carbon_type) avgflag='A', long_name='wood harvest carbon (to product pools)', & ptr_patch=this%wood_harvestc_patch) + this%slash_harvestc_patch(begp:endp) = spval + call hist_addfld1d (fname='SLASH_HARVESTC', units='gC/m^2/s', & + avgflag='A', long_name='slash harvest carbon (to litter)', & + ptr_patch=this%slash_harvestc_patch) + this%fire_closs_patch(begp:endp) = spval call hist_addfld1d (fname='PFT_FIRE_CLOSS', units='gC/m^2/s', & avgflag='A', long_name='total patch-level fire C loss for non-peat fires outside land-type converted region', & @@ -2790,11 +2799,6 @@ subroutine InitHistory(this, bounds, carbon_type) if (carbon_type == 'c12') then - this%cwdc_hr_col(begc:endc) = spval - call hist_addfld1d (fname='CWDC_HR', units='gC/m^2/s', & - avgflag='A', long_name='coarse woody debris C heterotrophic respiration', & - ptr_col=this%cwdc_hr_col) - this%cwdc_loss_col(begc:endc) = spval call hist_addfld1d (fname='CWDC_LOSS', units='gC/m^2/s', & avgflag='A', long_name='coarse woody debris C loss', & @@ -2825,7 +2829,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%dwt_seedc_to_leaf_grc(begg:endg) = spval call hist_addfld1d (fname='DWT_SEEDC_TO_LEAF', units='gC/m^2/s', & avgflag='A', long_name='seed source to patch-level leaf', & - ptr_gcell=this%dwt_seedc_to_leaf_grc) + ptr_gcell=this%dwt_seedc_to_leaf_grc, default='inactive') this%dwt_seedc_to_leaf_patch(begp:endp) = spval call hist_addfld1d (fname='DWT_SEEDC_TO_LEAF_PATCH', units='gC/m^2/s', & @@ -2837,7 +2841,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%dwt_seedc_to_deadstem_grc(begg:endg) = spval call hist_addfld1d (fname='DWT_SEEDC_TO_DEADSTEM', units='gC/m^2/s', & avgflag='A', long_name='seed source to patch-level deadstem', & - ptr_gcell=this%dwt_seedc_to_deadstem_grc) + ptr_gcell=this%dwt_seedc_to_deadstem_grc, default='inactive') this%dwt_seedc_to_deadstem_patch(begp:endp) = spval call hist_addfld1d (fname='DWT_SEEDC_TO_DEADSTEM_PATCH', units='gC/m^2/s', & @@ -2866,6 +2870,19 @@ subroutine InitHistory(this, bounds, carbon_type) long_name='conversion C flux (immediate loss to atm), dribbled throughout the year', & ptr_gcell=this%dwt_conv_cflux_dribbled_grc) + this%dwt_wood_productc_gain_patch(begp:endp) = spval + call hist_addfld1d (fname='DWT_WOOD_PRODUCTC_GAIN_PATCH', units='gC/m^2/s', & + avgflag='A', & + long_name='patch-level landcover change-driven addition to wood product pools' // & + '(0 at all times except first timestep of year) ' // & + '(per-area-gridcell; only makes sense with dov2xy=.false.)', & + ptr_patch=this%dwt_wood_productc_gain_patch, default='inactive') + + this%dwt_slash_cflux_col(begc:endc) = spval + call hist_addfld1d (fname='DWT_SLASH_CFLUX', units='gC/m^2/s', & + avgflag='A', long_name='slash C flux to litter and CWD due to land use', & + ptr_col=this%dwt_slash_cflux_col) + this%dwt_frootc_to_litr_met_c_col(begc:endc,:) = spval call hist_addfld_decomp (fname='DWT_FROOTC_TO_LITR_MET_C', units='gC/m^2/s', type2d='levdcmp', & avgflag='A', long_name='fine root to litter due to landcover change', & @@ -2894,7 +2911,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%crop_seedc_to_leaf_patch(begp:endp) = spval call hist_addfld1d (fname='CROP_SEEDC_TO_LEAF', units='gC/m^2/s', & avgflag='A', long_name='crop seed source to leaf', & - ptr_patch=this%crop_seedc_to_leaf_patch) + ptr_patch=this%crop_seedc_to_leaf_patch, default='inactive') this%sr_col(begc:endc) = spval call hist_addfld1d (fname='SR', units='gC/m^2/s', & @@ -2994,7 +3011,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%dwt_seedc_to_leaf_grc(begg:endg) = spval call hist_addfld1d (fname='C13_DWT_SEEDC_TO_LEAF', units='gC13/m^2/s', & avgflag='A', long_name='C13 seed source to patch-level leaf', & - ptr_gcell=this%dwt_seedc_to_leaf_grc) + ptr_gcell=this%dwt_seedc_to_leaf_grc, default='inactive') this%dwt_seedc_to_leaf_patch(begp:endp) = spval call hist_addfld1d (fname='C13_DWT_SEEDC_TO_LEAF_PATCH', units='gC13/m^2/s', & @@ -3006,7 +3023,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%dwt_seedc_to_deadstem_grc(begg:endg) = spval call hist_addfld1d (fname='C13_DWT_SEEDC_TO_DEADSTEM', units='gC13/m^2/s', & avgflag='A', long_name='C13 seed source to patch-level deadstem', & - ptr_gcell=this%dwt_seedc_to_deadstem_grc) + ptr_gcell=this%dwt_seedc_to_deadstem_grc, default='inactive') this%dwt_seedc_to_deadstem_patch(begp:endp) = spval call hist_addfld1d (fname='C13_DWT_SEEDC_TO_DEADSTEM_PATCH', units='gC13/m^2/s', & @@ -3035,6 +3052,11 @@ subroutine InitHistory(this, bounds, carbon_type) long_name='C13 conversion C flux (immediate loss to atm), dribbled throughout the year', & ptr_gcell=this%dwt_conv_cflux_dribbled_grc) + this%dwt_slash_cflux_col(begc:endc) = spval + call hist_addfld1d (fname='C13_DWT_SLASH_CFLUX', units='gC/m^2/s', & + avgflag='A', long_name='C13 slash C flux to litter and CWD due to land use', & + ptr_col=this%dwt_slash_cflux_col) + this%dwt_frootc_to_litr_met_c_col(begc:endc,:) = spval call hist_addfld_decomp (fname='C13_DWT_FROOTC_TO_LITR_MET_C', units='gC13/m^2/s', type2d='levdcmp', & avgflag='A', long_name='C13 fine root to litter due to landcover change', & @@ -3063,7 +3085,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%crop_seedc_to_leaf_patch(begp:endp) = spval call hist_addfld1d (fname='C13_CROP_SEEDC_TO_LEAF', units='gC13/m^2/s', & avgflag='A', long_name='C13 crop seed source to leaf', & - ptr_patch=this%crop_seedc_to_leaf_patch) + ptr_patch=this%crop_seedc_to_leaf_patch, default='inactive') this%sr_col(begc:endc) = spval call hist_addfld1d (fname='C13_SR', units='gC13/m^2/s', & @@ -3138,7 +3160,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%dwt_seedc_to_leaf_grc(begg:endg) = spval call hist_addfld1d (fname='C14_DWT_SEEDC_TO_LEAF', units='gC14/m^2/s', & avgflag='A', long_name='C14 seed source to patch-level leaf', & - ptr_gcell=this%dwt_seedc_to_leaf_grc) + ptr_gcell=this%dwt_seedc_to_leaf_grc, default='inactive') this%dwt_seedc_to_leaf_patch(begp:endp) = spval call hist_addfld1d (fname='C14_DWT_SEEDC_TO_LEAF_PATCH', units='gC14/m^2/s', & @@ -3150,7 +3172,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%dwt_seedc_to_deadstem_grc(begg:endg) = spval call hist_addfld1d (fname='C14_DWT_SEEDC_TO_DEADSTEM', units='gC14/m^2/s', & avgflag='A', long_name='C14 seed source to patch-level deadstem', & - ptr_gcell=this%dwt_seedc_to_deadstem_grc) + ptr_gcell=this%dwt_seedc_to_deadstem_grc, default='inactive') this%dwt_seedc_to_deadstem_patch(begp:endp) = spval call hist_addfld1d (fname='C14_DWT_SEEDC_TO_DEADSTEM_PATCH', units='gC14/m^2/s', & @@ -3179,6 +3201,11 @@ subroutine InitHistory(this, bounds, carbon_type) long_name='C14 conversion C flux (immediate loss to atm), dribbled throughout the year', & ptr_gcell=this%dwt_conv_cflux_dribbled_grc) + this%dwt_slash_cflux_col(begc:endc) = spval + call hist_addfld1d (fname='C14_DWT_SLASH_CFLUX', units='gC/m^2/s', & + avgflag='A', long_name='C14 slash C flux to litter and CWD due to land use', & + ptr_col=this%dwt_slash_cflux_col) + this%dwt_frootc_to_litr_met_c_col(begc:endc,:) = spval call hist_addfld_decomp (fname='C14_DWT_FROOTC_TO_LITR_MET_C', units='gC14/m^2/s', type2d='levdcmp', & avgflag='A', long_name='C14 fine root to litter due to landcover change', & @@ -3207,7 +3234,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%crop_seedc_to_leaf_patch(begp:endp) = spval call hist_addfld1d (fname='C14_CROP_SEEDC_TO_LEAF', units='gC14/m^2/s', & avgflag='A', long_name='C14 crop seed source to leaf', & - ptr_patch=this%crop_seedc_to_leaf_patch) + ptr_patch=this%crop_seedc_to_leaf_patch, default='inactive') this%sr_col(begc:endc) = spval call hist_addfld1d (fname='C14_SR', units='gC14/m^2/s', & @@ -3325,6 +3352,7 @@ subroutine InitCold(this, bounds) ! also initialize dynamic landcover fluxes so that they have ! real values on first timestep, prior to calling pftdyn_cnbal if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + this%dwt_slash_cflux_col(c) = 0._r8 do j = 1, nlevdecomp_full this%dwt_frootc_to_litr_met_c_col(c,j) = 0._r8 this%dwt_frootc_to_litr_cel_c_col(c,j) = 0._r8 @@ -3853,6 +3881,7 @@ subroutine SetValues ( this, & this%bgnpp_patch(i) = value_patch this%litfall_patch(i) = value_patch this%wood_harvestc_patch(i) = value_patch + this%slash_harvestc_patch(i) = value_patch this%cinputs_patch(i) = value_patch this%coutputs_patch(i) = value_patch this%fire_closs_patch(i) = value_patch @@ -3924,6 +3953,10 @@ subroutine ZeroDwt( this, bounds ) this%dwt_conv_cflux_grc(g) = 0._r8 end do + do c = bounds%begc,bounds%endc + this%dwt_slash_cflux_col(c) = 0._r8 + end do + do j = 1, nlevdecomp_full do c = bounds%begc,bounds%endc this%dwt_frootc_to_litr_met_c_col(c,j) = 0._r8 @@ -4319,6 +4352,29 @@ subroutine Summary_carbonflux(this, & this%hrv_deadcrootc_storage_to_litter_patch(p) + & this%hrv_deadcrootc_xfer_to_litter_patch(p) + ! (Slash Harvest Flux) - Additional Wood Harvest Veg C Losses + this%slash_harvestc_patch(p) = & + this%hrv_leafc_to_litter_patch(p) + & + this%hrv_leafc_storage_to_litter_patch(p) + & + this%hrv_leafc_xfer_to_litter_patch(p) + & + this%hrv_frootc_to_litter_patch(p) + & + this%hrv_frootc_storage_to_litter_patch(p) + & + this%hrv_frootc_xfer_to_litter_patch(p) + & + this%hrv_livestemc_to_litter_patch(p) + & + this%hrv_livestemc_storage_to_litter_patch(p) + & + this%hrv_livestemc_xfer_to_litter_patch(p) + & + this%hrv_deadstemc_storage_to_litter_patch(p) + & + this%hrv_deadstemc_xfer_to_litter_patch(p) + & + this%hrv_livecrootc_to_litter_patch(p) + & + this%hrv_livecrootc_storage_to_litter_patch(p) + & + this%hrv_livecrootc_xfer_to_litter_patch(p) + & + this%hrv_deadcrootc_to_litter_patch(p) + & + this%hrv_deadcrootc_storage_to_litter_patch(p) + & + this%hrv_deadcrootc_xfer_to_litter_patch(p) + & + this%hrv_xsmrpool_to_atm_patch(p) + & + this%hrv_gresp_storage_to_litter_patch(p) + & + this%hrv_gresp_xfer_to_litter_patch(p) + end do ! end of patches loop !------------------------------------------------ diff --git a/src/biogeochem/CNVegCarbonStateType.F90 b/src/biogeochem/CNVegCarbonStateType.F90 index e27f94190f..41eb79134f 100644 --- a/src/biogeochem/CNVegCarbonStateType.F90 +++ b/src/biogeochem/CNVegCarbonStateType.F90 @@ -92,13 +92,20 @@ module CNVegCarbonStateType procedure , public :: Summary => Summary_carbonstate procedure , public :: DynamicPatchAdjustments ! adjust state variables when patch areas change - procedure , private :: InitAllocate - procedure , private :: InitHistory - procedure , private :: InitCold + procedure , private :: InitAllocate ! Allocate arrays + procedure , private :: InitReadNML ! Read in namelist + procedure , private :: InitHistory ! Initialize history + procedure , private :: InitCold ! Initialize arrays for a cold-start end type cnveg_carbonstate_type ! !PRIVATE DATA: + + type, private :: cnvegcarbonstate_const_type + ! !PRIVATE MEMBER DATA: + real(r8) :: initial_vegC = 20._r8 ! Initial vegetation carbon for leafc/frootc and storage + end type + type(cnvegcarbonstate_const_type), private :: cnvegcstate_const ! Constants used here character(len=*), parameter :: sourcefile = & __FILE__ @@ -107,27 +114,90 @@ module CNVegCarbonStateType contains !------------------------------------------------------------------------ - subroutine Init(this, bounds, carbon_type, ratio, c12_cnveg_carbonstate_inst) + subroutine Init(this, bounds, carbon_type, ratio, NLFilename, & + c12_cnveg_carbonstate_inst) class(cnveg_carbonstate_type) :: this type(bounds_type) , intent(in) :: bounds real(r8) , intent(in) :: ratio - character(len=*) , intent(in) :: carbon_type - type(cnveg_carbonstate_type) , intent(in), optional :: c12_cnveg_carbonstate_inst + character(len=*) , intent(in) :: carbon_type ! Carbon isotope type C12, C13 or C1 + character(len=*) , intent(in) :: NLFilename ! Namelist filename + type(cnveg_carbonstate_type) , intent(in), optional :: c12_cnveg_carbonstate_inst ! cnveg_carbonstate for C12 (if C13 or C14) !----------------------------------------------------------------------- this%species = species_from_string(carbon_type) call this%InitAllocate ( bounds) + call this%InitReadNML ( NLFilename ) call this%InitHistory ( bounds, carbon_type) if (present(c12_cnveg_carbonstate_inst)) then - call this%InitCold ( bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst) + call this%InitCold ( bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst ) else - call this%InitCold ( bounds, ratio, carbon_type) + call this%InitCold ( bounds, ratio, carbon_type ) end if end subroutine Init + !------------------------------------------------------------------------ + subroutine InitReadNML(this, NLFilename) + ! + ! !DESCRIPTION: + ! Read the namelist for CNVegCarbonState + ! + !USES: + use fileutils , only : getavu, relavu, opnfil + use shr_nl_mod , only : shr_nl_find_group_name + use spmdMod , only : masterproc, mpicom + use shr_mpi_mod , only : shr_mpi_bcast + use clm_varctl , only : iulog + ! + ! !ARGUMENTS: + class(cnveg_carbonstate_type) :: this + character(len=*) , intent(in) :: NLFilename ! Namelist filename + ! + ! !LOCAL VARIABLES: + integer :: ierr ! error code + integer :: unitn ! unit for namelist file + + character(len=*), parameter :: subname = 'InitReadNML' + character(len=*), parameter :: nmlname = 'cnvegcarbonstate' ! MUST match what is in namelist below + !----------------------------------------------------------------------- + real(r8) :: initial_vegC + namelist /cnvegcarbonstate/ initial_vegC + + initial_vegC = cnvegcstate_const%initial_vegC + + if (masterproc) then + unitn = getavu() + write(iulog,*) 'Read in '//nmlname//' namelist' + call opnfil (NLFilename, unitn, 'F') + call shr_nl_find_group_name(unitn, nmlname, status=ierr) + if (ierr == 0) then + read(unitn, nml=cnvegcarbonstate, iostat=ierr) + if (ierr /= 0) then + call endrun(msg="ERROR reading "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + else + call endrun(msg="ERROR could NOT find "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + call relavu( unitn ) + end if + + call shr_mpi_bcast (initial_vegC , mpicom) + + cnvegcstate_const%initial_vegC = initial_vegC + + if (masterproc) then + write(iulog,*) ' ' + write(iulog,*) nmlname//' settings:' + write(iulog,nml=cnvegcarbonstate) ! Name here MUST be the same as in nmlname above! + write(iulog,*) ' ' + end if + + !----------------------------------------------------------------------- + + end subroutine InitReadNML + !------------------------------------------------------------------------ subroutine InitAllocate(this, bounds) ! @@ -257,12 +327,12 @@ subroutine InitHistory(this, bounds, carbon_type) this%leafc_storage_patch(begp:endp) = spval call hist_addfld1d (fname='LEAFC_STORAGE', units='gC/m^2', & avgflag='A', long_name='leaf C storage', & - ptr_patch=this%leafc_storage_patch) + ptr_patch=this%leafc_storage_patch, default='inactive') this%leafc_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='LEAFC_XFER', units='gC/m^2', & avgflag='A', long_name='leaf C transfer', & - ptr_patch=this%leafc_xfer_patch) + ptr_patch=this%leafc_xfer_patch, default='inactive') this%leafc_storage_xfer_acc_patch(begp:endp) = spval call hist_addfld1d (fname='LEAFC_STORAGE_XFER_ACC', units='gC/m^2', & @@ -282,12 +352,12 @@ subroutine InitHistory(this, bounds, carbon_type) this%frootc_storage_patch(begp:endp) = spval call hist_addfld1d (fname='FROOTC_STORAGE', units='gC/m^2', & avgflag='A', long_name='fine root C storage', & - ptr_patch=this%frootc_storage_patch) + ptr_patch=this%frootc_storage_patch, default='inactive') this%frootc_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='FROOTC_XFER', units='gC/m^2', & avgflag='A', long_name='fine root C transfer', & - ptr_patch=this%frootc_xfer_patch) + ptr_patch=this%frootc_xfer_patch, default='inactive') this%livestemc_patch(begp:endp) = spval call hist_addfld1d (fname='LIVESTEMC', units='gC/m^2', & @@ -297,12 +367,12 @@ subroutine InitHistory(this, bounds, carbon_type) this%livestemc_storage_patch(begp:endp) = spval call hist_addfld1d (fname='LIVESTEMC_STORAGE', units='gC/m^2', & avgflag='A', long_name='live stem C storage', & - ptr_patch=this%livestemc_storage_patch) + ptr_patch=this%livestemc_storage_patch, default='inactive') this%livestemc_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='LIVESTEMC_XFER', units='gC/m^2', & avgflag='A', long_name='live stem C transfer', & - ptr_patch=this%livestemc_xfer_patch) + ptr_patch=this%livestemc_xfer_patch, default='inactive') this%deadstemc_patch(begp:endp) = spval call hist_addfld1d (fname='DEADSTEMC', units='gC/m^2', & @@ -312,12 +382,12 @@ subroutine InitHistory(this, bounds, carbon_type) this%deadstemc_storage_patch(begp:endp) = spval call hist_addfld1d (fname='DEADSTEMC_STORAGE', units='gC/m^2', & avgflag='A', long_name='dead stem C storage', & - ptr_patch=this%deadstemc_storage_patch) + ptr_patch=this%deadstemc_storage_patch, default='inactive') this%deadstemc_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='DEADSTEMC_XFER', units='gC/m^2', & avgflag='A', long_name='dead stem C transfer', & - ptr_patch=this%deadstemc_xfer_patch) + ptr_patch=this%deadstemc_xfer_patch, default='inactive') this%livecrootc_patch(begp:endp) = spval call hist_addfld1d (fname='LIVECROOTC', units='gC/m^2', & @@ -327,12 +397,12 @@ subroutine InitHistory(this, bounds, carbon_type) this%livecrootc_storage_patch(begp:endp) = spval call hist_addfld1d (fname='LIVECROOTC_STORAGE', units='gC/m^2', & avgflag='A', long_name='live coarse root C storage', & - ptr_patch=this%livecrootc_storage_patch) + ptr_patch=this%livecrootc_storage_patch, default='inactive') this%livecrootc_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='LIVECROOTC_XFER', units='gC/m^2', & avgflag='A', long_name='live coarse root C transfer', & - ptr_patch=this%livecrootc_xfer_patch) + ptr_patch=this%livecrootc_xfer_patch, default='inactive') this%deadcrootc_patch(begp:endp) = spval call hist_addfld1d (fname='DEADCROOTC', units='gC/m^2', & @@ -342,22 +412,22 @@ subroutine InitHistory(this, bounds, carbon_type) this%deadcrootc_storage_patch(begp:endp) = spval call hist_addfld1d (fname='DEADCROOTC_STORAGE', units='gC/m^2', & avgflag='A', long_name='dead coarse root C storage', & - ptr_patch=this%deadcrootc_storage_patch) + ptr_patch=this%deadcrootc_storage_patch, default='inactive') this%deadcrootc_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='DEADCROOTC_XFER', units='gC/m^2', & avgflag='A', long_name='dead coarse root C transfer', & - ptr_patch=this%deadcrootc_xfer_patch) + ptr_patch=this%deadcrootc_xfer_patch, default='inactive') this%gresp_storage_patch(begp:endp) = spval call hist_addfld1d (fname='GRESP_STORAGE', units='gC/m^2', & avgflag='A', long_name='growth respiration storage', & - ptr_patch=this%gresp_storage_patch) + ptr_patch=this%gresp_storage_patch, default='inactive') this%gresp_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='GRESP_XFER', units='gC/m^2', & avgflag='A', long_name='growth respiration transfer', & - ptr_patch=this%gresp_xfer_patch) + ptr_patch=this%gresp_xfer_patch, default='inactive') this%cpool_patch(begp:endp) = spval call hist_addfld1d (fname='CPOOL', units='gC/m^2', & @@ -372,7 +442,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%ctrunc_patch(begp:endp) = spval call hist_addfld1d (fname='PFT_CTRUNC', units='gC/m^2', & avgflag='A', long_name='patch-level sink for C truncation', & - ptr_patch=this%ctrunc_patch) + ptr_patch=this%ctrunc_patch, default='inactive') this%dispvegc_patch(begp:endp) = spval call hist_addfld1d (fname='DISPVEGC', units='gC/m^2', & @@ -540,7 +610,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%ctrunc_patch(begp:endp) = spval call hist_addfld1d (fname='C13_PFT_CTRUNC', units='gC13/m^2', & avgflag='A', long_name='C13 patch-level sink for C truncation', & - ptr_patch=this%ctrunc_patch) + ptr_patch=this%ctrunc_patch, default='inactive') this%dispvegc_patch(begp:endp) = spval call hist_addfld1d (fname='C13_DISPVEGC', units='gC13/m^2', & @@ -577,6 +647,18 @@ subroutine InitHistory(this, bounds, carbon_type) avgflag='A', long_name='C13 total ecosystem carbon, incl veg but excl cpool and product pools', & ptr_col=this%totecosysc_col) + if (use_crop) then + this%grainc_patch(begp:endp) = spval + call hist_addfld1d (fname='C13_GRAINC', units='gC/m^2', & + avgflag='A', long_name='C13 grain C (does not equal yield)', & + ptr_patch=this%grainc_patch) + this%cropseedc_deficit_patch(begp:endp) = spval + call hist_addfld1d (fname='C13_CROPSEEDC_DEFICIT', units='gC/m^2', & + avgflag='A', long_name='C13 C used for crop seed that needs to be repaid', & + ptr_patch=this%cropseedc_deficit_patch) + end if + + endif !------------------------------- @@ -740,6 +822,18 @@ subroutine InitHistory(this, bounds, carbon_type) avgflag='A', long_name='C14 total ecosystem carbon, incl veg but excl cpool and product pools', & ptr_col=this%totecosysc_col) + if (use_crop) then + this%grainc_patch(begp:endp) = spval + call hist_addfld1d (fname='C14_GRAINC', units='gC/m^2', & + avgflag='A', long_name='C14 grain C (does not equal yield)', & + ptr_patch=this%grainc_patch) + this%cropseedc_deficit_patch(begp:endp) = spval + call hist_addfld1d (fname='C14_CROPSEEDC_DEFICIT', units='gC/m^2', & + avgflag='A', long_name='C14 C used for crop seed that needs to be repaid', & + ptr_patch=this%cropseedc_deficit_patch) + end if + + endif end subroutine InitHistory @@ -758,8 +852,8 @@ subroutine InitCold(this, bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst ! !ARGUMENTS: class(cnveg_carbonstate_type) :: this type(bounds_type) , intent(in) :: bounds - real(r8) , intent(in) :: ratio - character(len=*) , intent(in) :: carbon_type ! 'c12' or 'c13' or 'c14' + real(r8) , intent(in) :: ratio ! Standard isotope ratio + character(len=*) , intent(in) :: carbon_type ! 'c12' or 'c13' or 'c14' type(cnveg_carbonstate_type) , optional, intent(in) :: c12_cnveg_carbonstate_inst ! ! !LOCAL VARIABLES: @@ -812,36 +906,26 @@ subroutine InitCold(this, bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then if (patch%itype(p) == noveg) then - this%leafc_patch(p) = 0._r8 - this%leafc_storage_patch(p) = 0._r8 - if (MM_Nuptake_opt .eqv. .true.) then - this%frootc_patch(p) = 0._r8 - this%frootc_storage_patch(p) = 0._r8 - end if + this%leafc_patch(p) = 0._r8 + this%leafc_storage_patch(p) = 0._r8 + this%frootc_patch(p) = 0._r8 + this%frootc_storage_patch(p) = 0._r8 else if (pftcon%evergreen(patch%itype(p)) == 1._r8) then - this%leafc_patch(p) = 1._r8 * ratio - this%leafc_storage_patch(p) = 0._r8 - if (MM_Nuptake_opt .eqv. .true.) then - this%leafc_patch(p) = 20._r8 * ratio - this%frootc_patch(p) = 20._r8 * ratio - this%frootc_storage_patch(p) = 0._r8 - end if + this%leafc_patch(p) = cnvegcstate_const%initial_vegC * ratio + this%leafc_storage_patch(p) = 0._r8 + this%frootc_patch(p) = cnvegcstate_const%initial_vegC * ratio + this%frootc_storage_patch(p) = 0._r8 else if (patch%itype(p) >= npcropmin) then ! prognostic crop types - this%leafc_patch(p) = 0._r8 - this%leafc_storage_patch(p) = 0._r8 - if (MM_Nuptake_opt .eqv. .true.) then - this%frootc_patch(p) = 0._r8 - this%frootc_storage_patch(p) = 0._r8 - end if + this%leafc_patch(p) = 0._r8 + this%leafc_storage_patch(p) = 0._r8 + this%frootc_patch(p) = 0._r8 + this%frootc_storage_patch(p) = 0._r8 else - this%leafc_patch(p) = 0._r8 - this%leafc_storage_patch(p) = 1._r8 * ratio - if (MM_Nuptake_opt .eqv. .true.) then - this%leafc_storage_patch(p) = 20._r8 * ratio - this%frootc_patch(p) = 0._r8 - this%frootc_storage_patch(p) = 20._r8 * ratio - end if + this%leafc_patch(p) = 0._r8 + this%leafc_storage_patch(p) = cnvegcstate_const%initial_vegC * ratio + this%frootc_patch(p) = 0._r8 + this%frootc_storage_patch(p) = cnvegcstate_const%initial_vegC * ratio end if end if this%leafc_xfer_patch(p) = 0._r8 @@ -951,7 +1035,9 @@ subroutine InitCold(this, bounds, ratio, carbon_type, c12_cnveg_carbonstate_inst end subroutine InitCold !----------------------------------------------------------------------- - subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonstate_inst) + subroutine Restart ( this, bounds, ncid, flag, carbon_type, reseed_dead_plants, & + c12_cnveg_carbonstate_inst, filter_reseed_patch, & + num_reseed_patch) ! ! !DESCRIPTION: ! Read/write CN restart data for carbon state @@ -962,6 +1048,8 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta use clm_varctl , only : spinup_state, use_cndv, MM_Nuptake_opt use clm_time_manager , only : get_nstep, is_restart, get_nstep use landunit_varcon , only : istsoil, istcrop + use spmdMod , only : mpicom + use shr_mpi_mod , only : shr_mpi_sum use restUtilMod use ncdio_pio ! @@ -971,7 +1059,10 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta type(file_desc_t) , intent(inout) :: ncid ! netcdf id character(len=*) , intent(in) :: flag !'read' or 'write' character(len=*) , intent(in) :: carbon_type ! 'c12' or 'c13' or 'c14' + logical , intent(in) :: reseed_dead_plants type (cnveg_carbonstate_type) , intent(in), optional :: c12_cnveg_carbonstate_inst + integer , intent(out), optional :: filter_reseed_patch(:) + integer , intent(out), optional :: num_reseed_patch ! ! !LOCAL VARIABLES: integer :: i,j,k,l,c,p @@ -985,6 +1076,7 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta integer :: decomp_cascade_state, restart_file_decomp_cascade_state ! spinup state as read from restart file, for determining whether to enter or exit spinup mode. integer :: restart_file_spinup_state + integer :: total_num_reseed_patch ! Total number of patches to reseed across all processors !------------------------------------------------------------------------ @@ -1002,6 +1094,16 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta ratio = c14ratio end if + if ( ( present(num_reseed_patch) .and. .not. present(filter_reseed_patch)) & + .or. (.not. present(num_reseed_patch) .and. present(filter_reseed_patch) ) )then + call endrun(msg=' ERROR: filter_reseed_patch and num_reseed_patch both need to be entered ' //& + errMsg(sourcefile, __LINE__)) + end if + if ( present(num_reseed_patch) )then + num_reseed_patch = 0 + filter_reseed_patch(:) = -1 + end if + !-------------------------------- ! patch carbon state variables (c12) !-------------------------------- @@ -1140,66 +1242,106 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta this%deadstemc_patch(i) = this%deadstemc_patch(i) * 10._r8 this%deadcrootc_patch(i) = this%deadcrootc_patch(i) * 10._r8 end do - else if (spinup_state == 2 .and. restart_file_spinup_state <= 1 ) then - if ( masterproc ) write(iulog,*) ' CNRest: taking Dead wood C pools into AD spinup mode' - enter_spinup = .true. - if ( masterproc ) write(iulog, *) 'Dividing stemc and crootc by 10 for enter spinup ' - ! If a pft is dead (indicated by totvegc = 0) then we reseed that - ! pft according to the cold start protocol in the InitCold subroutine. - ! Thus, the variable totvegc is required to be read here from the restart file - ! so that if it is zero for a given pft, the pft can be reseeded. - ! This is only done if spinup_state == 2 and restart_file_spinup_state <=1. - ! totvegc is read in for all situations, including this one, at the end - ! of this subroutine. - !-------------------------------- - ! C12 carbon state variables - !-------------------------------- - - if (carbon_type == 'c12') then - call restartvar(ncid=ncid, flag=flag, varname='totvegc', xtype=ncd_double, & - dim1name='pft', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=this%totvegc_patch) + else if (spinup_state == 2 .and. restart_file_spinup_state <= 1 )then + if (spinup_state == 2 .and. restart_file_spinup_state <= 1 )then + if ( masterproc ) write(iulog,*) ' CNRest: taking Dead wood C pools into AD spinup mode' + enter_spinup = .true. + if ( masterproc ) write(iulog, *) 'Dividing stemc and crootc by 10 for enter spinup ' + do i = bounds%begp,bounds%endp + this%deadstemc_patch(i) = this%deadstemc_patch(i) / 10._r8 + this%deadcrootc_patch(i) = this%deadcrootc_patch(i) / 10._r8 + end do end if + end if + end if + !-------------------------------- + ! C12 carbon state variables + !-------------------------------- - !-------------------------------- - ! C13 carbon state variables - !-------------------------------- - - if ( carbon_type == 'c13') then - call restartvar(ncid=ncid, flag=flag, varname='totvegc_13', xtype=ncd_double, & - dim1name='pft', & - long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=this%totvegc_patch) - if (flag=='read' .and. .not. readvar) then - if ( masterproc ) write(iulog,*) 'initializing cnveg_carbonstate_inst%totvegc with atmospheric c13 value' - do i = bounds%begp,bounds%endp - if (pftcon%c3psn(patch%itype(i)) == 1._r8) then - this%totvegc_patch(i) = c12_cnveg_carbonstate_inst%totvegc_patch(i) * c3_r2 - else - this%totvegc_patch(i) = c12_cnveg_carbonstate_inst%totvegc_patch(i) * c4_r2 - endif - end do - end if - end if + if (carbon_type == 'c12') then + call restartvar(ncid=ncid, flag=flag, varname='totvegc', xtype=ncd_double, & + dim1name='pft', long_name='', units='', & + interpinic_flag='interp', readvar=readvar, data=this%totvegc_patch) + ! totvegc_col needed for resetting soil carbon stocks during AD spinup exit + call restartvar(ncid=ncid, flag=flag, varname='totvegc_col', xtype=ncd_double, & + dim1name='column', long_name='', units='', & + interpinic_flag='interp', readvar=readvar, data=this%totvegc_col) + end if - !-------------------------------- - ! C14 patch carbon state variables - !-------------------------------- - - if ( carbon_type == 'c14') then - call restartvar(ncid=ncid, flag=flag, varname='totvegc_14', xtype=ncd_double, & - dim1name='pft', long_name='', units='', & - interpinic_flag='interp', readvar=readvar, data=this%totvegc_patch) - if (flag=='read' .and. .not. readvar) then - if ( masterproc ) write(iulog,*) 'initializing this%totvegc_patch with atmospheric c14 value' - do i = bounds%begp,bounds%endp - if (this%totvegc_patch(i) /= spval .and. & - .not. isnan(this%totvegc_patch(i)) ) then - this%totvegc_patch(i) = c12_cnveg_carbonstate_inst%totvegc_patch(i) * c14ratio - endif - end do - end if - end if + !-------------------------------- + ! C13 carbon state variables + !-------------------------------- + + if ( carbon_type == 'c13') then + call restartvar(ncid=ncid, flag=flag, varname='totvegc_13', xtype=ncd_double, & + dim1name='pft', long_name='', units='', & + interpinic_flag='interp', readvar=readvar, data=this%totvegc_patch) + if (flag=='read' .and. .not. readvar) then + if ( masterproc ) write(iulog,*) 'initializing cnveg_carbonstate_inst%totvegc with atmospheric c13 value' + do i = bounds%begp,bounds%endp + if (pftcon%c3psn(patch%itype(i)) == 1._r8) then + this%totvegc_patch(i) = c12_cnveg_carbonstate_inst%totvegc_patch(i) * c3_r2 + else + this%totvegc_patch(i) = c12_cnveg_carbonstate_inst%totvegc_patch(i) * c4_r2 + endif + end do + end if + + call restartvar(ncid=ncid, flag=flag, varname='totvegc_col_13', xtype=ncd_double, & + dim1name='column', long_name='', units='', & + interpinic_flag='interp', readvar=readvar, data=this%totvegc_col) + if (flag=='read' .and. .not. readvar) then + if ( masterproc ) write(iulog,*) 'initializing cnveg_carbonstate_inst%totvegc with atmospheric c13 value' + do i = bounds%begc,bounds%endc + if (pftcon%c3psn(patch%itype(i)) == 1._r8) then + this%totvegc_col(i) = c12_cnveg_carbonstate_inst%totvegc_col(i) * c3_r2 + else + this%totvegc_col(i) = c12_cnveg_carbonstate_inst%totvegc_col(i) * c4_r2 + endif + end do + end if + + end if + + !-------------------------------- + ! C14 patch carbon state variables + !-------------------------------- + + if ( carbon_type == 'c14') then + call restartvar(ncid=ncid, flag=flag, varname='totvegc_14', xtype=ncd_double, & + dim1name='pft', long_name='', units='', & + interpinic_flag='interp', readvar=readvar, data=this%totvegc_patch) + if (flag=='read' .and. .not. readvar) then + if ( masterproc ) write(iulog,*) 'initializing this%totvegc_patch with atmospheric c14 value' + do i = bounds%begp,bounds%endp + if (this%totvegc_patch(i) /= spval .and. & + .not. isnan(this%totvegc_patch(i)) ) then + this%totvegc_patch(i) = c12_cnveg_carbonstate_inst%totvegc_patch(i) * c14ratio + endif + end do + endif + + call restartvar(ncid=ncid, flag=flag, varname='totvegc_col_14', xtype=ncd_double, & + dim1name='column', long_name='', units='', & + interpinic_flag='interp', readvar=readvar, data=this%totvegc_col) + if (flag=='read' .and. .not. readvar) then + if ( masterproc ) write(iulog,*) 'initializing cnveg_carbonstate_inst%totvegc with atmospheric c14 value' + do i = bounds%begc,bounds%endc + if (this%totvegc_col(i) /= spval .and. & + .not. isnan(this%totvegc_col(i)) ) then + this%totvegc_col(i) = c12_cnveg_carbonstate_inst%totvegc_col(i) * c14ratio + endif + end do + end if + end if + + + if ( flag == 'read' .and. (enter_spinup .or. (reseed_dead_plants .and. .not. is_restart())) .and. .not. use_cndv) then + if ( masterproc ) write(iulog, *) 'Reseeding dead plants for CNVegCarbonState' + ! If a pft is dead (indicated by totvegc = 0) then we reseed that + ! pft according to the cold start protocol in the InitCold subroutine. + ! Thus, the variable totvegc is required to be read before here + ! so that if it is zero for a given pft, the pft can be reseeded. do i = bounds%begp,bounds%endp if (this%totvegc_patch(i) .le. 0.0_r8) then !----------------------------------------------- @@ -1209,39 +1351,28 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta this%leafcmax_patch(i) = 0._r8 l = patch%landunit(i) - if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + if (lun%itype(l) == istsoil )then + if ( present(num_reseed_patch) ) then + num_reseed_patch = num_reseed_patch + 1 + filter_reseed_patch(num_reseed_patch) = i + end if if (patch%itype(i) == noveg) then - this%leafc_patch(i) = 0._r8 - this%leafc_storage_patch(i) = 0._r8 - if (MM_Nuptake_opt .eqv. .true.) then - this%frootc_patch(i) = 0._r8 - this%frootc_storage_patch(i) = 0._r8 - end if + this%leafc_patch(i) = 0._r8 + this%leafc_storage_patch(i) = 0._r8 + this%frootc_patch(i) = 0._r8 + this%frootc_storage_patch(i) = 0._r8 else if (pftcon%evergreen(patch%itype(i)) == 1._r8) then - this%leafc_patch(i) = 1._r8 * ratio - this%leafc_storage_patch(i) = 0._r8 - if (MM_Nuptake_opt .eqv. .true.) then - this%leafc_patch(i) = 20._r8 * ratio - this%frootc_patch(i) = 20._r8 * ratio - this%frootc_storage_patch(i) = 0._r8 - end if - else if (patch%itype(i) >= npcropmin) then ! prognostic crop types - this%leafc_patch(i) = 0._r8 - this%leafc_storage_patch(i) = 0._r8 - if (MM_Nuptake_opt .eqv. .true.) then - this%frootc_patch(i) = 0._r8 - this%frootc_storage_patch(i) = 0._r8 - end if + this%leafc_patch(i) = cnvegcstate_const%initial_vegC * ratio + this%leafc_storage_patch(i) = 0._r8 + this%frootc_patch(i) = cnvegcstate_const%initial_vegC * ratio + this%frootc_storage_patch(i) = 0._r8 else - this%leafc_patch(i) = 0._r8 - this%leafc_storage_patch(i) = 1._r8 * ratio - if (MM_Nuptake_opt .eqv. .true.) then - this%leafc_storage_patch(i) = 20._r8 * ratio - this%frootc_patch(i) = 0._r8 - this%frootc_storage_patch(i) = 20._r8 * ratio - end if + this%leafc_patch(i) = 0._r8 + this%leafc_storage_patch(i) = cnvegcstate_const%initial_vegC * ratio + this%frootc_patch(i) = 0._r8 + this%frootc_storage_patch(i) = cnvegcstate_const%initial_vegC * ratio end if end if this%leafc_xfer_patch(i) = 0._r8 @@ -1327,9 +1458,6 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta end if endif - else - this%deadstemc_patch(i) = this%deadstemc_patch(i) / 10._r8 - this%deadcrootc_patch(i) = this%deadcrootc_patch(i) / 10._r8 end if end do if ( .not. is_restart() .and. get_nstep() == 1 ) then @@ -1358,7 +1486,10 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta end if end do end if - end if + if ( present(num_reseed_patch) ) then + call shr_mpi_sum( num_reseed_patch, total_num_reseed_patch, mpicom ) + if ( masterproc ) write(iulog,*) 'Total num_reseed, over all tasks = ', total_num_reseed_patch + end if end if end if @@ -1392,6 +1523,7 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta this%leafc_storage_patch(i) = c12_cnveg_carbonstate_inst%leafc_storage_patch(i) * c3_r2 else this%leafc_storage_patch(i) = c12_cnveg_carbonstate_inst%leafc_storage_patch(i) * c4_r2 + this%leafc_storage_patch(i) = c12_cnveg_carbonstate_inst%leafc_storage_patch(i) * c4_r2 endif end do end if @@ -1987,28 +2119,55 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta !-------------------------------- if (use_crop) then - ! TODO(wjs, 2017-01-18) Introduce isotopic versions of the following (can follow - ! what's done for cropseedc_deficit, below): - - call restartvar(ncid=ncid, flag=flag, varname='grainc', xtype=ncd_double, & - dim1name='pft', long_name='grain C', units='gC/m2', & - interpinic_flag='interp', readvar=readvar, data=this%grainc_patch) + if (carbon_type == 'c12') then + call restartvar(ncid=ncid, flag=flag, varname='grainc', xtype=ncd_double, & + dim1name='pft', long_name='grain C', units='gC/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_patch) - call restartvar(ncid=ncid, flag=flag, varname='grainc_storage', xtype=ncd_double, & - dim1name='pft', long_name='grain C storage', units='gC/m2', & - interpinic_flag='interp', readvar=readvar, data=this%grainc_storage_patch) + call restartvar(ncid=ncid, flag=flag, varname='grainc_storage', xtype=ncd_double, & + dim1name='pft', long_name='grain C storage', units='gC/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_storage_patch) - call restartvar(ncid=ncid, flag=flag, varname='grainc_xfer', xtype=ncd_double, & - dim1name='pft', long_name='grain C transfer', units='gC/m2', & - interpinic_flag='interp', readvar=readvar, data=this%grainc_xfer_patch) + call restartvar(ncid=ncid, flag=flag, varname='grainc_xfer', xtype=ncd_double, & + dim1name='pft', long_name='grain C transfer', units='gC/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_xfer_patch) - if (carbon_type == 'c12') then call restartvar(ncid=ncid, flag=flag, varname='cropseedc_deficit', xtype=ncd_double, & dim1name='pft', long_name='pool for seeding new crop growth', units='gC/m2', & interpinic_flag='interp', readvar=readvar, data=this%cropseedc_deficit_patch) end if if (carbon_type == 'c13') then + call restartvar(ncid=ncid, flag=flag, varname='grainc_13', xtype=ncd_double, & + dim1name='pft', long_name='c13 grain C', units='gC13/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_patch) + if (flag=='read' .and. .not. readvar) then + call set_missing_from_template( & + my_var = this%grainc_patch, & + template_var = c12_cnveg_carbonstate_inst%grainc_patch, & + multiplier = c3_r2) + end if + + call restartvar(ncid=ncid, flag=flag, varname='grainc_13_storage', xtype=ncd_double, & + dim1name='pft', long_name='c13 grain C storage', units='gC13/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_storage_patch) + if (flag=='read' .and. .not. readvar) then + call set_missing_from_template( & + my_var = this%grainc_storage_patch, & + template_var = c12_cnveg_carbonstate_inst%grainc_storage_patch, & + multiplier = c3_r2) + end if + + call restartvar(ncid=ncid, flag=flag, varname='grainc_13_xfer', xtype=ncd_double, & + dim1name='pft', long_name='c13 grain C transfer', units='gC13/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_xfer_patch) + if (flag=='read' .and. .not. readvar) then + call set_missing_from_template( & + my_var = this%grainc_xfer_patch, & + template_var = c12_cnveg_carbonstate_inst%grainc_xfer_patch, & + multiplier = c3_r2) + end if + call restartvar(ncid=ncid, flag=flag, varname='cropseedc_13_deficit', xtype=ncd_double, & dim1name='pft', long_name='pool for seeding new crop growth', units='gC13/m2', & interpinic_flag='interp', readvar=readvar, data=this%cropseedc_deficit_patch) @@ -2021,6 +2180,37 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_cnveg_carbonsta end if if ( carbon_type == 'c14' ) then + + call restartvar(ncid=ncid, flag=flag, varname='grainc_14', xtype=ncd_double, & + dim1name='pft', long_name='c14 grain C', units='gC14/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_patch) + if (flag=='read' .and. .not. readvar) then + call set_missing_from_template( & + my_var = this%grainc_patch, & + template_var = c12_cnveg_carbonstate_inst%grainc_patch, & + multiplier = c3_r2) + end if + + call restartvar(ncid=ncid, flag=flag, varname='grainc_14_storage', xtype=ncd_double, & + dim1name='pft', long_name='c14 grain C storage', units='gC14/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_storage_patch) + if (flag=='read' .and. .not. readvar) then + call set_missing_from_template( & + my_var = this%grainc_storage_patch, & + template_var = c12_cnveg_carbonstate_inst%grainc_storage_patch, & + multiplier = c3_r2) + end if + + call restartvar(ncid=ncid, flag=flag, varname='grainc_14_xfer', xtype=ncd_double, & + dim1name='pft', long_name='c14 grain C transfer', units='gC14/m2', & + interpinic_flag='interp', readvar=readvar, data=this%grainc_xfer_patch) + if (flag=='read' .and. .not. readvar) then + call set_missing_from_template( & + my_var = this%grainc_xfer_patch, & + template_var = c12_cnveg_carbonstate_inst%grainc_xfer_patch, & + multiplier = c3_r2) + end if + call restartvar(ncid=ncid, flag=flag, varname='cropseedc_14_deficit', xtype=ncd_double, & dim1name='pft', long_name='pool for seeding new crop growth', units='gC14/m2', & interpinic_flag='interp', readvar=readvar, data=this%cropseedc_deficit_patch) @@ -2188,6 +2378,8 @@ subroutine Summary_carbonstate(this, bounds, num_allc, filter_allc, & ! ! !USES: use subgridAveMod, only : p2c + use clm_time_manager , only : get_nstep + ! ! !DESCRIPTION: ! Perform patch and column-level carbon summary calculations @@ -2252,8 +2444,7 @@ subroutine Summary_carbonstate(this, bounds, num_allc, filter_allc, & this%storvegc_patch(p) = & this%storvegc_patch(p) + & this%grainc_storage_patch(p) + & - this%grainc_xfer_patch(p) + & - this%cropseedc_deficit_patch(p) + this%grainc_xfer_patch(p) this%dispvegc_patch(p) = & this%dispvegc_patch(p) + & @@ -2271,6 +2462,10 @@ subroutine Summary_carbonstate(this, bounds, num_allc, filter_allc, & this%xsmrpool_patch(p) + & this%ctrunc_patch(p) + if (use_crop) then + this%totc_patch(p) = this%totc_patch(p) + this%cropseedc_deficit_patch(p) + end if + ! (WOODC) - wood C this%woodc_patch(p) = & this%deadstemc_patch(p) + & @@ -2494,16 +2689,9 @@ subroutine DynamicPatchAdjustments(this, bounds, & var = this%cpool_patch(begp:endp), & flux_out_grc_area = conv_cflux(begp:endp)) - ! BUG(wjs, 2016-06-01, bugz 2316) Probably the behavior should be the same for carbon - ! isotopes as for standard c12, but for now I'm preserving the old behavior. - if (this%species == CN_SPECIES_C12) then - call update_patch_state( & - var = this%xsmrpool_patch(begp:endp), & - flux_out_grc_area = conv_cflux(begp:endp)) - else - call update_patch_state( & - var = this%xsmrpool_patch(begp:endp)) - end if + call update_patch_state( & + var = this%xsmrpool_patch(begp:endp), & + flux_out_grc_area = conv_cflux(begp:endp)) call update_patch_state( & var = this%ctrunc_patch(begp:endp), & diff --git a/src/biogeochem/CNVegNitrogenFluxType.F90 b/src/biogeochem/CNVegNitrogenFluxType.F90 index 3eca615ef4..1bb630c687 100644 --- a/src/biogeochem/CNVegNitrogenFluxType.F90 +++ b/src/biogeochem/CNVegNitrogenFluxType.F90 @@ -946,7 +946,7 @@ subroutine InitHistory(this, bounds) if (use_crop) then this%fert_patch(begp:endp) = spval - call hist_addfld1d (fname='FERT', units='gN/m^2/s', & + call hist_addfld1d (fname='NFERTILIZATION', units='gN/m^2/s', & avgflag='A', long_name='fertilizer added', & ptr_patch=this%fert_patch) end if @@ -962,7 +962,7 @@ subroutine InitHistory(this, bounds) this%fert_counter_patch(begp:endp) = spval call hist_addfld1d (fname='FERT_COUNTER', units='seconds', & avgflag='A', long_name='time left to fertilize', & - ptr_patch=this%fert_counter_patch) + ptr_patch=this%fert_counter_patch, default='inactive') end if !------------------------------- @@ -1062,7 +1062,7 @@ subroutine InitHistory(this, bounds) this%crop_seedn_to_leaf_patch(begp:endp) = spval call hist_addfld1d (fname='CROP_SEEDN_TO_LEAF', units='gN/m^2/s', & avgflag='A', long_name='crop seed source to leaf', & - ptr_patch=this%crop_seedn_to_leaf_patch) + ptr_patch=this%crop_seedn_to_leaf_patch, default='inactive') this%plant_ndemand_patch(begp:endp) = spval call hist_addfld1d (fname='PLANT_NDEMAND', units='gN/m^2/s', & diff --git a/src/biogeochem/CNVegNitrogenStateType.F90 b/src/biogeochem/CNVegNitrogenStateType.F90 index 78702c3d09..97a5ffaae4 100644 --- a/src/biogeochem/CNVegNitrogenStateType.F90 +++ b/src/biogeochem/CNVegNitrogenStateType.F90 @@ -208,7 +208,7 @@ subroutine InitHistory(this, bounds) ptr_patch=this%grainn_patch) call hist_addfld1d (fname='CROPSEEDN_DEFICIT', units='gN/m^2', & avgflag='A', long_name='N used for crop seed that needs to be repaid', & - ptr_patch=this%cropseedn_deficit_patch) + ptr_patch=this%cropseedn_deficit_patch, default='inactive') end if this%leafn_patch(begp:endp) = spval @@ -219,12 +219,12 @@ subroutine InitHistory(this, bounds) this%leafn_storage_patch(begp:endp) = spval call hist_addfld1d (fname='LEAFN_STORAGE', units='gN/m^2', & avgflag='A', long_name='leaf N storage', & - ptr_patch=this%leafn_storage_patch) + ptr_patch=this%leafn_storage_patch, default='inactive') this%leafn_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='LEAFN_XFER', units='gN/m^2', & avgflag='A', long_name='leaf N transfer', & - ptr_patch=this%leafn_xfer_patch) + ptr_patch=this%leafn_xfer_patch, default='inactive') if ( use_fun ) then this%leafn_storage_xfer_acc_patch(begp:endp) = spval @@ -246,12 +246,12 @@ subroutine InitHistory(this, bounds) this%frootn_storage_patch(begp:endp) = spval call hist_addfld1d (fname='FROOTN_STORAGE', units='gN/m^2', & avgflag='A', long_name='fine root N storage', & - ptr_patch=this%frootn_storage_patch) + ptr_patch=this%frootn_storage_patch, default='inactive') this%frootn_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='FROOTN_XFER', units='gN/m^2', & avgflag='A', long_name='fine root N transfer', & - ptr_patch=this%frootn_xfer_patch) + ptr_patch=this%frootn_xfer_patch, default='inactive') this%livestemn_patch(begp:endp) = spval call hist_addfld1d (fname='LIVESTEMN', units='gN/m^2', & @@ -261,12 +261,12 @@ subroutine InitHistory(this, bounds) this%livestemn_storage_patch(begp:endp) = spval call hist_addfld1d (fname='LIVESTEMN_STORAGE', units='gN/m^2', & avgflag='A', long_name='live stem N storage', & - ptr_patch=this%livestemn_storage_patch) + ptr_patch=this%livestemn_storage_patch, default='inactive') this%livestemn_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='LIVESTEMN_XFER', units='gN/m^2', & avgflag='A', long_name='live stem N transfer', & - ptr_patch=this%livestemn_xfer_patch) + ptr_patch=this%livestemn_xfer_patch, default='inactive') this%deadstemn_patch(begp:endp) = spval call hist_addfld1d (fname='DEADSTEMN', units='gN/m^2', & @@ -276,12 +276,12 @@ subroutine InitHistory(this, bounds) this%deadstemn_storage_patch(begp:endp) = spval call hist_addfld1d (fname='DEADSTEMN_STORAGE', units='gN/m^2', & avgflag='A', long_name='dead stem N storage', & - ptr_patch=this%deadstemn_storage_patch) + ptr_patch=this%deadstemn_storage_patch, default='inactive') this%deadstemn_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='DEADSTEMN_XFER', units='gN/m^2', & avgflag='A', long_name='dead stem N transfer', & - ptr_patch=this%deadstemn_xfer_patch) + ptr_patch=this%deadstemn_xfer_patch, default='inactive') this%livecrootn_patch(begp:endp) = spval call hist_addfld1d (fname='LIVECROOTN', units='gN/m^2', & @@ -291,12 +291,12 @@ subroutine InitHistory(this, bounds) this%livecrootn_storage_patch(begp:endp) = spval call hist_addfld1d (fname='LIVECROOTN_STORAGE', units='gN/m^2', & avgflag='A', long_name='live coarse root N storage', & - ptr_patch=this%livecrootn_storage_patch) + ptr_patch=this%livecrootn_storage_patch, default='inactive') this%livecrootn_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='LIVECROOTN_XFER', units='gN/m^2', & avgflag='A', long_name='live coarse root N transfer', & - ptr_patch=this%livecrootn_xfer_patch) + ptr_patch=this%livecrootn_xfer_patch, default='inactive') this%deadcrootn_patch(begp:endp) = spval call hist_addfld1d (fname='DEADCROOTN', units='gN/m^2', & @@ -306,12 +306,12 @@ subroutine InitHistory(this, bounds) this%deadcrootn_storage_patch(begp:endp) = spval call hist_addfld1d (fname='DEADCROOTN_STORAGE', units='gN/m^2', & avgflag='A', long_name='dead coarse root N storage', & - ptr_patch=this%deadcrootn_storage_patch) + ptr_patch=this%deadcrootn_storage_patch, default='inactive') this%deadcrootn_xfer_patch(begp:endp) = spval call hist_addfld1d (fname='DEADCROOTN_XFER', units='gN/m^2', & avgflag='A', long_name='dead coarse root N transfer', & - ptr_patch=this%deadcrootn_xfer_patch) + ptr_patch=this%deadcrootn_xfer_patch, default='inactive') this%retransn_patch(begp:endp) = spval call hist_addfld1d (fname='RETRANSN', units='gN/m^2', & @@ -326,7 +326,7 @@ subroutine InitHistory(this, bounds) this%ntrunc_patch(begp:endp) = spval call hist_addfld1d (fname='PFT_NTRUNC', units='gN/m^2', & avgflag='A', long_name='patch-level sink for N truncation', & - ptr_patch=this%ntrunc_patch) + ptr_patch=this%ntrunc_patch, default='inactive') this%dispvegn_patch(begp:endp) = spval call hist_addfld1d (fname='DISPVEGN', units='gN/m^2', & @@ -525,7 +525,9 @@ subroutine InitCold(this, bounds, & end subroutine InitCold !----------------------------------------------------------------------- - subroutine Restart ( this, bounds, ncid, flag ) + subroutine Restart ( this, bounds, ncid, flag, leafc_patch, & + leafc_storage_patch, frootc_patch, frootc_storage_patch, & + deadstemc_patch, filter_reseed_patch, num_reseed_patch ) ! ! !DESCRIPTION: ! Read/write restart data @@ -534,7 +536,8 @@ subroutine Restart ( this, bounds, ncid, flag ) use restUtilMod use ncdio_pio use clm_varctl , only : spinup_state, use_cndv - use clm_time_manager , only : get_nstep + use clm_time_manager , only : get_nstep, is_restart + use clm_varctl , only : MM_Nuptake_opt ! ! !ARGUMENTS: @@ -542,9 +545,16 @@ subroutine Restart ( this, bounds, ncid, flag ) type(bounds_type) , intent(in) :: bounds type(file_desc_t) , intent(inout) :: ncid character(len=*) , intent(in) :: flag !'read' or 'write' or 'define' + real(r8) , intent(in) :: leafc_patch(bounds%begp:) + real(r8) , intent(in) :: leafc_storage_patch(bounds%begp:) + real(r8) , intent(in) :: frootc_patch(bounds%begp:) + real(r8) , intent(in) :: frootc_storage_patch(bounds%begp:) + real(r8) , intent(in) :: deadstemc_patch(bounds%begp:) + integer , intent(in) :: filter_reseed_patch(:) + integer , intent(in) :: num_reseed_patch ! ! !LOCAL VARIABLES: - integer :: i,j,k,l,c + integer :: i, p, l logical :: readvar real(r8), pointer :: ptr1d(:) ! temp. pointers for slicing larger arrays character(len=128) :: varname ! temporary @@ -723,6 +733,108 @@ subroutine Restart ( this, bounds, ncid, flag ) endif end if + ! Reseed dead plants + if ( flag == 'read' .and. num_reseed_patch > 0 )then + if ( masterproc ) write(iulog, *) 'Reseed dead plants for CNVegNitrogenState' + do i = 1, num_reseed_patch + p = filter_reseed_patch(i) + + l = patch%landunit(p) + + if (patch%itype(p) == noveg) then + this%leafn_patch(p) = 0._r8 + this%leafn_storage_patch(p) = 0._r8 + if (MM_Nuptake_opt .eqv. .true.) then + this%frootn_patch(p) = 0._r8 + this%frootn_storage_patch(p) = 0._r8 + end if + else + this%leafn_patch(p) = leafc_patch(p) / pftcon%leafcn(patch%itype(p)) + this%leafn_storage_patch(p) = leafc_storage_patch(p) / pftcon%leafcn(patch%itype(p)) + if (MM_Nuptake_opt .eqv. .true.) then + this%frootn_patch(p) = frootc_patch(p) / pftcon%frootcn(patch%itype(p)) + this%frootn_storage_patch(p) = frootc_storage_patch(p) / pftcon%frootcn(patch%itype(p)) + end if + end if + + this%leafn_xfer_patch(p) = 0._r8 + + this%leafn_storage_xfer_acc_patch(p) = 0._r8 + this%storage_ndemand_patch(p) = 0._r8 + + if ( use_crop )then + this%grainn_patch(p) = 0._r8 + this%grainn_storage_patch(p) = 0._r8 + this%grainn_xfer_patch(p) = 0._r8 + this%cropseedn_deficit_patch(p) = 0._r8 + end if + if (MM_Nuptake_opt .eqv. .false.) then ! if not running in floating CN ratio option + this%frootn_patch(p) = 0._r8 + this%frootn_storage_patch(p) = 0._r8 + end if + this%frootn_xfer_patch(p) = 0._r8 + this%livestemn_patch(p) = 0._r8 + this%livestemn_storage_patch(p) = 0._r8 + this%livestemn_xfer_patch(p) = 0._r8 + + ! tree types need to be initialized with some stem mass so that + ! roughness length is not zero in canopy flux calculation + + if (pftcon%woody(patch%itype(p)) == 1._r8) then + this%deadstemn_patch(p) = deadstemc_patch(p) / pftcon%deadwdcn(patch%itype(p)) + else + this%deadstemn_patch(p) = 0._r8 + end if + + this%deadstemn_storage_patch(p) = 0._r8 + this%deadstemn_xfer_patch(p) = 0._r8 + this%livecrootn_patch(p) = 0._r8 + this%livecrootn_storage_patch(p) = 0._r8 + this%livecrootn_xfer_patch(p) = 0._r8 + this%deadcrootn_patch(p) = 0._r8 + this%deadcrootn_storage_patch(p) = 0._r8 + this%deadcrootn_xfer_patch(p) = 0._r8 + this%retransn_patch(p) = 0._r8 + this%npool_patch(p) = 0._r8 + this%ntrunc_patch(p) = 0._r8 + this%dispvegn_patch(p) = 0._r8 + this%storvegn_patch(p) = 0._r8 + this%totvegn_patch(p) = 0._r8 + this%totn_patch(p) = 0._r8 + + ! calculate totvegc explicitly so that it is available for the isotope + ! code on the first time step. + + this%totvegn_patch(p) = & + this%leafn_patch(p) + & + this%leafn_storage_patch(p) + & + this%leafn_xfer_patch(p) + & + this%frootn_patch(p) + & + this%frootn_storage_patch(p) + & + this%frootn_xfer_patch(p) + & + this%livestemn_patch(p) + & + this%livestemn_storage_patch(p) + & + this%livestemn_xfer_patch(p) + & + this%deadstemn_patch(p) + & + this%deadstemn_storage_patch(p) + & + this%deadstemn_xfer_patch(p) + & + this%livecrootn_patch(p) + & + this%livecrootn_storage_patch(p) + & + this%livecrootn_xfer_patch(p) + & + this%deadcrootn_patch(p) + & + this%deadcrootn_storage_patch(p) + & + this%deadcrootn_xfer_patch(p) + & + this%npool_patch(p) + + if ( use_crop )then + this%totvegn_patch(p) = & + this%totvegn_patch(p) + & + this%grainn_patch(p) + & + this%grainn_storage_patch(p) + & + this%grainn_xfer_patch(p) + end if + end do + end if end subroutine Restart diff --git a/src/biogeochem/CNVegStateType.F90 b/src/biogeochem/CNVegStateType.F90 index f0607aaae4..85d18431c9 100644 --- a/src/biogeochem/CNVegStateType.F90 +++ b/src/biogeochem/CNVegStateType.F90 @@ -321,7 +321,7 @@ subroutine InitHistory(this, bounds) ptr_col=this%nfire_col) this%farea_burned_col(begc:endc) = spval - call hist_addfld1d (fname='FAREA_BURNED', units='proportion', & + call hist_addfld1d (fname='FAREA_BURNED', units='proportion/sec', & avgflag='A', long_name='timestep fractional area burned', & ptr_col=this%farea_burned_col) @@ -669,23 +669,31 @@ subroutine initCold(this, bounds) end subroutine initCold !------------------------------------------------------------------------ - subroutine Restart(this, bounds, ncid, flag) + subroutine Restart(this, bounds, ncid, flag, cnveg_carbonstate, & + cnveg_nitrogenstate, filter_reseed_patch, num_reseed_patch) ! ! !USES: use shr_log_mod, only : errMsg => shr_log_errMsg use spmdMod , only : masterproc use abortutils , only : endrun + use CNVegNitrogenStateType, only: cnveg_nitrogenstate_type + use CNVegCarbonStateType , only: cnveg_carbonstate_type use restUtilMod use ncdio_pio + use pftconMod , only : pftcon ! ! !ARGUMENTS: class(cnveg_state_type) :: this type(bounds_type), intent(in) :: bounds type(file_desc_t), intent(inout) :: ncid character(len=*) , intent(in) :: flag + type(cnveg_nitrogenstate_type), intent(in) :: cnveg_nitrogenstate + type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate + integer , intent(out), optional :: filter_reseed_patch(:) + integer , intent(out), optional :: num_reseed_patch ! ! !LOCAL VARIABLES: - integer :: j,c,i ! indices + integer :: j,c,i,p ! indices logical :: readvar ! determine if variable is on initial file real(r8), pointer :: ptr2d(:,:) ! temp. pointers for slicing larger arrays real(r8), pointer :: ptr1d(:) ! temp. pointers for slicing larger arrays @@ -899,6 +907,41 @@ subroutine Restart(this, bounds, ncid, flag) dim1name='pft', long_name='', units='', & interpinic_flag='interp', readvar=readvar, data=this%grain_flag_patch) end if + if ( flag == 'read' .and. num_reseed_patch > 0 )then + if ( masterproc ) write(iulog, *) 'Reseed dead plants for CNVegState' + do i = 1, num_reseed_patch + p = filter_reseed_patch(i) + ! phenology variables + this%dormant_flag_patch(p) = 1._r8 + this%days_active_patch(p) = 0._r8 + this%onset_flag_patch(p) = 0._r8 + this%onset_counter_patch(p) = 0._r8 + this%onset_gddflag_patch(p) = 0._r8 + this%onset_fdd_patch(p) = 0._r8 + this%onset_gdd_patch(p) = 0._r8 + this%onset_swi_patch(p) = 0._r8 + this%offset_flag_patch(p) = 0._r8 + this%offset_counter_patch(p) = 0._r8 + this%offset_fdd_patch(p) = 0._r8 + this%offset_swi_patch(p) = 0._r8 + this%lgsf_patch(p) = 0._r8 + this%bglfr_patch(p) = 0._r8 + this%bgtr_patch(p) = 0._r8 + this%annavg_t2m_patch(p) = 280._r8 + this%tempavg_t2m_patch(p) = 0._r8 + this%grain_flag_patch(p) = 0._r8 + + this%c_allometry_patch(p) = 0._r8 + this%n_allometry_patch(p) = 0._r8 + this%tempsum_potential_gpp_patch(p) = 0._r8 + this%annsum_potential_gpp_patch(p) = 0._r8 + this%tempmax_retransn_patch(p) = 0._r8 + this%annmax_retransn_patch(p) = 0._r8 + this%downreg_patch(p) = 0._r8 + this%leafcn_offset_patch(p) = spval + this%plantCN_patch(p) = spval + end do + end if end subroutine Restart diff --git a/src/biogeochem/CNVegetationFacade.F90 b/src/biogeochem/CNVegetationFacade.F90 index bc586bc2f2..10c8164baa 100644 --- a/src/biogeochem/CNVegetationFacade.F90 +++ b/src/biogeochem/CNVegetationFacade.F90 @@ -13,7 +13,7 @@ module CNVegetationFacade ! then have an instance of VegBase, which depending on the run, can be either a CNVeg or ! EDVeg instance. ! - ! In addition, we probably want an implementation when running without CN or ED - i.e., + ! In addition, we probably want an implementation when running without CN or fates - i.e., ! an SPVeg inst. This would provide implementations for get_leafn_patch, ! get_downreg_patch, etc., so that we don't need to handle the non-cn case here (note ! that, currently, we return NaN for most of these getters, because these arrays are @@ -45,6 +45,7 @@ module CNVegetationFacade use perf_mod , only : t_startf, t_stopf use decompMod , only : bounds_type use clm_varctl , only : iulog, use_cn, use_cndv, use_c13, use_c14 + use abortutils , only : endrun use spmdMod , only : masterproc use clm_time_manager , only : get_curr_date, get_ref_date use clm_time_manager , only : get_nstep, is_end_curr_year, is_first_step @@ -97,7 +98,7 @@ module CNVegetationFacade ! !PUBLIC TYPES: type, public :: cn_vegetation_type - ! FIXME(bja, 2016-06) These need to be public for use when ED is + ! FIXME(bja, 2016-06) These need to be public for use when fates is ! turned on. Should either be moved out of here or create some ED ! version of the facade.... type(cnveg_state_type) :: cnveg_state_inst @@ -122,6 +123,9 @@ module CNVegetationFacade class(cnfire_method_type), allocatable :: cnfire_method type(dgvs_type) :: dgvs_inst + ! Control variables + logical, private :: reseed_dead_plants ! Flag to indicate if should reseed dead plants when starting up the model + ! TODO(wjs, 2016-02-19) Evaluate whether some other variables should be moved in ! here. Whether they should be moved in depends on how tightly they are tied in with ! the other CN Vegetation stuff. A question to ask is: Is this module used when @@ -168,8 +172,11 @@ module CNVegetationFacade procedure, public :: get_annsum_npp_patch ! Get patch-level annual sum NPP array procedure, public :: get_agnpp_patch ! Get patch-level aboveground NPP array procedure, public :: get_bgnpp_patch ! Get patch-level belowground NPP array - procedure, public :: get_froot_carbon_patch ! Get patch-level fine root carbon array - procedure, public :: get_croot_carbon_patch ! Get patch-level coarse root carbon array + procedure, public :: get_froot_carbon_patch ! Get patch-level fine root carbon array + procedure, public :: get_croot_carbon_patch ! Get patch-level coarse root carbon array + procedure, public :: get_totvegc_col ! Get column-level total vegetation carbon array + + procedure, private :: CNReadNML ! Read in the CN general namelist end type cn_vegetation_type character(len=*), parameter, private :: sourcefile = & @@ -207,14 +214,18 @@ subroutine Init(this, bounds, NLFilename) call this%cnveg_state_inst%Init(bounds) if (use_cn) then - call this%cnveg_carbonstate_inst%Init(bounds, carbon_type='c12', ratio=1._r8) + + ! Read in the general CN namelist + call this%CNReadNML( NLFilename ) ! MUST be called first as passes down control information to others + + call this%cnveg_carbonstate_inst%Init(bounds, carbon_type='c12', ratio=1._r8, NLFilename=NLFilename) if (use_c13) then call this%c13_cnveg_carbonstate_inst%Init(bounds, carbon_type='c13', ratio=c13ratio, & - c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) + NLFilename=NLFilename, c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) end if if (use_c14) then call this%c14_cnveg_carbonstate_inst%Init(bounds, carbon_type='c14', ratio=c14ratio, & - c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) + NLFilename=NLFilename, c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) end if call this%cnveg_carbonflux_inst%Init(bounds, carbon_type='c12') if (use_c13) then @@ -223,12 +234,12 @@ subroutine Init(this, bounds, NLFilename) if (use_c14) then call this%c14_cnveg_carbonflux_inst%Init(bounds, carbon_type='c14') end if - call this%cnveg_nitrogenstate_inst%Init(bounds, & - this%cnveg_carbonstate_inst%leafc_patch(begp:endp), & - this%cnveg_carbonstate_inst%leafc_storage_patch(begp:endp), & - this%cnveg_carbonstate_inst%frootc_patch(begp:endp), & + call this%cnveg_nitrogenstate_inst%Init(bounds, & + this%cnveg_carbonstate_inst%leafc_patch(begp:endp), & + this%cnveg_carbonstate_inst%leafc_storage_patch(begp:endp), & + this%cnveg_carbonstate_inst%frootc_patch(begp:endp), & this%cnveg_carbonstate_inst%frootc_storage_patch(begp:endp), & - this%cnveg_carbonstate_inst%deadstemc_patch(begp:endp)) + this%cnveg_carbonstate_inst%deadstemc_patch(begp:endp) ) call this%cnveg_nitrogenflux_inst%Init(bounds) call this%c_products_inst%Init(bounds, species_non_isotope_type('C')) @@ -253,6 +264,67 @@ subroutine Init(this, bounds, NLFilename) end subroutine Init + !----------------------------------------------------------------------- + subroutine CNReadNML( this, NLFilename ) + ! + ! !DESCRIPTION: + ! Read in the general CN control namelist + ! + ! !USES: + use fileutils , only : getavu, relavu, opnfil + use shr_nl_mod , only : shr_nl_find_group_name + use spmdMod , only : masterproc, mpicom + use shr_mpi_mod , only : shr_mpi_bcast + use clm_varctl , only : iulog + ! + ! !ARGUMENTS: + class(cn_vegetation_type), intent(inout) :: this + character(len=*) , intent(in) :: NLFilename ! Namelist filename + ! + ! !LOCAL VARIABLES: + integer :: ierr ! error code + integer :: unitn ! unit for namelist file + + character(len=*), parameter :: subname = 'CNReadNML' + character(len=*), parameter :: nmlname = 'cn_general' ! MUST match what is in namelist below + !----------------------------------------------------------------------- + logical :: reseed_dead_plants + namelist /cn_general/ reseed_dead_plants + + reseed_dead_plants = this%reseed_dead_plants + + if (masterproc) then + unitn = getavu() + write(iulog,*) 'Read in '//nmlname//' namelist' + call opnfil (NLFilename, unitn, 'F') + call shr_nl_find_group_name(unitn, nmlname, status=ierr) + if (ierr == 0) then + read(unitn, nml=cn_general, iostat=ierr) ! Namelist name here MUST be the same as in nmlname above! + if (ierr /= 0) then + call endrun(msg="ERROR reading "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + else + call endrun(msg="ERROR could NOT find "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + call relavu( unitn ) + end if + + call shr_mpi_bcast (reseed_dead_plants , mpicom) + + this%reseed_dead_plants = reseed_dead_plants + + if (masterproc) then + write(iulog,*) ' ' + write(iulog,*) nmlname//' settings:' + write(iulog,nml=cn_general) ! Name here MUST be the same as in nmlname above! + write(iulog,*) ' ' + end if + + !----------------------------------------------------------------------- + + end subroutine CNReadNML + + !----------------------------------------------------------------------- subroutine InitAccBuffer(this, bounds) ! @@ -352,22 +424,32 @@ subroutine Restart(this, bounds, ncid, flag) type(bounds_type), intent(in) :: bounds type(file_desc_t), intent(inout) :: ncid character(len=*) , intent(in) :: flag + integer :: reseed_patch(bounds%endp-bounds%begp+1) + integer :: num_reseed_patch ! ! !LOCAL VARIABLES: + integer :: begp, endp + character(len=*), parameter :: subname = 'Restart' !----------------------------------------------------------------------- if (use_cn) then - call this%cnveg_state_inst%restart(bounds, ncid, flag=flag) - call this%cnveg_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c12') + begp = bounds%begp + endp = bounds%endp + call this%cnveg_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c12', & + reseed_dead_plants=this%reseed_dead_plants, filter_reseed_patch=reseed_patch, & + num_reseed_patch=num_reseed_patch ) + if ( flag /= 'read' .and. num_reseed_patch /= 0 )then + call endrun(msg="ERROR num_reseed should be zero and is not"//errmsg(sourcefile, __LINE__)) + end if if (use_c13) then call this%c13_cnveg_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c13', & - c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) + reseed_dead_plants=this%reseed_dead_plants, c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) end if if (use_c14) then call this%c14_cnveg_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c14', & - c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) + reseed_dead_plants=this%reseed_dead_plants, c12_cnveg_carbonstate_inst=this%cnveg_carbonstate_inst) end if call this%cnveg_carbonflux_inst%restart(bounds, ncid, flag=flag, carbon_type='c12') @@ -378,8 +460,18 @@ subroutine Restart(this, bounds, ncid, flag) call this%c14_cnveg_carbonflux_inst%restart(bounds, ncid, flag=flag, carbon_type='c14') end if - call this%cnveg_nitrogenstate_inst%restart(bounds, ncid, flag=flag) + call this%cnveg_nitrogenstate_inst%restart(bounds, ncid, flag=flag, & + leafc_patch=this%cnveg_carbonstate_inst%leafc_patch(begp:endp), & + leafc_storage_patch=this%cnveg_carbonstate_inst%leafc_storage_patch(begp:endp), & + frootc_patch=this%cnveg_carbonstate_inst%frootc_patch(begp:endp), & + frootc_storage_patch=this%cnveg_carbonstate_inst%frootc_storage_patch(begp:endp), & + deadstemc_patch=this%cnveg_carbonstate_inst%deadstemc_patch(begp:endp), & + filter_reseed_patch=reseed_patch, num_reseed_patch=num_reseed_patch) call this%cnveg_nitrogenflux_inst%restart(bounds, ncid, flag=flag) + call this%cnveg_state_inst%restart(bounds, ncid, flag=flag, & + cnveg_carbonstate=this%cnveg_carbonstate_inst, & + cnveg_nitrogenstate=this%cnveg_nitrogenstate_inst, & + filter_reseed_patch=reseed_patch, num_reseed_patch=num_reseed_patch) call this%c_products_inst%restart(bounds, ncid, flag) if (use_c13) then @@ -523,7 +615,7 @@ end subroutine UpdateSubgridWeights !----------------------------------------------------------------------- - subroutine DynamicAreaConservation(this, bounds, & + subroutine DynamicAreaConservation(this, bounds, clump_index, & num_soilp_with_inactive, filter_soilp_with_inactive, & num_soilc_with_inactive, filter_soilc_with_inactive, & prior_weights, patch_state_updater, column_state_updater, & @@ -545,6 +637,11 @@ subroutine DynamicAreaConservation(this, bounds, & ! !ARGUMENTS: class(cn_vegetation_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer , intent(in) :: clump_index + integer , intent(in) :: num_soilp_with_inactive ! number of points in filter_soilp_with_inactive integer , intent(in) :: filter_soilp_with_inactive(:) ! soil patch filter that includes inactive points integer , intent(in) :: num_soilc_with_inactive ! number of points in filter_soilc_with_inactive @@ -611,7 +708,7 @@ subroutine DynamicAreaConservation(this, bounds, & call t_stopf('CNUpdateDynPatch') call t_startf('dyn_cnbal_col') - call dyn_cnbal_col(bounds, column_state_updater, & + call dyn_cnbal_col(bounds, clump_index, column_state_updater, & soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst, & ch4_inst) @@ -1308,4 +1405,32 @@ function get_croot_carbon_patch(this, bounds, tlai) result(croot_carbon_patch) end function get_croot_carbon_patch + !----------------------------------------------------------------------- + function get_totvegc_col(this, bounds) result(totvegc_col) + ! + ! !DESCRIPTION: + ! Get column-level total vegetation carbon array + ! + ! !USES: + ! + ! !ARGUMENTS: + class(cn_vegetation_type), intent(in) :: this + type(bounds_type), intent(in) :: bounds + real(r8) :: totvegc_col(bounds%begc:bounds%endc) ! function result: (gC/m2) + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'get_totvegc_col' + !----------------------------------------------------------------------- + + if (use_cn) then + totvegc_col(bounds%begc:bounds%endc) = & + this%cnveg_carbonstate_inst%totvegc_col(bounds%begc:bounds%endc) + else + totvegc_col(bounds%begc:bounds%endc) = nan + end if + + end function get_totvegc_col + + end module CNVegetationFacade diff --git a/src/biogeochem/CropType.F90 b/src/biogeochem/CropType.F90 index 29dd796290..eaed486bc5 100644 --- a/src/biogeochem/CropType.F90 +++ b/src/biogeochem/CropType.F90 @@ -154,6 +154,13 @@ subroutine ReadNML(this, NLFilename ) this%baset_mapping = baset_mapping this%baset_latvary_intercept = baset_latvary_intercept this%baset_latvary_slope = baset_latvary_slope + if ( trim(this%baset_mapping) == baset_map_constant ) then + if ( masterproc ) write(iulog,*) 'baset mapping for ALL crops are constant' + else if ( trim(this%baset_mapping) == baset_map_latvary ) then + if ( masterproc ) write(iulog,*) 'baset mapping for crops vary with latitude' + else + call endrun(msg="Bad value for baset_mapping in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if if (masterproc) then write(iulog,*) ' ' @@ -233,10 +240,12 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='crop phenology phase', & ptr_patch=this%cphase_patch, default='active') - this%latbaset_patch(begp:endp) = spval - call hist_addfld1d (fname='LATBASET', units='degree C', & - avgflag='A', long_name='latitude vary base temperature for gddplant', & - ptr_patch=this%latbaset_patch) + if ( (trim(this%baset_mapping) == baset_map_latvary) )then + this%latbaset_patch(begp:endp) = spval + call hist_addfld1d (fname='LATBASET', units='degree C', & + avgflag='A', long_name='latitude vary base temperature for gddplant', & + ptr_patch=this%latbaset_patch, default='inactive') + end if end subroutine InitHistory @@ -248,6 +257,7 @@ subroutine InitCold(this, bounds) use clm_instur, only : fert_cft use pftconMod , only : pftcon use GridcellType , only : grc + use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) ! !ARGUMENTS: class(crop_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds @@ -258,6 +268,7 @@ subroutine InitCold(this, bounds) character(len=*), parameter :: subname = 'InitCold' !----------------------------------------------------------------------- +!DLL - added wheat & sugarcane restrictions to base T vary by lat do p= bounds%begp,bounds%endp g = patch%gridcell(p) ivt = patch%itype(p) @@ -271,7 +282,12 @@ subroutine InitCold(this, bounds) else this%latbaset_patch(p)=pftcon%baset(ivt) end if + if ( trim(this%baset_mapping) == baset_map_constant ) then + this%latbaset_patch(p) = nan + end if end do +!DLL -- end of mods + if (use_crop) then do p= bounds%begp,bounds%endp g = patch%gridcell(p) @@ -511,11 +527,14 @@ subroutine CropUpdateAccVars(this, bounds, t_ref2m_patch, t_soisno_col) use shr_const_mod , only : SHR_CONST_CDAY, SHR_CONST_TKFRZ use clm_time_manager , only : get_step_size, get_nstep use clm_varpar , only : nlevsno, nlevgrnd - use pftconMod , only : nwwheat, nirrig_wwheat, pftcon + use pftconMod , only : nswheat, nirrig_swheat, pftcon + use pftconMod , only : nwwheat, nirrig_wwheat + use pftconMod , only : nsugarcane, nirrig_sugarcane use ColumnType , only : col use PatchType , only : patch ! ! !ARGUMENTS: + implicit none class(crop_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds real(r8) , intent(in) :: t_ref2m_patch( bounds%begp:) @@ -553,16 +572,23 @@ subroutine CropUpdateAccVars(this, bounds, t_ref2m_patch, t_soisno_col) ! Accumulate and extract GDDPLANT + call extract_accum_field ('GDDPLANT', rbufslp, nstep) + do p = begp,endp + rbufslp(p) = max(0.,this%gddplant_patch(p)-rbufslp(p)) + end do + call update_accum_field ('GDDPLANT', rbufslp, nstep) do p = begp,endp if (this%croplive_patch(p)) then ! relative to planting date ivt = patch%itype(p) - if ( trim(this%baset_mapping) == baset_map_constant ) then + if ( (trim(this%baset_mapping) == baset_map_latvary) .and. & + ((ivt == nswheat) .or. (ivt == nirrig_swheat) .or. & + (ivt == nsugarcane) .or. (ivt == nirrig_sugarcane)) ) then rbufslp(p) = max(0._r8, min(pftcon%mxtmp(ivt), & - t_ref2m_patch(p)-(SHR_CONST_TKFRZ + pftcon%baset(ivt)))) & + t_ref2m_patch(p)-(SHR_CONST_TKFRZ + this%latbaset_patch(p)))) & * dtime/SHR_CONST_CDAY else rbufslp(p) = max(0._r8, min(pftcon%mxtmp(ivt), & - t_ref2m_patch(p)-(SHR_CONST_TKFRZ + this%latbaset_patch(p)))) & + t_ref2m_patch(p)-(SHR_CONST_TKFRZ + pftcon%baset(ivt)))) & * dtime/SHR_CONST_CDAY end if if (ivt == nwwheat .or. ivt == nirrig_wwheat) then diff --git a/src/biogeochem/DryDepVelocity.F90 b/src/biogeochem/DryDepVelocity.F90 index f20ba9cae3..603e9d24c4 100644 --- a/src/biogeochem/DryDepVelocity.F90 +++ b/src/biogeochem/DryDepVelocity.F90 @@ -48,9 +48,10 @@ Module DryDepVelocity ! bugs in rlu and rcl calculations. Added ! no vegetation removal for CO. See README for details and ! Val Martin et al., 2014 GRL for major corrections + ! Modified: Louisa Emmons -- 30 November 2017 + ! Corrected the equation calculating stomatal resistance from rssun and rssha, + ! and removed factor that scaled Rs to match observations ! - !********* !!! IMPORTANT !!! ************ - ! STOMATAL RESISTANCE IS OPTIMIZED TO MATCH UP OBSERVATIONS !----------------------------------------------------------------------- use shr_log_mod , only : errMsg => shr_log_errMsg @@ -81,12 +82,14 @@ Module DryDepVelocity ! type, public :: drydepvel_type - real(r8), pointer, public :: velocity_patch (:,:) ! Dry Deposition Velocity + real(r8), pointer, public :: velocity_patch (:,:) ! Dry Deposition Velocity + real(r8), pointer, private :: rs_drydep_patch (:) ! Stomatal resistance associated with dry deposition velocity for Ozone contains procedure , public :: Init procedure , private :: InitAllocate + procedure , private :: InitHistory end type drydepvel_type !----------------------------------------------------------------------- @@ -103,6 +106,7 @@ subroutine Init(this, bounds) type(bounds_type), intent(in) :: bounds call this%InitAllocate(bounds) + call this%InitHistory(bounds) end subroutine Init @@ -126,10 +130,53 @@ subroutine InitAllocate(this, bounds) ! Dry Deposition Velocity if ( n_drydep > 0 .and. drydep_method == DD_XLND )then allocate(this%velocity_patch(begp:endp, n_drydep)); this%velocity_patch(:,:) = nan + allocate(this%rs_drydep_patch(begp:endp)) ; this%rs_drydep_patch(:) = nan end if end subroutine InitAllocate + !----------------------------------------------------------------------- + subroutine InitHistory(this, bounds) + ! + ! !DESCRIPTION: + ! Initialize history output fields for dry deposition diagnositics + ! + ! !USES + use clm_varcon , only : spval + use histFileMod , only : hist_addfld1d + use seq_drydep_mod , only : mapping + ! + ! !ARGUMENTS: + class(drydepvel_type) :: this + type(bounds_type), intent(in) :: bounds + real(r8), pointer :: ptr_1d(:) ! pointer to 1d patch array + ! + ! !LOCAL VARIABLES + integer :: ispec + integer :: begp, endp + !--------------------------------------------------------------------- + + begp = bounds%begp; endp = bounds%endp + + if ( n_drydep == 0 .or. drydep_method /= DD_XLND ) return + + do ispec=1,n_drydep + if(mapping(ispec) <= 0) cycle + + this%velocity_patch(begp:endp,ispec)= spval + ptr_1d => this%velocity_patch(begp:endp,ispec) + call hist_addfld1d ( fname='DRYDEPV_'//trim(drydep_list(ispec)), units='cm/sec', & + avgflag='A', long_name='Dry Deposition Velocity', & + ptr_patch=ptr_1d, default='inactive' ) + end do + + this%rs_drydep_patch(begp:endp)= spval + call hist_addfld1d ( fname='RS_DRYDEP_O3', units='s/m', & + avgflag='A', long_name='Stomatal Resistance Associated with Ozone Dry Deposition Velocity', & + ptr_patch=this%rs_drydep_patch, default='inactive' ) + + end subroutine InitHistory + !----------------------------------------------------------------------- subroutine depvel_compute( bounds, & atm2lnd_inst, canopystate_inst, waterstate_inst, frictionvel_inst, & @@ -142,7 +189,7 @@ subroutine depvel_compute( bounds, & use shr_const_mod , only : tmelt => shr_const_tkfrz use seq_drydep_mod , only : seq_drydep_setHCoeff, mapping, drat, foxd use seq_drydep_mod , only : rcls, h2_a, h2_b, h2_c, ri, rac, rclo, rlu, rgss, rgso - use landunit_varcon, only : istsoil, istice, istice_mec, istdlak, istwet + use landunit_varcon, only : istsoil, istice_mec, istdlak, istwet use clm_varctl , only : iulog use pftconMod , only : noveg, ndllf_evr_tmp_tree, ndllf_evr_brl_tree use pftconMod , only : ndllf_dcd_brl_tree, nbrdlf_evr_trp_tree @@ -152,6 +199,8 @@ subroutine depvel_compute( bounds, & use pftconMod , only : nbrdlf_dcd_brl_shrub,nc3_arctic_grass use pftconMod , only : nc3_nonarctic_grass, nc4_grass, nc3crop use pftconMod , only : nc3irrig, npcropmin, npcropmax + use clm_varcon , only : spval + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -177,7 +226,6 @@ subroutine depvel_compute( bounds, & real(r8) :: pg ! surface pressure real(r8) :: tc ! temperature in celsius - real(r8) :: rs ! constant for calculating rsmx real(r8) :: es ! saturation vapor pressur real(r8) :: ws ! saturation mixing ratio real(r8) :: rmx ! resistance by vegetation @@ -197,7 +245,6 @@ subroutine depvel_compute( bounds, & !mvm 11/30/2013 real(r8) :: rlu_lai ! constant to calculate rlu over bulk canopy - real(r8) :: rs_factor ! constant to optimize stomatal resistance logical :: has_dew logical :: has_rain @@ -209,6 +256,7 @@ subroutine depvel_compute( bounds, & real(r8), dimension(n_drydep) :: rlux !vegetative resistance (upper canopy) real(r8), dimension(n_drydep) :: rgsx !gournd resistance real(r8), dimension(n_drydep) :: heff + real(r8) :: rs ! stomatal resistance associated with dry deposition velocity (s/m) real(r8) :: rc !combined surface resistance real(r8) :: cts !correction to flu rcl and rgs for frost real(r8) :: rlux_o3 !to calculate O3 leaf resistance in dew/rain conditions @@ -251,7 +299,8 @@ subroutine depvel_compute( bounds, & mlaidiff => canopystate_inst%mlaidiff_patch , & ! Input: [real(r8) (:) ] difference in lai between month one and month two annlai => canopystate_inst%annlai_patch , & ! Input: [real(r8) (:,:) ] 12 months of monthly lai from input data set - velocity => drydepvel_inst%velocity_patch & ! Output: [real(r8) (:,:) ] cm/sec + velocity => drydepvel_inst%velocity_patch , & ! Output: [real(r8) (:,:) ] cm/sec + rs_drydep => drydepvel_inst%rs_drydep_patch & ! Output: [real(r8) (:) ] stomatal resistance associated with Ozone dry deposition velocity (s/m) ) !_________________________________________________________________ @@ -326,7 +375,7 @@ subroutine depvel_compute( bounds, & index_season = -1 if ( lun%itype(l) /= istsoil )then - if ( lun%itype(l) == istice .or. lun%itype(l) == istice_mec ) then + if ( lun%itype(l) == istice_mec ) then wesveg = 8 index_season = 4 elseif ( lun%itype(l) == istdlak ) then @@ -436,7 +485,7 @@ subroutine depvel_compute( bounds, & ! no deposition on snow, ice, desert, and water !------------------------------------------------------------------------------------- if( wesveg == 1 .or. wesveg == 7 .or. wesveg == 8 .or. index_season == 4 ) then - rgsx(ispec) = 1.e36_r8 + rgsx(ispec) = spval else var_soilw = max( .1_r8,min( soilw,.3_r8 ) ) if( wesveg == 3 ) then @@ -454,25 +503,24 @@ subroutine depvel_compute( bounds, & !------------------------------------------------------------------------------------- no_dep: if( wesveg == 7 .or. elai(pi).le.0_r8 ) then !mvm 11/26/2013 - rclx(ispec)=1.e36_r8 - rsmx(ispec)=1.e36_r8 - rlux(ispec)=1.e36_r8 + rclx(ispec) = spval + rsmx(ispec) = spval + rlux(ispec) = spval + rs = spval else !Stomatal resistance - !MVM: adjusted rs to calculate stomata conductance over bulk canopy (CLM report pag 161) ! fvitt -- at midnight rssun and/or rssha can be zero in some places which sets rs to zero ! --- this fix prevents divide by zero error (when rsmx is zero) if (rssun(pi)>0._r8 .and. rssun(pi)<1.e30 .and. rssha(pi)>0._r8 .and. rssha(pi)<1.e30 ) then - rs=(fsun(pi)*rssun(pi)/elai(pi))+((rssha(pi)/elai(pi))*(1.-fsun(pi))) + !LKE: corrected rs to add rssun and rssha in parallel (11/30/2017) + rs=1._r8/(fsun(pi)*elai(pi)/rssun(pi) + (1.-fsun(pi))*elai(pi)/rssha(pi)) else - rs=1.e36_r8 + rs=spval endif - !MVM: rs_factor=0.2 to match up Rs observations (Padro et al, 1996) - rs_factor = 0.2_r8 - rsmx(ispec) = rs_factor*rs*drat(ispec)+rmx + rsmx(ispec) = rs*drat(ispec)+rmx ! Leaf resistance !MVM: adjusted rlu by LAI to get leaf resistance over bulk canopy (gao and wesely, 1995) @@ -489,9 +537,9 @@ subroutine depvel_compute( bounds, & !small in vegetation [Mueller and Brasseur, 1995]. !------------------------------------ if( ispec == index_co ) then - rclx(ispec)=1.e36_r8 - rsmx(ispec)=1.e36_r8 - rlux(ispec)=1.e36_r8 + rclx(ispec) = spval + rsmx(ispec) = spval + rlux(ispec) = spval endif !-------------------------------------------- @@ -506,6 +554,9 @@ subroutine depvel_compute( bounds, & end if endif no_dep + if ( ispec == index_o3 )then + rs_drydep(pi) = rs + end if end do species_loop1 @@ -576,7 +627,7 @@ subroutine depvel_compute( bounds, & end if !mvm 11/30/2013: special case for CO if( ispec.eq.index_co ) then - rlux(ispec)=1.e36_r8 + rlux(ispec) = spval endif end do species_loop2 endif non_freezing @@ -611,6 +662,8 @@ subroutine depvel_compute( bounds, & velocity(pi,ispec) = 0.2_r8 case ( 'CB1', 'CB2', 'OC1', 'OC2', 'SOAM', 'SOAI', 'SOAT', 'SOAB', 'SOAX' ) velocity(pi,ispec) = 0.10_r8 + case ( 'SO2' ) + velocity(pi,ispec) = (1._r8/(ram1(pi)+rb1(pi)+rc))*200._r8 case default velocity(pi,ispec) = (1._r8/(ram1(pi)+rb1(pi)+rc))*100._r8 end select diff --git a/src/biogeochem/EDBGCDynMod.F90 b/src/biogeochem/EDBGCDynMod.F90 index aa57435c52..107cdf91c0 100644 --- a/src/biogeochem/EDBGCDynMod.F90 +++ b/src/biogeochem/EDBGCDynMod.F90 @@ -1,13 +1,15 @@ module EDBGCDynMod -! This module creates a pathway to call the belowground biogeochemistry code as driven by the ED vegetation model +! This module creates a pathway to call the belowground biogeochemistry code as driven by the fates vegetation model ! but bypassing the aboveground CN vegetation code. It is modeled after the CNDriverMod in its call sequence and ! functionality. use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : use_c13, use_c14, use_ed + use clm_varctl , only : use_c13, use_c14, use_fates use decompMod , only : bounds_type use perf_mod , only : t_startf, t_stopf + use shr_log_mod , only : errMsg => shr_log_errMsg + use abortutils , only : endrun use clm_varctl , only : use_century_decomp, use_nitrif_denitrif use CNVegCarbonStateType , only : cnveg_carbonstate_type use CNVegCarbonFluxType , only : cnveg_carbonflux_type @@ -16,7 +18,6 @@ module EDBGCDynMod use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type use SoilBiogeochemNitrogenFluxType , only : soilbiogeochem_nitrogenflux_type - use EDCLMLinkMod , only : ed_clm_type use CanopyStateType , only : canopystate_type use SoilStateType , only : soilstate_type use SoilHydrologyType , only : soilhydrology_type @@ -26,12 +27,15 @@ module EDBGCDynMod use atm2lndType , only : atm2lnd_type use SoilStateType , only : soilstate_type use ch4Mod , only : ch4_type - use EDtypesMod , only : ed_site_type + ! public :: EDBGCDynInit ! BGC dynamics: initialization public :: EDBGCDyn ! BGC Dynamics public :: EDBGCDynSummary ! BGC dynamics: summary + character(len=*), parameter, private :: sourcefile = & + __FILE__ + contains @@ -39,7 +43,6 @@ module EDBGCDynMod subroutine EDBGCDyn(bounds, & num_soilc, filter_soilc, num_soilp, filter_soilp, num_pcropp, filter_pcropp, doalb, & cnveg_carbonflux_inst, cnveg_carbonstate_inst, & - ed_clm_inst, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & soilbiogeochem_state_inst, & soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & @@ -90,7 +93,6 @@ subroutine EDBGCDyn(bounds, & logical , intent(in) :: doalb ! true = surface albedo calculation time step type(cnveg_carbonflux_type) , intent(inout) :: cnveg_carbonflux_inst type(cnveg_carbonstate_type) , intent(inout) :: cnveg_carbonstate_inst - type(ed_clm_type) , intent(inout) :: ed_clm_inst type(soilbiogeochem_state_type) , intent(inout) :: soilbiogeochem_state_inst type(soilbiogeochem_carbonflux_type) , intent(inout) :: soilbiogeochem_carbonflux_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst @@ -265,7 +267,7 @@ subroutine EDBGCDynSummary(bounds, num_soilc, filter_soilc, num_soilp, filter_so c13_soilbiogeochem_carbonflux_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonflux_inst, c14_soilbiogeochem_carbonstate_inst, & soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & - ed_clm_inst, sites, nsites, fcolumn) + clm_fates, nc) ! ! !DESCRIPTION: ! Call to all CN and SoilBiogeochem summary routines @@ -275,6 +277,7 @@ subroutine EDBGCDynSummary(bounds, num_soilc, filter_soilc, num_soilp, filter_so use clm_varpar , only: ndecomp_cascade_transitions use CNPrecisionControlMod , only: CNPrecisionControl use SoilBiogeochemPrecisionControlMod , only: SoilBiogeochemPrecisionControl + use CLMFatesInterfaceMod , only: hlm_fates_interface_type ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -290,10 +293,8 @@ subroutine EDBGCDynSummary(bounds, num_soilc, filter_soilc, num_soilp, filter_so type(soilbiogeochem_carbonstate_type) , intent(inout) :: c14_soilbiogeochem_carbonstate_inst type(soilbiogeochem_nitrogenflux_type) , intent(inout) :: soilbiogeochem_nitrogenflux_inst type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst - type(ed_clm_type) , intent(inout) :: ed_clm_inst - type(ed_site_type) , intent(inout), target :: sites(nsites) - integer , intent(in) :: nsites - integer , intent(in) :: fcolumn(nsites) + type(hlm_fates_interface_type) , intent(inout) :: clm_fates + integer , intent(in) :: nc ! thread index ! ! !LOCAL VARIABLES: integer :: begc,endc @@ -340,28 +341,20 @@ subroutine EDBGCDynSummary(bounds, num_soilc, filter_soilc, num_soilp, filter_so end if ! call soilbiogeochem_nitrogenflux_inst%Summary(bounds, num_soilc, filter_soilc) - ! ---------------------------------------------- - ! ed veg carbon state and flux summary - ! ---------------------------------------------- - - call ed_clm_inst%SummarizeNetFluxes(bounds, num_soilc, filter_soilc, & - nsites, sites(:), fcolumn(:), & - soilbiogeochem_carbonflux_inst, & - soilbiogeochem_carbonstate_inst) + ! ----------------------------------------------------------------------------------- + ! fates veg carbon state and flux summary, Nitrogen (TBD) and Balance Checks + ! ----------------------------------------------------------------------------------- ! ---------------------------------------------- - ! ed veg nitrogen flux summary + ! fates veg nitrogen flux summary ! ---------------------------------------------- - - ! TBD... - ! ---------------------------------------------- - ! calculate balance checks on entire carbon cycle (ED + BGC) + ! calculate balance checks on entire carbon cycle (FATES + BGC) ! ---------------------------------------------- - call ed_clm_inst%ED_BGC_Carbon_Balancecheck(bounds, num_soilc, filter_soilc, & - soilbiogeochem_carbonflux_inst) - + call clm_fates%wrap_bgc_summary(nc, soilbiogeochem_carbonflux_inst, & + soilbiogeochem_carbonstate_inst) + call t_stopf('BGCsum') end subroutine EDBGCDynSummary diff --git a/src/biogeochem/FireEmisFactorsMod.F90 b/src/biogeochem/FireEmisFactorsMod.F90 index 04768040a0..7aef11ffc3 100644 --- a/src/biogeochem/FireEmisFactorsMod.F90 +++ b/src/biogeochem/FireEmisFactorsMod.F90 @@ -51,9 +51,11 @@ subroutine fire_emis_factors_get( comp_name, factors, molecwght ) ! !DESCRIPTION: ! Method for getting FireEmis information for a named compound ! +! !USES: + use pftconMod , only : nc3crop ! !ARGUMENTS: character(len=*),intent(in) :: comp_name ! FireEmis compound name - real(r8), intent(out) :: factors(npfts) ! vegitation type factors for the compound of intrest + real(r8), intent(out) :: factors(:) ! vegetation type factors for the compound of interest real(r8), intent(out) :: molecwght ! molecular weight of the compound of intrest ! !EOP @@ -71,7 +73,10 @@ subroutine fire_emis_factors_get( comp_name, factors, molecwght ) call endrun(errmes) endif - factors(:) = comp_factors_table( ndx )%eff(:) + factors(:npfts) = comp_factors_table( ndx )%eff(:npfts) + if ( size(factors) > npfts )then + factors(npfts+1:) = comp_factors_table( ndx )%eff(nc3crop) + end if molecwght = comp_factors_table( ndx )%wght end subroutine fire_emis_factors_get @@ -91,6 +96,7 @@ subroutine fire_emis_factors_init( filename ) use ncdio_pio, only : ncd_pio_openfile,ncd_inqdlen use pio, only : pio_inq_varid,pio_get_var,file_desc_t,pio_closefile use fileutils , only : getfil + use clm_varpar , only : mxpft ! ! !ARGUMENTS: character(len=*),intent(in) :: filename ! FireEmis factors input file @@ -121,6 +127,9 @@ subroutine fire_emis_factors_init( filename ) call ncd_inqdlen( ncid, dimid, n_pfts, name='PFT_Num') npfts = n_pfts + if ( npfts /= mxpft .and. npfts /= 16 )then + call endrun('Number of PFTs on fire emissions file is NOT correct. Its neither the total number of PFTS nor 16') + end if ierr = pio_inq_varid(ncid,'Comp_EF', comp_ef_vid) ierr = pio_inq_varid(ncid,'Comp_Name',comp_name_vid) @@ -137,7 +146,7 @@ subroutine fire_emis_factors_init( filename ) call bld_hash_table_indices( comp_names ) do i=1,n_comps start=(/i,1/) - count=(/1,16/) + count=(/1,npfts/) ierr = pio_get_var( ncid, comp_ef_vid, start, count, comp_factors ) call enter_hash_data( trim(comp_names(i)), comp_factors, comp_molecwghts(i) ) diff --git a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 index 85b79b5b39..f404ac9611 100644 --- a/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 +++ b/src/biogeochem/NutrientCompetitionFlexibleCNMod.F90 @@ -25,6 +25,7 @@ module NutrientCompetitionFlexibleCNMod use PatchType , only : patch use NutrientCompetitionMethodMod, only : nutrient_competition_method_type use NutrientCompetitionMethodMod, only : params_inst + use clm_varctl , only : iulog ! implicit none private @@ -1358,6 +1359,8 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & 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) (:) ] + livestemn => cnveg_nitrogenstate_inst%livestemn_patch , & ! Input: [real(r8) (:) ] (gN/m2) livestem N + frootn => cnveg_nitrogenstate_inst%frootn_patch , & ! Input: [real(r8) (:) ] (gN/m2) fine root N sminn_vr => soilbiogeochem_nitrogenstate_inst%sminn_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral N btran => energyflux_inst%btran_patch , & ! Input: [real(r8) (:) ] transpiration wetness factor (0 to 1) t_scalar => soilbiogeochem_carbonflux_inst%t_scalar_col & ! Input: [real(r8) (:,:) ] soil temperature scalar for decomp @@ -1533,7 +1536,6 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & ! 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 @@ -1542,7 +1544,11 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & huigrain(p))/((gddmaturity(p)*declfact(ivt(p)))- & huigrain(p)),1._r8)**allconss(ivt(p)) ))) end if - if (aleafi(p) > aleaff(ivt(p))) then + + ! 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)))- & @@ -1572,14 +1578,11 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & 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 * ((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)))) + leafn_to_retransn(p) = t1 * max(leafn(p)- (leafc(p) / fleafcn(ivt(p))),0._r8) + livestemn_to_retransn(p) = t1 * max(livestemn(p) - (livestemc(p) / fstemcn(ivt(p))),0._r8) 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)))) + frootn_to_retransn(p) = t1 * max(frootn(p) - (frootc(p) / ffrootcn(ivt(p))),0._r8) end if grain_flag(p) = 1._r8 end if @@ -1599,6 +1602,7 @@ subroutine calc_plant_nitrogen_demand(this, bounds, num_soilp, filter_soilp, & f5 = arepr(p) / aleaf(p) g1 = 0.25_r8 + else ! .not croplive f1 = 0._r8 f3 = 0._r8 diff --git a/src/biogeochem/SpeciesIsotopeType.F90 b/src/biogeochem/SpeciesIsotopeType.F90 index a9feb5e154..b5fb749823 100644 --- a/src/biogeochem/SpeciesIsotopeType.F90 +++ b/src/biogeochem/SpeciesIsotopeType.F90 @@ -92,7 +92,7 @@ pure function hist_fname(this, basename, suffix) result(fname) fname = trim(this%species_name) // trim(this%isotope_name) // '_' // & trim(basename) // trim(this%species_name) if (present(suffix)) then - fname = fname // suffix + fname = trim(fname) // trim(suffix) end if end function hist_fname @@ -117,7 +117,7 @@ function rest_fname(this, basename, suffix) result(fname) species_name_lcase = shr_string_toLower(trim(this%species_name)) fname = trim(basename) // species_name_lcase // '_' // trim(this%isotope_name) if (present(suffix)) then - fname = fname // suffix + fname = trim(fname) // trim(suffix) end if end function rest_fname diff --git a/src/biogeochem/SpeciesNonIsotopeType.F90 b/src/biogeochem/SpeciesNonIsotopeType.F90 index 4bde5ec583..0daf6b3f72 100644 --- a/src/biogeochem/SpeciesNonIsotopeType.F90 +++ b/src/biogeochem/SpeciesNonIsotopeType.F90 @@ -81,7 +81,7 @@ pure function hist_fname(this, basename, suffix) result(fname) fname = trim(basename) // trim(this%species_name) if (present(suffix)) then - fname = fname // suffix + fname = trim(fname) // trim(suffix) end if end function hist_fname @@ -104,9 +104,9 @@ function rest_fname(this, basename, suffix) result(fname) !----------------------------------------------------------------------- species_name_lcase = shr_string_toLower(trim(this%species_name)) - fname = trim(basename) // species_name_lcase + fname = trim(basename) // trim(species_name_lcase) if (present(suffix)) then - fname = fname // suffix + fname = trim(fname) // trim(suffix) end if end function rest_fname diff --git a/src/biogeochem/ch4FInundatedStreamType.F90 b/src/biogeochem/ch4FInundatedStreamType.F90 new file mode 100644 index 0000000000..eb9f743f67 --- /dev/null +++ b/src/biogeochem/ch4FInundatedStreamType.F90 @@ -0,0 +1,393 @@ + +module ch4FInundatedStreamType + +#include "shr_assert.h" + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Contains methods for reading in finundated streams file for methane code. + ! + ! !USES + use shr_kind_mod , only: r8 => shr_kind_r8, CL => shr_kind_cl + use spmdMod , only: mpicom, masterproc + use clm_varctl , only: iulog + use abortutils , only: endrun + use decompMod , only: bounds_type + use ch4varcon , only: finundation_mtd + + ! !PUBLIC TYPES: + implicit none + private + save + + type, public :: ch4finundatedstream_type + real(r8), pointer, private :: zwt0_gdc (:) ! col coefficient for determining finundated (m) + real(r8), pointer, private :: f0_gdc (:) ! col maximum inundated fraction for a gridcell (for methane code) + real(r8), pointer, private :: p3_gdc (:) ! col coefficient for determining finundated (m) + real(r8), pointer, private :: fws_slope_gdc (:) ! col slope in fws = slope * tws + intercept (A coefficient) + real(r8), pointer, private :: fws_intercept_gdc (:) ! col slope in fws = slope * tws + intercept (B coefficient) + contains + + ! !PUBLIC MEMBER FUNCTIONS: + procedure, public :: Init ! Initialize and read data in + procedure, public :: CalcFinundated ! Calculate finundated based on input streams + procedure, public :: UseStreams ! If streams will be used + + ! !PRIVATE MEMBER FUNCTIONS: + procedure, private :: InitAllocate ! Allocate data + + end type ch4finundatedstream_type + + + ! ! PRIVATE DATA: + + type, private :: streamcontrol_type + character(len=CL) :: stream_fldFileName_ch4finundated ! Filename + character(len=CL) :: ch4finundatedmapalgo ! map algo + character(len=CL) :: fldList ! List of fields to read + contains + procedure, private :: ReadNML ! Read in namelist + end type streamcontrol_type + + type(streamcontrol_type), private :: control ! Stream control data + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + !============================================================================== + +contains + + !============================================================================== + + subroutine Init(this, bounds, NLFilename) + ! + ! Initialize the ch4 finundated stream object + ! + ! Uses: + use clm_varctl , only : inst_name + use clm_time_manager , only : get_calendar, get_curr_date + use ncdio_pio , only : pio_subsystem + use shr_pio_mod , only : shr_pio_getiotype + use shr_nl_mod , only : shr_nl_find_group_name + use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_mpi_mod , only : shr_mpi_bcast + use ndepStreamMod , only : clm_domain_mct + use domainMod , only : ldomain + use decompMod , only : bounds_type, gsmap_lnd_gdc2glo + use mct_mod , only : mct_ggrid, mct_avect_indexra + use shr_strdata_mod , only : shr_strdata_type, shr_strdata_create + use shr_strdata_mod , only : shr_strdata_print, shr_strdata_advance + use spmdMod , only : comp_id, iam + use ch4varcon , only : finundation_mtd_h2osfc + use ch4varcon , only : finundation_mtd_ZWT_inversion, finundation_mtd_TWS_inversion + ! + ! arguments + implicit none + class(ch4finundatedstream_type) :: this + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename + ! + ! local variables + integer :: ig, g ! Indices + type(mct_ggrid) :: dom_clm ! domain information + type(shr_strdata_type) :: sdat ! input data stream + integer :: index_ZWT0 = 0 ! Index of ZWT0 field + integer :: index_F0 = 0 ! Index of F0 field + integer :: index_P3 = 0 ! Index of P3 field + integer :: index_FWS_TWS_A = 0 ! Index of FWS_TWS_A field + integer :: index_FWS_TWS_B = 0 ! Index of FWS_TWS_B field + integer :: year ! year (0, ...) for nstep+1 + integer :: mon ! month (1, ..., 12) for nstep+1 + integer :: day ! day of month (1, ..., 31) for nstep+1 + integer :: sec ! seconds into current date for nstep+1 + integer :: mcdate ! Current model date (yyyymmdd) + character(len=*), parameter :: stream_name = 'ch4finundated' + character(*), parameter :: subName = "('ch4finundatedstream::Init')" + !----------------------------------------------------------------------- + if ( finundation_mtd /= finundation_mtd_h2osfc )then + call this%InitAllocate( bounds ) + call control%ReadNML( bounds, NLFileName ) + + if ( this%useStreams() )then + call clm_domain_mct (bounds, dom_clm) + + call shr_strdata_create(sdat,name=stream_name,& + pio_subsystem=pio_subsystem, & + pio_iotype=shr_pio_getiotype(inst_name), & + mpicom=mpicom, compid=comp_id, & + gsmap=gsmap_lnd_gdc2glo, ggrid=dom_clm, & + nxg=ldomain%ni, nyg=ldomain%nj, & + yearFirst=1996, & + yearLast=1996, & + yearAlign=1, & + offset=0, & + domFilePath='', & + domFileName=trim(control%stream_fldFileName_ch4finundated), & + domTvarName='time', & + domXvarName='LONGXY' , & + domYvarName='LATIXY' , & + domAreaName='AREA', & + domMaskName='LANDMASK', & + filePath='', & + filename=(/trim(control%stream_fldFileName_ch4finundated)/),& + fldListFile=control%fldList, & + fldListModel=control%fldList, & + fillalgo='none', & + mapalgo=control%ch4finundatedmapalgo, & + calendar=get_calendar(), & + taxmode='extend' ) + + if (masterproc) then + call shr_strdata_print(sdat,'CLM '//stream_name//' data') + endif + + if( finundation_mtd == finundation_mtd_ZWT_inversion )then + index_ZWT0 = mct_avect_indexra(sdat%avs(1),'ZWT0') + index_F0 = mct_avect_indexra(sdat%avs(1),'F0' ) + index_P3 = mct_avect_indexra(sdat%avs(1),'P3' ) + else if( finundation_mtd == finundation_mtd_TWS_inversion )then + index_FWS_TWS_A = mct_avect_indexra(sdat%avs(1),'FWS_TWS_A') + index_FWS_TWS_B = mct_avect_indexra(sdat%avs(1),'FWS_TWS_B') + end if + + + ! Explicitly set current date to a hardcoded constant value. Otherwise + ! using the real date can cause roundoff differences that are + ! detrected as issues with exact restart. EBK M05/20/2017 + !call get_curr_date(year, mon, day, sec) + year = 1996 + mon = 12 + day = 31 + sec = 0 + mcdate = year*10000 + mon*100 + day + + call shr_strdata_advance(sdat, mcdate, sec, mpicom, 'ch4finundated') + + ! Get the data + ig = 0 + do g = bounds%begg,bounds%endg + ig = ig+1 + if ( index_ZWT0 > 0 )then + this%zwt0_gdc(g) = sdat%avs(1)%rAttr(index_ZWT0,ig) + end if + if ( index_F0 > 0 )then + this%f0_gdc(g) = sdat%avs(1)%rAttr(index_F0,ig) + end if + if ( index_P3 > 0 )then + this%p3_gdc(g) = sdat%avs(1)%rAttr(index_P3,ig) + end if + if ( index_FWS_TWS_A > 0 )then + this%fws_slope_gdc(g) = sdat%avs(1)%rAttr(index_FWS_TWS_A,ig) + end if + if ( index_FWS_TWS_B > 0 )then + this%fws_intercept_gdc(g) = sdat%avs(1)%rAttr(index_FWS_TWS_B,ig) + end if + end do + end if + end if + + end subroutine Init + + !----------------------------------------------------------------------- + logical function UseStreams(this) + ! + ! !DESCRIPTION: + ! Return true if + ! + ! !USES: + ! + ! !ARGUMENTS: + implicit none + class(ch4finundatedstream_type) :: this + ! + ! !LOCAL VARIABLES: + if ( trim(control%stream_fldFileName_ch4finundated) == '' )then + UseStreams = .false. + else + UseStreams = .true. + end if + end function UseStreams + + !----------------------------------------------------------------------- + subroutine InitAllocate(this, bounds) + ! + ! !DESCRIPTION: + ! Allocate module variables and data structures + ! + ! !USES: + use shr_infnan_mod, only: nan => shr_infnan_nan, assignment(=) + use ch4varcon , only: finundation_mtd_ZWT_inversion, finundation_mtd_TWS_inversion + ! + ! !ARGUMENTS: + implicit none + class(ch4finundatedstream_type) :: this + type(bounds_type), intent(in) :: bounds + ! + ! !LOCAL VARIABLES: + integer :: begc, endc + integer :: begg, endg + !--------------------------------------------------------------------- + + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + + if( finundation_mtd == finundation_mtd_ZWT_inversion )then + allocate(this%zwt0_gdc (begg:endg)) ; this%zwt0_gdc (:) = nan + allocate(this%f0_gdc (begg:endg)) ; this%f0_gdc (:) = nan + allocate(this%p3_gdc (begg:endg)) ; this%p3_gdc (:) = nan + else if( finundation_mtd == finundation_mtd_TWS_inversion )then + allocate(this%fws_slope_gdc (begg:endg)) ; this%fws_slope_gdc (:) = nan + allocate(this%fws_intercept_gdc(begg:endg)) ; this%fws_intercept_gdc(:) = nan + end if + + end subroutine InitAllocate + + !----------------------------------------------------------------------- + subroutine CalcFinundated(this, bounds, num_soilc, filter_soilc, soilhydrology_inst, waterstate_inst, & + qflx_surf_lag_col, finundated ) + ! + ! !DESCRIPTION: + ! + ! Calculate finundated according to the appropriate methodology + ! + ! !USES: + use ColumnType , only : col + use ch4varcon , only : finundation_mtd_h2osfc, finundation_mtd_ZWT_inversion + use ch4varcon , only : finundation_mtd_TWS_inversion + use clm_varpar , only : nlevsoi + use SoilHydrologyType, only : soilhydrology_type + use WaterstateType , only : waterstate_type + use shr_log_mod , only : errMsg => shr_log_errMsg + ! + ! !ARGUMENTS: + implicit none + class(ch4finundatedstream_type) :: this + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_soilc ! number of column soil points in column filter + integer , intent(in) :: filter_soilc(:) ! column filter for soil points + type(soilhydrology_type) , intent(in) :: soilhydrology_inst + type(waterstate_type) , intent(in) :: waterstate_inst + real(r8) , intent(in) :: qflx_surf_lag_col(bounds%begc:) !time-lagged surface runoff (mm H2O /s) + real(r8) , intent(inout) :: finundated(bounds%begc:) ! fractional inundated area in soil column (excluding dedicated wetland columns) + ! + ! !LOCAL VARIABLES: + integer :: g, c, fc ! Indices + real(r8) :: zwt_actual ! Total water storage (ZWT) to use either perched or total depending on conditions + + SHR_ASSERT_ALL((ubound(qflx_surf_lag_col) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(finundated) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + associate( & + z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) (-nlevsno+1:nlevsoi) + zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) + zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Input: [real(r8) (:) ] perched water table depth (m) + tws => waterstate_inst%tws_grc , & ! Input: [real(r8) (:) ] total water storage (kg m-2) + frac_h2osfc => waterstate_inst%frac_h2osfc_col & ! Input: [real(r8) (:) ] fraction of ground covered by surface water (0 to 1) + ) + + ! Calculate finundated + do fc = 1, num_soilc + c = filter_soilc(fc) + g = col%gridcell(c) + select case( finundation_mtd ) + case ( finundation_mtd_h2osfc ) + finundated(c) = frac_h2osfc(c) + case ( finundation_mtd_ZWT_inversion ) + if (this%zwt0_gdc(g) > 0._r8) then + if (zwt_perched(c) < z(c,nlevsoi)-1.e-5_r8 .and. zwt_perched(c) < zwt(c)) then + zwt_actual = zwt_perched(c) + else + zwt_actual = zwt(c) + end if + finundated(c) = this%f0_gdc(g) * exp(-zwt_actual/this%zwt0_gdc(g)) + this%p3_gdc(g)*qflx_surf_lag_col(c) + else + finundated(c) = this%p3_gdc(g)*qflx_surf_lag_col(c) + end if + case ( finundation_mtd_TWS_inversion ) + finundated(c) = this%fws_slope_gdc(g) * tws(g) + this%fws_intercept_gdc(g) + end select + finundated(c) = min( 1.0_r8, max( 0.0_r8, finundated(c) ) ) + end do + end associate + + end subroutine CalcFinundated + !============================================================================== + + subroutine ReadNML(this, bounds, NLFilename) + ! + ! Read the namelist data stream information. + ! + ! Uses: + use clm_varctl , only : inst_name + use clm_time_manager , only : get_calendar + use ncdio_pio , only : pio_subsystem + use shr_pio_mod , only : shr_pio_getiotype + use shr_nl_mod , only : shr_nl_find_group_name + use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_mpi_mod , only : shr_mpi_bcast + use fileutils , only : getavu, relavu + use ch4varcon , only : finundation_mtd_ZWT_inversion, finundation_mtd_TWS_inversion + ! + ! arguments + implicit none + class(streamcontrol_type) :: this + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename + ! + ! local variables + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + character(len=CL) :: stream_fldFileName_ch4finundated = ' ' + character(len=CL) :: ch4finundatedmapalgo = 'bilinear' + character(len=*), parameter :: namelist_name = 'ch4finundated' ! MUST agree with name in namelist and read + character(len=*), parameter :: shr_strdata_unset = 'NOT_SET' + character(len=*), parameter :: subName = "('ch4finundated::ReadNML')" + character(len=*), parameter :: F00 = "('(ch4finundated_readnml) ',4a)" + !----------------------------------------------------------------------- + + namelist /ch4finundated/ & ! MUST agree with namelist_name above + ch4finundatedmapalgo, stream_fldFileName_ch4finundated + + ! Default values for namelist + + ! Read ch4finundateddyn_nml namelist + if (masterproc) then + nu_nml = getavu() + open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call shr_nl_find_group_name(nu_nml, namelist_name, status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=ch4finundated,iostat=nml_error) ! MUST agree with namelist_name above + if (nml_error /= 0) then + call endrun(msg=' ERROR reading '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__)) + end if + else + call endrun(msg=' ERROR finding '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__)) + end if + close(nu_nml) + call relavu( nu_nml ) + endif + + call shr_mpi_bcast(stream_fldFileName_ch4finundated, mpicom) + call shr_mpi_bcast(ch4finundatedmapalgo , mpicom) + + if (masterproc) then + write(iulog,*) ' ' + write(iulog,*) namelist_name, ' stream settings:' + write(iulog,*) ' stream_fldFileName_ch4finundated = ',stream_fldFileName_ch4finundated + write(iulog,*) ' ch4finundatedmapalgo = ',ch4finundatedmapalgo + write(iulog,*) ' ' + endif + this%stream_fldFileName_ch4finundated = stream_fldFileName_ch4finundated + this%ch4finundatedmapalgo = ch4finundatedmapalgo + if ( finundation_mtd == finundation_mtd_ZWT_inversion )then + this%fldList = "ZWT0:F0:P3" + else if ( finundation_mtd == finundation_mtd_TWS_inversion )then + this%fldList = "FWS_TWS_A:FWS_TWS_B" + else + call endrun(msg=' ERROR do NOT know what list of variables to read for this finundation_mtd type'// & + errMsg(sourcefile, __LINE__)) + end if + + end subroutine ReadNML + +end module ch4FInundatedStreamType diff --git a/src/biogeochem/ch4Mod.F90 b/src/biogeochem/ch4Mod.F90 index 0a9555b7b1..26dc791f72 100644 --- a/src/biogeochem/ch4Mod.F90 +++ b/src/biogeochem/ch4Mod.F90 @@ -37,6 +37,7 @@ module ch4Mod use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch + use ch4FInundatedStreamType , only : ch4finundatedstream_type ! implicit none private @@ -202,6 +203,7 @@ module ch4Mod real(r8), pointer, public :: grnd_ch4_cond_patch (:) ! patch tracer conductance for boundary layer [m/s] real(r8), pointer, public :: grnd_ch4_cond_col (:) ! col tracer conductance for boundary layer [m/s] + type(ch4finundatedstream_type), private :: ch4findstream ! ch4 finundated stream data contains @@ -221,17 +223,19 @@ module ch4Mod contains !------------------------------------------------------------------------ - subroutine Init( this, bounds, cellorg_col, fsurdat ) + subroutine Init( this, bounds, cellorg_col, fsurdat, NLFilename ) class(ch4_type) :: this type(bounds_type), intent(in) :: bounds real(r8) , intent(in) :: cellorg_col (bounds%begc:, 1:) character(len=*) , intent(in) :: fsurdat ! surface data file name + character(len=*), intent(in) :: NLFilename ! Namelist filename call this%InitAllocate (bounds) if (use_lch4) then call this%InitHistory (bounds) call this%InitCold (bounds, cellorg_col, fsurdat) + call this%ch4findstream%Init( bounds, NLFilename ) end if end subroutine Init @@ -363,6 +367,7 @@ subroutine InitHistory(this, bounds) character(10) :: active integer :: begc,endc integer :: begg,endg + real(r8), pointer :: data2dptr(:,:) ! temp. pointers for slicing larger arrays !--------------------------------------------------------------------- begc = bounds%begc; endc = bounds%endc @@ -394,7 +399,7 @@ subroutine InitHistory(this, bounds) ! finundated is implicitly 1). call hist_addfld1d (fname='FINUNDATED_LAG', units='unitless', & avgflag='A', long_name='time-lagged inundated fraction of vegetated columns', & - ptr_col=this%finundated_lag_col, l2g_scale_type='veg') + ptr_col=this%finundated_lag_col, l2g_scale_type='veg', default='inactive') this%ch4_surf_diff_sat_col(begc:endc) = spval call hist_addfld1d (fname='CH4_SURF_DIFF_SAT', units='mol/m2/s', & @@ -654,17 +659,19 @@ subroutine InitHistory(this, bounds) this%conc_o2_sat_col(begc:endc,1:nlevgrnd) = spval ! Using l2g_scale_type='veg_plus_lake' to exclude mass in non-lake special landunits, ! which can arise from dynamic column adjustments - call hist_addfld2d (fname='CONC_O2_SAT', units='mol/m3', type2d='levgrnd', & + data2dptr => this%conc_o2_sat_col(:,1:nlevsoi) + call hist_addfld2d (fname='CONC_O2_SAT', units='mol/m3', type2d='levsoi', & avgflag='A', long_name='O2 soil Concentration for inundated / lake area', & - ptr_col=this%conc_o2_sat_col, l2g_scale_type='veg_plus_lake') + ptr_col=data2dptr, l2g_scale_type='veg_plus_lake') this%conc_o2_unsat_col(begc:endc,1:nlevgrnd) = spval ! Using l2g_scale_type='veg' to exclude mass in special landunits, which can arise ! from dynamic column adjustments. (We also exclude lakes here, because they don't ! have any unsaturated area.) - call hist_addfld2d (fname='CONC_O2_UNSAT', units='mol/m3', type2d='levgrnd', & + data2dptr => this%conc_o2_unsat_col(:,1:nlevsoi) + call hist_addfld2d (fname='CONC_O2_UNSAT', units='mol/m3', type2d='levsoi', & avgflag='A', long_name='O2 soil Concentration for non-inundated area', & - ptr_col=this%conc_o2_unsat_col, l2g_scale_type='veg') + ptr_col=data2dptr, l2g_scale_type='veg') this%ch4co2f_grc(begg:endg) = spval call hist_addfld1d (fname='FCH4TOCO2', units='gC/m2/s', & @@ -689,7 +696,7 @@ subroutine InitHistory(this, bounds) this%qflx_surf_lag_col(begc:endc) = spval call hist_addfld1d (fname='QOVER_LAG', units='mm/s', & avgflag='A', long_name='time-lagged surface runoff for soil columns', & - ptr_col=this%qflx_surf_lag_col) + ptr_col=this%qflx_surf_lag_col, default='inactive') if (allowlakeprod) then this%lake_soilc_col(begc:endc,1:nlevgrnd) = spval @@ -730,7 +737,8 @@ subroutine InitCold(this, bounds, cellorg_col, fsurdat) use clm_varpar , only : nlevsoi, nlevgrnd, nlevdecomp use landunit_varcon , only : istsoil, istdlak, istcrop use clm_varctl , only : iulog - use ch4varcon , only : allowlakeprod, usephfact, fin_use_fsat + use ch4varcon , only : allowlakeprod, usephfact, finundation_mtd + use ch4varcon , only : finundation_mtd_ZWT_inversion use spmdMod , only : masterproc use fileutils , only : getfil use ncdio_pio @@ -758,16 +766,16 @@ subroutine InitCold(this, bounds, cellorg_col, fsurdat) ! Initialize time constant variables !---------------------------------------- - allocate(zwt0_in(bounds%begg:bounds%endg)) - allocate(f0_in(bounds%begg:bounds%endg)) - allocate(p3_in(bounds%begg:bounds%endg)) + allocate(zwt0_in (bounds%begg:bounds%endg)) + allocate(f0_in (bounds%begg:bounds%endg)) + allocate(p3_in (bounds%begg:bounds%endg)) if (usephfact) allocate(ph_in(bounds%begg:bounds%endg)) ! Methane code parameters for finundated call getfil( fsurdat, locfn, 0 ) call ncd_pio_openfile (ncid, trim(locfn), 0) - if (.not. fin_use_fsat) then + if ( finundation_mtd == finundation_mtd_zwt_inversion ) then call ncd_io(ncid=ncid, varname='ZWT0', flag='read', data=zwt0_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then call endrun(msg=' ERROR: Running with CH4 Model but ZWT0 not on surfdata file'//& @@ -798,10 +806,10 @@ subroutine InitCold(this, bounds, cellorg_col, fsurdat) do c = bounds%begc, bounds%endc g = col%gridcell(c) - if (.not. fin_use_fsat) then - this%zwt0_col(c) = zwt0_in(g) - this%f0_col(c) = f0_in(g) - this%p3_col(c) = p3_in(g) + if (finundation_mtd == finundation_mtd_ZWT_inversion ) then + this%zwt0_col(c) = zwt0_in(g) + this%f0_col(c) = f0_in(g) + this%p3_col(c) = p3_in(g) end if if (usephfact) this%pH_col(c) = pH_in(g) end do @@ -1241,7 +1249,7 @@ subroutine Restart( this, bounds, ncid, flag ) end subroutine Restart !----------------------------------------------------------------------- - subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) + subroutine DynamicColumnAdjustments(this, bounds, clump_index, column_state_updater) ! ! !DESCRIPTION: ! Adjust state variables when column areas change due to dynamic landuse @@ -1252,6 +1260,11 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) ! !ARGUMENTS: class(ch4_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer , intent(in) :: clump_index + type(column_state_updater_type) , intent(in) :: column_state_updater ! ! !LOCAL VARIABLES: @@ -1284,6 +1297,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) this%finundated_col(begc:endc) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = finundated_new_col(begc:endc)) f_uninundated_col(begc:endc) = & @@ -1292,10 +1306,12 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) f_uninundated_col(begc:endc) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = f_uninundated_new_col(begc:endc)) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%finundated_lag_col(begc:endc)) this%dyn_ch4bal_adjustments_col(begc:endc) = 0._r8 @@ -1303,6 +1319,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) do j = 1, nlevsoi call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%conc_ch4_sat_col(begc:endc, j), & fractional_area_old = this%finundated_col(begc:endc), & fractional_area_new = finundated_new_col(begc:endc), & @@ -1315,6 +1332,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%conc_ch4_unsat_col(begc:endc, j), & fractional_area_old = f_uninundated_col(begc:endc), & fractional_area_new = f_uninundated_new_col(begc:endc), & @@ -1328,6 +1346,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) ! layer_sat_lag just applies to the UNinundated portion of the column call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%layer_sat_lag_col(begc:endc, j), & fractional_area_old = f_uninundated_col(begc:endc), & fractional_area_new = f_uninundated_new_col(begc:endc)) @@ -1338,12 +1357,14 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%conc_o2_sat_col(begc:endc, j), & fractional_area_old = this%finundated_col(begc:endc), & fractional_area_new = finundated_new_col(begc:endc)) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%conc_o2_unsat_col(begc:endc, j), & fractional_area_old = f_uninundated_col(begc:endc), & fractional_area_new = f_uninundated_new_col(begc:endc)) @@ -1616,8 +1637,9 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & use subgridAveMod , only : p2c, c2g use clm_varpar , only : nlevgrnd, nlevdecomp use pftconMod , only : noveg - use ch4varcon , only : replenishlakec, allowlakeprod, ch4offline, fin_use_fsat + use ch4varcon , only : replenishlakec, allowlakeprod, ch4offline use clm_varcon , only : secspday + use ch4varcon , only : finundation_mtd, finundation_mtd_h2osfc ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -1702,6 +1724,7 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & frac_h2osfc => waterstate_inst%frac_h2osfc_col , & ! Input: [real(r8) (:) ] fraction of ground covered by surface water (0 to 1) snow_depth => waterstate_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m) + tws => waterstate_inst%tws_grc , & ! Input: [real(r8) (:) ] total water storage (kg m-2) qflx_surf => waterflux_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] surface runoff (mm H2O /s) conc_o2_sat => ch4_inst%conc_o2_sat_col , & ! Input: [real(r8) (:,:) ] O2 conc in each soil layer (mol/m3) (nlevsoi) @@ -1797,7 +1820,7 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & c_atm(g,3) = forc_pco2(g) / rgasm / forc_t(g) ! [mol/m3 air] end do - ! Calculate finundated + ! Save finundated before, and calculate lagged surface runoff do fc = 1, num_soilc c = filter_soilc(fc) g = col%gridcell(c) @@ -1814,10 +1837,19 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & qflx_surf_lag(c) = qflx_surf_lag(c) * exp(-dtime/qflxlags) & + qflx_surf(c) * (1._r8 - exp(-dtime/qflxlags)) - !There may be ways to improve this for irrigated crop columns... - if (fin_use_fsat) then - finundated(c) = frac_h2osfc(c) - else + end do + + ! Caulculate finundated + if ( ch4_inst%ch4findstream%useStreams() & + .or. (finundation_mtd == finundation_mtd_h2osfc) )then + call ch4_inst%ch4findstream%CalcFinundated( bounds, num_soilc, & + filter_soilc, soilhydrology_inst, waterstate_inst, & + qflx_surf_lag(begc:endc), finundated(begc:endc) ) + else + + ! Calculate finundated with ZWT inversion from surface dataset + do fc = 1, num_soilc + c = filter_soilc(fc) if (zwt0(c) > 0._r8) then if (zwt_perched(c) < z(c,nlevsoi)-1.e-5_r8 .and. zwt_perched(c) < zwt(c)) then zwt_actual = zwt_perched(c) @@ -1828,8 +1860,13 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & else finundated(c) = p3(c)*qflx_surf_lag(c) end if - end if + + end do + end if + ! Calculate finundated before snow and lagged version of finundated + do fc = 1, num_soilc + c = filter_soilc(fc) if (snow_depth(c) <= 0._r8) then ! If snow_depth<=0,use the above method to calculate finundated. finundated(c) = max( min(finundated(c),1._r8), 0._r8) finundated_pre_snow(c) = finundated(c) @@ -2395,7 +2432,6 @@ subroutine ch4_prod (bounds, num_methc, filter_methc, num_methp, & do j=1,nlevsoi do fc = 1, num_methc c = filter_methc (fc) - g = col%gridcell(c) if (.not. lake) then @@ -3306,7 +3342,11 @@ subroutine ch4_tran (bounds, & o2demand = o2_decomp_depth(c,j) + o2_oxid_depth(c,j) ! o2_decomp_depth includes autotrophic root respiration if (o2demand > 0._r8) then - o2stress(c,j) = min((conc_o2(c,j) / dtime + o2_aere_depth(c,j)) / o2demand, 1._r8) + if ( (conc_o2(c,j) / dtime + o2_aere_depth(c,j)) > o2demand )then + o2stress(c,j) = 1._r8 + else + o2stress(c,j) = (conc_o2(c,j) / dtime + o2_aere_depth(c,j)) / o2demand + end if else o2stress(c,j) = 1._r8 end if diff --git a/src/biogeochem/ch4varcon.F90 b/src/biogeochem/ch4varcon.F90 index 532e5709dd..5bf4917e74 100644 --- a/src/biogeochem/ch4varcon.F90 +++ b/src/biogeochem/ch4varcon.F90 @@ -12,59 +12,58 @@ module ch4varcon ! ! Methane Model Parameters ! + private - logical :: use_aereoxid_prog = .true. ! if false then aereoxid is read off of + logical, public :: use_aereoxid_prog = .true. ! if false then aereoxid is read off of ! the parameter file and may be modifed by the user (default aereoxid on the ! file is 0.0). - logical :: transpirationloss = .true. ! switch for activating CH4 loss from transpiration + logical, public :: transpirationloss = .true. ! switch for activating CH4 loss from transpiration ! Transpiration loss assumes that the methane concentration in dissolved soil ! water remains constant through the plant and is released when the water evaporates ! from the stomata. ! Currently hard-wired to true; impact is < 1 Tg CH4/yr - logical :: allowlakeprod = .false. ! Switch to allow production under lakes based on soil carbon dataset + logical, public :: allowlakeprod = .false. ! Switch to allow production under lakes based on soil carbon dataset ! (Methane can be produced, and CO2 produced from methane oxidation, ! which will slowly reduce the available carbon stock, if ! replenishlakec, but no other biogeochem is done.) ! Note: switching this off turns off ALL lake methane biogeochem. However, 0 values ! will still be averaged into the concentration _sat history fields. - logical :: usephfact = .false. ! Switch to use pH factor in methane production + logical, public :: usephfact = .false. ! Switch to use pH factor in methane production - logical :: replenishlakec = .true. ! Switch for keeping carbon storage under lakes constant + logical, public :: replenishlakec = .true. ! Switch for keeping carbon storage under lakes constant ! so that lakes do not affect the carbon balance ! Good for long term rather than transient warming experiments ! NOTE SWITCHING THIS OFF ASSUMES TRANSIENT CARBON SUPPLY FROM LAKES; COUPLED MODEL WILL NOT CONSERVE CARBON ! IN THIS MODE. - ! New namelists added 6/12/11 + ! inundatrion fraction -- which is used in methane code and potentially soil code + integer, public :: finundation_mtd ! Finundation method type to use, one of the following + integer, public, parameter :: finundation_mtd_h2osfc = 0 ! Use prognostic fsat h2osfc + integer, public, parameter :: finundation_mtd_ZWT_inversion = 1 ! Use inversion of ZWT to Prigent satellite inundation obs. data + integer, public, parameter :: finundation_mtd_TWS_inversion = 2 ! Use inversion of TWS to Prigent satellite inundation obs. data - logical :: fin_use_fsat = .false. ! Use fsat rather than the inversion to Prigent satellite inundation obs. (applied to - ! CLM water table depth and surface runoff) to calculated finundated which is - ! used in methane code and potentially soil code - !!!! Attn EK: Set this to true when Sean Swenson's prognostic, tested - ! fsat is integrated. (CLM4 fsat is bad for these purposes.) - - logical :: usefrootc = .false. ! Use CLMCN fine root C rather than ann NPP & LAI based parameterization to + logical, public :: usefrootc = .false. ! Use CLMCN fine root C rather than ann NPP & LAI based parameterization to ! calculate tiller C for aerenchyma area calculation. ! The NPP & LAI param. was based on Wania for Arctic sedges and may not be ! appropriate for woody Patches, although nongrassporosratio above partly adjusts ! for this. However, using fine root C reduces the aerenchyma area by a large ! factor. - logical :: ch4offline = .true. ! true --> Methane is not passed between the land & atmosphere. + logical, public :: ch4offline = .true. ! true --> Methane is not passed between the land & atmosphere. ! NEM is not added to NEE flux to atm. to correct for methane production, ! and ambient CH4 is set to constant 2009 value. - logical :: ch4rmcnlim = .false. ! Remove the N and low moisture limitations on SOM HR when calculating + logical, public :: ch4rmcnlim = .false. ! Remove the N and low moisture limitations on SOM HR when calculating ! methanogenesis. ! Note: this option has not been extensively tested. ! Currently hardwired off. - logical :: anoxicmicrosites = .false. ! Use Arah & Stephen 1998 expression to allow production above the water table + logical, public :: anoxicmicrosites = .false. ! Use Arah & Stephen 1998 expression to allow production above the water table ! Currently hardwired off; expression is crude. - logical :: ch4frzout = .false. ! Exclude CH4 from frozen fraction of soil pore H2O, to simulate "freeze-out" pulse + logical, public :: ch4frzout = .false. ! Exclude CH4 from frozen fraction of soil pore H2O, to simulate "freeze-out" pulse ! as in Mastepanov 2008. ! Causes slight increase in emissions in the fall and decrease in the spring. ! Currently hardwired off; small impact. @@ -85,7 +84,7 @@ subroutine ch4conrd () ! ! !USES: use fileutils , only : relavu, getavu - use spmdMod , only : masterproc, mpicom, MPI_REAL8, MPI_LOGICAL + use spmdMod , only : masterproc, mpicom, MPI_REAL8, MPI_LOGICAL, MPI_INTEGER use shr_nl_mod , only : shr_nl_find_group_name use shr_log_mod , only : errMsg => shr_log_errMsg ! @@ -95,6 +94,7 @@ subroutine ch4conrd () integer :: ierr ! error code integer :: unitn ! unit for namelist file character(len=32) :: subname = 'ch4conrd' ! subroutine name + character(len=50) :: finundation_method = 'ZWT_inversion' ! String for finundation_method to use !----------------------------------------------------------------------- ! ---------------------------------------------------------------------- @@ -103,7 +103,7 @@ subroutine ch4conrd () ! Driver namelist /ch4par_in/ & - ch4offline, fin_use_fsat, replenishlakec, allowlakeprod + ch4offline, replenishlakec, allowlakeprod, finundation_method ! Production namelist /ch4par_in/ & @@ -136,30 +136,41 @@ subroutine ch4conrd () end if call relavu( unitn ) + if ( trim(finundation_method) == "h2osfc" )then + finundation_mtd = finundation_mtd_h2osfc + else if ( trim(finundation_method) == "TWS_inversion" )then + finundation_mtd = finundation_mtd_tws_inversion + else if ( trim(finundation_method) == "ZWT_inversion" )then + finundation_mtd = finundation_mtd_zwt_inversion + else + call endrun(msg='error bad value for finundation_method in ch4par_in namelist'//& + errMsg(sourcefile, __LINE__)) + end if + end if ! masterproc call mpi_bcast ( use_aereoxid_prog, 1 , MPI_LOGICAL, 0, mpicom, ierr ) - call mpi_bcast (allowlakeprod, 1 , MPI_LOGICAL, 0, mpicom, ierr) - call mpi_bcast (usephfact, 1 , MPI_LOGICAL, 0, mpicom, ierr) - call mpi_bcast (replenishlakec, 1 , MPI_LOGICAL, 0, mpicom, ierr) - call mpi_bcast (fin_use_fsat, 1 , MPI_LOGICAL, 0, mpicom, ierr) - call mpi_bcast (usefrootc, 1 , MPI_LOGICAL, 0, mpicom, ierr) - call mpi_bcast (ch4offline, 1 , MPI_LOGICAL, 0, mpicom, ierr) + call mpi_bcast (allowlakeprod, 1 , MPI_LOGICAL, 0, mpicom, ierr) + call mpi_bcast (usephfact, 1 , MPI_LOGICAL, 0, mpicom, ierr) + call mpi_bcast (replenishlakec, 1 , MPI_LOGICAL, 0, mpicom, ierr) + call mpi_bcast (finundation_mtd, 1 , MPI_INTEGER, 0, mpicom, ierr) + call mpi_bcast (usefrootc, 1 , MPI_LOGICAL, 0, mpicom, ierr) + call mpi_bcast (ch4offline, 1 , MPI_LOGICAL, 0, mpicom, ierr) if (masterproc) then write(iulog,*) 'Successfully read CH4 namelist' write(iulog,*)' ' - write(iulog,*)'allowlakeprod = ', allowlakeprod - write(iulog,*)'usephfact = ', usephfact - write(iulog,*)'replenishlakec = ', replenishlakec - write(iulog,*)'fin_use_fsat = ', fin_use_fsat - write(iulog,*)'usefrootc = ', usefrootc - write(iulog,*)'ch4offline = ', ch4offline + write(iulog,*)'allowlakeprod = ', allowlakeprod + write(iulog,*)'usephfact = ', usephfact + write(iulog,*)'replenishlakec = ', replenishlakec + write(iulog,*)'finundation_method = ', finundation_method + write(iulog,*)'usefrootc = ', usefrootc + write(iulog,*)'ch4offline = ', ch4offline + write(iulog,*)'use_aereoxid_prog = ', use_aereoxid_prog if (ch4offline) write(iulog,*)'CH4 Model will be running offline and not affect fluxes to atmosphere' - write(iulog,*)'use_aereoxid_prog = ', use_aereoxid_prog if ( .not. use_aereoxid_prog ) then write(iulog,*) 'Aerenchyma oxidation (aereoxid) value is being read from '//& ' the parameters file' diff --git a/src/biogeochem/dynConsBiogeochemMod.F90 b/src/biogeochem/dynConsBiogeochemMod.F90 index b16574683f..e233653ca7 100644 --- a/src/biogeochem/dynConsBiogeochemMod.F90 +++ b/src/biogeochem/dynConsBiogeochemMod.F90 @@ -586,6 +586,36 @@ subroutine dyn_cnbal_patch(bounds, & end do + + ! calculate patch-to-column slash fluxes into litter and CWD pools + do p = bounds%begp, bounds%endp + c = patch%column(p) + + ! fine and coarse root to litter and CWD slash carbon fluxes + cnveg_carbonflux_inst%dwt_slash_cflux_col(c) = & + cnveg_carbonflux_inst%dwt_slash_cflux_col(c) + & + dwt_frootc_to_litter(p)/dt + & + dwt_livecrootc_to_litter(p)/dt + & + dwt_deadcrootc_to_litter(p)/dt + + if ( use_c13 ) then + c13_cnveg_carbonflux_inst%dwt_slash_cflux_col(c) = & + c13_cnveg_carbonflux_inst%dwt_slash_cflux_col(c) + & + dwt_frootc13_to_litter(p)/dt + & + dwt_livecrootc13_to_litter(p)/dt + & + dwt_deadcrootc13_to_litter(p)/dt + endif + + if ( use_c14 ) then + c14_cnveg_carbonflux_inst%dwt_slash_cflux_col(c) = & + c14_cnveg_carbonflux_inst%dwt_slash_cflux_col(c) + & + dwt_frootc14_to_litter(p)/dt + & + dwt_livecrootc14_to_litter(p)/dt + & + dwt_deadcrootc14_to_litter(p)/dt + endif + + end do + ! calculate patch-to-column for fluxes into litter and CWD pools do j = 1, nlevdecomp @@ -801,7 +831,7 @@ subroutine dyn_cnbal_patch(bounds, & end subroutine dyn_cnbal_patch !----------------------------------------------------------------------- - subroutine dyn_cnbal_col(bounds, column_state_updater, & + subroutine dyn_cnbal_col(bounds, clump_index, column_state_updater, & soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst, & ch4_inst) @@ -815,6 +845,11 @@ subroutine dyn_cnbal_col(bounds, column_state_updater, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer , intent(in) :: clump_index + type(column_state_updater_type) , intent(in) :: column_state_updater type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst type(soilbiogeochem_carbonstate_type) , intent(inout) :: c13_soilbiogeochem_carbonstate_inst @@ -827,21 +862,22 @@ subroutine dyn_cnbal_col(bounds, column_state_updater, & character(len=*), parameter :: subname = 'dyn_cnbal_col' !----------------------------------------------------------------------- - call soilbiogeochem_carbonstate_inst%DynamicColumnAdjustments(bounds, & + call soilbiogeochem_carbonstate_inst%DynamicColumnAdjustments(bounds, clump_index, & column_state_updater) if (use_c13) then - call c13_soilbiogeochem_carbonstate_inst%DynamicColumnAdjustments(bounds, & + call c13_soilbiogeochem_carbonstate_inst%DynamicColumnAdjustments(bounds, clump_index, & column_state_updater) end if if (use_c14) then - call c14_soilbiogeochem_carbonstate_inst%DynamicColumnAdjustments(bounds, & + call c14_soilbiogeochem_carbonstate_inst%DynamicColumnAdjustments(bounds, clump_index, & column_state_updater) end if - call soilbiogeochem_nitrogenstate_inst%DynamicColumnAdjustments(bounds, column_state_updater) + call soilbiogeochem_nitrogenstate_inst%DynamicColumnAdjustments(bounds, clump_index, & + column_state_updater) if (use_lch4) then - call ch4_inst%DynamicColumnAdjustments(bounds, column_state_updater) + call ch4_inst%DynamicColumnAdjustments(bounds, clump_index, column_state_updater) end if end subroutine dyn_cnbal_col diff --git a/src/biogeochem/dynHarvestMod.F90 b/src/biogeochem/dynHarvestMod.F90 index aa7a4240b6..a9344fd5cf 100644 --- a/src/biogeochem/dynHarvestMod.F90 +++ b/src/biogeochem/dynHarvestMod.F90 @@ -51,7 +51,8 @@ module dynHarvestMod real(r8) , allocatable :: harvest(:) ! harvest rates logical :: do_harvest ! whether we're in a period when we should do harvest - character(len=64) :: harvest_units ! units from harvest variables + character(len=*), parameter :: string_not_set = "not_set" ! string to initialize with to indicate string wasn't set + character(len=64) :: harvest_units = string_not_set ! units from harvest variables character(len=*), parameter, private :: sourcefile = & __FILE__ !--------------------------------------------------------------------------- @@ -77,6 +78,7 @@ subroutine dynHarvest_init(bounds, harvest_filename) integer :: varnum ! counter for harvest variables integer :: num_points ! number of spatial points integer :: ier ! error code + character(len=64) :: units = string_not_set character(len=*), parameter :: subname = 'dynHarvest_init' !----------------------------------------------------------------------- @@ -100,7 +102,20 @@ subroutine dynHarvest_init(bounds, harvest_filename) dyn_file=dynHarvest_file, varname=harvest_varnames(varnum), & dim1name=grlnd, conversion_factor=1.0_r8, & do_check_sums_equal_1=.false., data_shape=[num_points]) - call harvest_inst(varnum)%get_att("units",harvest_units) + call harvest_inst(varnum)%get_att("units",units) + if ( trim(units) == string_not_set ) then + units = "unitless" + else if ( trim(units) == "unitless" ) then + + else if ( trim(units) /= "gC/m2/yr" ) then + call endrun(msg=' bad units read in from file='//trim(units)//errMsg(sourcefile, __LINE__)) + end if + if ( varnum > 1 .and. trim(units) /= trim(harvest_units) )then + call endrun(msg=' harvest units are inconsitent on file ='// & + trim(harvest_filename)//errMsg(sourcefile, __LINE__)) + end if + harvest_units = units + units = string_not_set end do end subroutine dynHarvest_init @@ -186,9 +201,8 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & integer :: p ! patch index integer :: g ! gridcell index integer :: fp ! patch filter index -!KO + real(r8):: thistreec ! carbon in this tree for calculating harvest fraction (gC/m2) real(r8):: cm ! rate for carbon harvest mortality (gC/m2/yr) -!KO real(r8):: am ! rate for fractional harvest mortality (1/yr) real(r8):: m ! rate for fractional harvest mortality (1/s) real(r8):: dtime ! model time step (s) @@ -296,9 +310,10 @@ subroutine CNHarvest (num_soilc, filter_soilc, num_soilp, filter_soilp, & if (do_harvest) then if (harvest_units == "gC/m2/yr") then + thistreec = leafc(p) + frootc(p) + livestemc(p) + deadstemc(p) + livecrootc(p) + deadcrootc(p) + xsmrpool(p) cm = harvest(g) - if (deadstemc(p) > 0.0_r8) then - am = min(1._r8,cm/deadstemc(p)) + if (thistreec > 0.0_r8) then + am = min(0.98_r8,cm/thistreec) ! Only harvest up to 98% so regrowth is possible PJL else am = 0._r8 end if diff --git a/src/biogeophys/AerosolMod.F90 b/src/biogeophys/AerosolMod.F90 index 705ca68036..e45aad41ab 100644 --- a/src/biogeophys/AerosolMod.F90 +++ b/src/biogeophys/AerosolMod.F90 @@ -13,6 +13,7 @@ module AerosolMod use WaterfluxType , only : waterflux_type use WaterstateType , only : waterstate_type use ColumnType , only : col + use abortutils , only : endrun ! ! !PUBLIC TYPES: implicit none @@ -23,7 +24,8 @@ module AerosolMod public :: AerosolFluxes ! ! !PUBLIC DATA MEMBERS: - real(r8), public, parameter :: snw_rds_min = 54.526_r8 ! minimum allowed snow effective radius (also "fresh snow" value) [microns + real(r8), public, parameter :: snw_rds_min = 54.526_r8 ! minimum allowed snow effective radius (also cold "fresh snow" value) [microns] + real(r8), public :: fresh_snw_rds_max = 204.526_r8 ! maximum warm fresh snow effective radius [microns] ! type, public :: aerosol_type real(r8), pointer, public :: mss_bcpho_col(:,:) ! mass of hydrophobic BC in snow (col,lyr) [kg] @@ -88,6 +90,7 @@ module AerosolMod procedure, private :: InitAllocate procedure, private :: InitHistory procedure, private :: InitCold + procedure, private :: InitReadNML end type aerosol_type @@ -98,14 +101,16 @@ module AerosolMod contains !------------------------------------------------------------------------ - subroutine Init(this, bounds) + subroutine Init(this, bounds, NLFilename) class(aerosol_type) :: this type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Input namelist filename call this%InitAllocate(bounds) call this%InitHistory(bounds) call this%InitCold(bounds) + call this%InitReadNML(NLFilename) end subroutine Init @@ -285,6 +290,58 @@ subroutine InitCold(this, bounds) end subroutine InitCold + !----------------------------------------------------------------------- + subroutine InitReadNML(this, NLFilename) + ! + ! !USES: + ! !USES: + use fileutils , only : getavu, relavu, opnfil + use shr_nl_mod , only : shr_nl_find_group_name + use spmdMod , only : masterproc, mpicom + use shr_mpi_mod , only : shr_mpi_bcast + use clm_varctl , only : iulog + ! + ! !ARGUMENTS: + class(aerosol_type) :: this + character(len=*), intent(in) :: NLFilename ! Input namelist filename + ! + ! !LOCAL VARIABLES: + !----------------------------------------------------------------------- + integer :: ierr ! error code + integer :: unitn ! unit for namelist file + + character(len=*), parameter :: subname = 'Aerosol::InitReadNML' + character(len=*), parameter :: nmlname = 'aerosol' + !----------------------------------------------------------------------- + namelist/aerosol/ fresh_snw_rds_max + + if (masterproc) then + unitn = getavu() + write(iulog,*) 'Read in '//nmlname//' namelist' + call opnfil (NLFilename, unitn, 'F') + call shr_nl_find_group_name(unitn, nmlname, status=ierr) + if (ierr == 0) then + read(unitn, nml=aerosol, iostat=ierr) + if (ierr /= 0) then + call endrun(msg="ERROR reading "//nmlname//" namelist "//errmsg(sourcefile, __LINE__)) + end if + else + call endrun(msg="ERROR could NOT find "//nmlname//" namelist "//errmsg(sourcefile, __LINE__)) + end if + call relavu( unitn ) + end if + + call shr_mpi_bcast (fresh_snw_rds_max , mpicom) + + if (masterproc) then + write(iulog,*) ' ' + write(iulog,*) nmlname//' settings:' + write(iulog,nml=aerosol) + write(iulog,*) ' ' + end if + + end subroutine InitReadNML + !------------------------------------------------------------------------ subroutine Restart(this, bounds, ncid, flag, & h2osoi_ice_col, h2osoi_liq_col) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 9731e39e0d..5a2876dbc9 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -5,12 +5,14 @@ module BalanceCheckMod ! Water and energy balance check. ! ! !USES: +#include "shr_assert.h" use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use abortutils , only : endrun use clm_varctl , only : iulog use clm_varcon , only : namep, namec + use clm_varpar , only : nlevsoi use GetGlobalValuesMod , only : GetGlobalIndex use atm2lndType , only : atm2lnd_type use EnergyFluxType , only : energyflux_type @@ -20,18 +22,24 @@ module BalanceCheckMod use WaterfluxType , only : waterflux_type use IrrigationMod , only : irrigation_type use GlacierSurfaceMassBalanceMod, only : glacier_smb_type + use TotalWaterAndHeatMod, only : ComputeWaterMassNonLake, ComputeWaterMassLake use GridcellType , only : grc use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch + use landunit_varcon , only : istdlak, istsoil,istcrop,istwet,istice_mec + use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall + use column_varcon , only : icol_road_perv, icol_road_imperv + use clm_varcon , only : aquifer_water_baseline ! ! !PUBLIC TYPES: implicit none save ! ! !PUBLIC MEMBER FUNCTIONS: - public :: BeginWaterBalance ! Initialize water balance check - public :: BalanceCheck ! Water and energy balance check + + public :: BeginWaterBalance ! Initialize water balance check + public :: BalanceCheck ! Water and energy balance check character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -42,92 +50,49 @@ module BalanceCheckMod !----------------------------------------------------------------------- subroutine BeginWaterBalance(bounds, & num_nolakec, filter_nolakec, num_lakec, filter_lakec, & - num_hydrologyc, filter_hydrologyc, & soilhydrology_inst, waterstate_inst) ! ! !DESCRIPTION: ! Initialize column-level water balance at beginning of time step ! - ! !USES: - use subgridAveMod , only : p2c - use clm_varpar , only : nlevgrnd, nlevsoi, nlevurb - use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall - use column_varcon , only : icol_road_perv, icol_road_imperv - ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_nolakec ! number of column non-lake points in column filter integer , intent(in) :: filter_nolakec(:) ! column filter for non-lake points - integer , intent(in) :: num_lakec ! number of column non-lake points in column filter - integer , intent(in) :: filter_lakec(:) ! column filter for non-lake points - integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter - integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points + integer , intent(in) :: num_lakec ! number of column lake points in column filter + integer , intent(in) :: filter_lakec(:) ! column filter for lake points type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(waterstate_type) , intent(inout) :: waterstate_inst ! ! !LOCAL VARIABLES: - integer :: c, p, f, j, fc ! indices - real(r8):: h2osoi_vol + integer :: c, j, fc ! indices !----------------------------------------------------------------------- associate( & zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) - - h2ocan_patch => waterstate_inst%h2ocan_patch , & ! Input: [real(r8) (:) ] canopy water (mm H2O) (patch-level) - h2osfc => waterstate_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) - h2osno => waterstate_inst%h2osno_col , & ! Input: [real(r8) (:) ] snow water (mm H2O) - h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) - h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) - zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) wa => soilhydrology_inst%wa_col , & ! Output: [real(r8) (:) ] water in the unconfined aquifer (mm) - h2ocan_col => waterstate_inst%h2ocan_col , & ! Output: [real(r8) (:) ] canopy water (mm H2O) (column level) begwb => waterstate_inst%begwb_col & ! Output: [real(r8) (:) ] water mass begining of the time step ) - ! Determine beginning water balance for time step - ! patch-level canopy water averaged to column - - call p2c(bounds, num_nolakec, filter_nolakec, & - h2ocan_patch(bounds%begp:bounds%endp), & - h2ocan_col(bounds%begc:bounds%endc)) - - do f = 1, num_hydrologyc - c = filter_hydrologyc(f) - if(zwt(c) <= zi(c,nlevsoi)) then - wa(c) = 5000._r8 - end if - end do - - do f = 1, num_nolakec - c = filter_nolakec(f) - if (col%itype(c) == icol_roof .or. col%itype(c) == icol_sunwall & - .or. col%itype(c) == icol_shadewall .or. col%itype(c) == icol_road_imperv) then - begwb(c) = h2ocan_col(c) + h2osno(c) - else - begwb(c) = h2ocan_col(c) + h2osno(c) + h2osfc(c) + wa(c) - end if - - end do - do j = 1, nlevgrnd - do f = 1, num_nolakec - c = filter_nolakec(f) - if ((col%itype(c) == icol_sunwall .or. col%itype(c) == icol_shadewall & - .or. col%itype(c) == icol_roof) .and. j > nlevurb) then - else - begwb(c) = begwb(c) + h2osoi_ice(c,j) + h2osoi_liq(c,j) - end if - end do - end do - - do f = 1, num_lakec - c = filter_lakec(f) - begwb(c) = h2osno(c) - end do + do fc = 1, num_nolakec + c = filter_nolakec(fc) + if (col%hydrologically_active(c)) then + if(zwt(c) <= zi(c,nlevsoi)) then + wa(c) = aquifer_water_baseline + end if + end if + end do + + call ComputeWaterMassNonLake(bounds, num_nolakec, filter_nolakec, & + soilhydrology_inst, waterstate_inst, begwb(bounds%begc:bounds%endc)) + + call ComputeWaterMassLake(bounds, num_lakec, filter_lakec, & + waterstate_inst, begwb(bounds%begc:bounds%endc)) end associate - end subroutine BeginWaterBalance + end subroutine BeginWaterBalance !----------------------------------------------------------------------- subroutine BalanceCheck( bounds, & @@ -150,12 +115,8 @@ subroutine BalanceCheck( bounds, & ! ! !USES: use clm_varcon , only : spval - use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall - use column_varcon , only : icol_road_perv, icol_road_imperv - use landunit_varcon , only : istdlak, istsoil,istcrop,istwet,istice,istice_mec - use clm_varctl , only : create_glacier_mec_landunit use clm_time_manager , only : get_step_size, get_nstep - use clm_initializeMod , only : surfalb_inst + use clm_instMod , only : surfalb_inst use CanopyStateType , only : canopystate_type use subgridAveMod ! @@ -197,18 +158,22 @@ subroutine BalanceCheck( bounds, & errh2o => waterstate_inst%errh2o_col , & ! Output: [real(r8) (:) ] water conservation error (mm H2O) errh2osno => waterstate_inst%errh2osno_col , & ! Output: [real(r8) (:) ] error in h2osno (kg m-2) endwb => waterstate_inst%endwb_col , & ! Output: [real(r8) (:) ] water mass end of the time step - + total_plant_stored_h2o_col => waterstate_inst%total_plant_stored_h2o_col, & ! Input: [real(r8) (:) ] water mass in plant tissues (kg m-2) + qflx_rootsoi_col => waterflux_inst%qflx_rootsoi_col , & ! Input [real(r8) (:) ] water loss in soil layers to root uptake (mm H2O/s) + ! (ie transpiration demand, often = transpiration) qflx_rain_grnd_col => waterflux_inst%qflx_rain_grnd_col , & ! Input: [real(r8) (:) ] rain on ground after interception (mm H2O/s) [+] qflx_snow_grnd_col => waterflux_inst%qflx_snow_grnd_col , & ! Input: [real(r8) (:) ] snow on ground after interception (mm H2O/s) [+] qflx_evap_soi => waterflux_inst%qflx_evap_soi_col , & ! Input: [real(r8) (:) ] soil evaporation (mm H2O/s) (+ = to atm) + qflx_snwcp_liq => waterflux_inst%qflx_snwcp_liq_col , & ! Input: [real(r8) (:) ] excess liquid h2o due to snow capping (outgoing) (mm H2O /s) [+]` qflx_snwcp_ice => waterflux_inst%qflx_snwcp_ice_col , & ! Input: [real(r8) (:) ] excess solid h2o due to snow capping (outgoing) (mm H2O /s) [+]` + qflx_snwcp_discarded_liq => waterflux_inst%qflx_snwcp_discarded_liq_col, & ! Input: [real(r8) (:) ] excess liquid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) [+]` + qflx_snwcp_discarded_ice => waterflux_inst%qflx_snwcp_discarded_ice_col, & ! Input: [real(r8) (:) ] excess solid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) [+]` qflx_evap_tot => waterflux_inst%qflx_evap_tot_col , & ! Input: [real(r8) (:) ] qflx_evap_soi + qflx_evap_can + qflx_tran_veg qflx_dew_snow => waterflux_inst%qflx_dew_snow_col , & ! Input: [real(r8) (:) ] surface dew added to snow pack (mm H2O /s) [+] qflx_sub_snow => waterflux_inst%qflx_sub_snow_col , & ! Input: [real(r8) (:) ] sublimation rate from snow pack (mm H2O /s) [+] qflx_evap_grnd => waterflux_inst%qflx_evap_grnd_col , & ! Input: [real(r8) (:) ] ground surface evaporation rate (mm H2O/s) [+] qflx_dew_grnd => waterflux_inst%qflx_dew_grnd_col , & ! Input: [real(r8) (:) ] ground surface dew formation (mm H2O /s) [+] qflx_prec_grnd => waterflux_inst%qflx_prec_grnd_col , & ! Input: [real(r8) (:) ] water onto ground including canopy runoff [kg/(m2 s)] - qflx_snwcp_liq => waterflux_inst%qflx_snwcp_liq_col , & ! Input: [real(r8) (:) ] excess liquid h2o due to snow capping (outgoing) (mm H2O /s) [+]` qflx_snow_h2osfc => waterflux_inst%qflx_snow_h2osfc_col , & ! Input: [real(r8) (:) ] snow falling on surface water (mm/s) qflx_h2osfc_to_ice => waterflux_inst%qflx_h2osfc_to_ice_col , & ! Input: [real(r8) (:) ] conversion of h2osfc to ice qflx_drain_perched => waterflux_inst%qflx_drain_perched_col , & ! Input: [real(r8) (:) ] sub-surface runoff (mm H2O /s) @@ -310,7 +275,8 @@ subroutine BalanceCheck( bounds, & - qflx_drain_perched(c) & - qflx_ice_runoff_snwcp(c) & - qflx_ice_runoff_xs(c) & - ) * dtime + - qflx_snwcp_discarded_liq(c) & + - qflx_snwcp_discarded_ice(c)) * dtime else errh2o(c) = 0.0_r8 @@ -355,7 +321,10 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'qflx_drain = ',qflx_drain(indexc)*dtime write(iulog,*)'qflx_ice_runoff_snwcp = ',qflx_ice_runoff_snwcp(indexc)*dtime write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc)*dtime - + write(iulog,*)'qflx_snwcp_discarded_ice = ',qflx_snwcp_discarded_ice(indexc)*dtime + write(iulog,*)'qflx_snwcp_discarded_liq = ',qflx_snwcp_discarded_liq(indexc)*dtime + write(iulog,*)'qflx_rootsoi_col(1:nlevsoil) = ',qflx_rootsoi_col(indexc,:)*dtime + write(iulog,*)'total_plant_stored_h2o_col = ',total_plant_stored_h2o_col(indexc) write(iulog,*)'deltawb = ',endwb(indexc)-begwb(indexc) write(iulog,*)'deltawb/dtime = ',(endwb(indexc)-begwb(indexc))/dtime write(iulog,*)'deltaflux = ',forc_rain_col(indexc)+forc_snow_col(indexc) - (qflx_evap_tot(indexc) + & @@ -371,8 +340,10 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'errh2o = ',errh2o(indexc) write(iulog,*)'forc_rain = ',forc_rain_col(indexc)*dtime write(iulog,*)'forc_snow = ',forc_snow_col(indexc)*dtime + write(iulog,*)'total_plant_stored_h2o_col = ',total_plant_stored_h2o_col(indexc) write(iulog,*)'endwb = ',endwb(indexc) write(iulog,*)'begwb = ',begwb(indexc) + write(iulog,*)'qflx_evap_tot = ',qflx_evap_tot(indexc)*dtime write(iulog,*)'qflx_irrig = ',qflx_irrig(indexc)*dtime write(iulog,*)'qflx_surf = ',qflx_surf(indexc)*dtime @@ -384,8 +355,10 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'qflx_ice_runoff_snwcp = ',qflx_ice_runoff_snwcp(indexc)*dtime write(iulog,*)'qflx_ice_runoff_xs = ',qflx_ice_runoff_xs(indexc)*dtime write(iulog,*)'qflx_glcice_dyn_water_flux = ', qflx_glcice_dyn_water_flux(indexc)*dtime + write(iulog,*)'qflx_snwcp_discarded_ice = ',qflx_snwcp_discarded_ice(indexc)*dtime + write(iulog,*)'qflx_snwcp_discarded_liq = ',qflx_snwcp_discarded_liq(indexc)*dtime + write(iulog,*)'qflx_rootsoi_col(1:nlevsoil) = ',qflx_rootsoi_col(indexc,:)*dtime write(iulog,*)'cold/colu = ',col%cold(indexc),col%colu(indexc) - write(iulog,*)'clm model is stopping' call endrun(decomp_index=indexc, clmlevel=namec, msg=errmsg(sourcefile, __LINE__)) end if @@ -406,7 +379,9 @@ subroutine BalanceCheck( bounds, & if (col%snl(c) < 0) then snow_sources(c) = qflx_prec_grnd(c) + qflx_dew_snow(c) + qflx_dew_grnd(c) snow_sinks(c) = qflx_sub_snow(c) + qflx_evap_grnd(c) + qflx_snow_drain(c) & - + qflx_snwcp_ice(c) + qflx_snwcp_liq(c) + qflx_sl_top_soil(c) + + qflx_snwcp_ice(c) + qflx_snwcp_liq(c) & + + qflx_snwcp_discarded_ice(c) + qflx_snwcp_discarded_liq(c) & + + qflx_sl_top_soil(c) if (lun%itype(l) == istdlak) then snow_sources(c) = qflx_snow_grnd_col(c) & @@ -414,17 +389,19 @@ subroutine BalanceCheck( bounds, & + qflx_dew_snow(c) + qflx_dew_grnd(c) ) snow_sinks(c) = frac_sno_eff(c) * (qflx_sub_snow(c) + qflx_evap_grnd(c) ) & + qflx_snwcp_ice(c) + qflx_snwcp_liq(c) & + + qflx_snwcp_discarded_ice(c) + qflx_snwcp_discarded_liq(c) & + qflx_snow_drain(c) + qflx_sl_top_soil(c) endif if (col%itype(c) == icol_road_perv .or. lun%itype(l) == istsoil .or. & lun%itype(l) == istcrop .or. lun%itype(l) == istwet .or. & - lun%itype(l) == istice .or. lun%itype(l) == istice_mec) then + lun%itype(l) == istice_mec) then snow_sources(c) = (qflx_snow_grnd_col(c) - qflx_snow_h2osfc(c) ) & + frac_sno_eff(c) * (qflx_rain_grnd_col(c) & + qflx_dew_snow(c) + qflx_dew_grnd(c) ) + qflx_h2osfc_to_ice(c) snow_sinks(c) = frac_sno_eff(c) * (qflx_sub_snow(c) + qflx_evap_grnd(c)) & + qflx_snwcp_ice(c) + qflx_snwcp_liq(c) & + + qflx_snwcp_discarded_ice(c) + qflx_snwcp_discarded_liq(c) & + qflx_snow_drain(c) + qflx_sl_top_soil(c) endif @@ -478,6 +455,8 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'qflx_dew_grnd = ',qflx_dew_grnd(indexc)*dtime write(iulog,*)'qflx_snwcp_ice = ',qflx_snwcp_ice(indexc)*dtime write(iulog,*)'qflx_snwcp_liq = ',qflx_snwcp_liq(indexc)*dtime + write(iulog,*)'qflx_snwcp_discarded_ice = ',qflx_snwcp_discarded_ice(indexc)*dtime + write(iulog,*)'qflx_snwcp_discarded_liq = ',qflx_snwcp_discarded_liq(indexc)*dtime write(iulog,*)'qflx_sl_top_soil = ',qflx_sl_top_soil(indexc)*dtime write(iulog,*)'clm model is stopping' @@ -632,7 +611,7 @@ subroutine BalanceCheck( bounds, & found = .false. do c = bounds%begc,bounds%endc if (col%active(c)) then - if (abs(errsoi_col(c)) > 1.0e-6_r8 ) then + if (abs(errsoi_col(c)) > 1.0e-5_r8 ) then found = .true. indexc = c end if diff --git a/src/biogeophys/BareGroundFluxesMod.F90 b/src/biogeophys/BareGroundFluxesMod.F90 index 2e0262719a..cfbc99b740 100644 --- a/src/biogeophys/BareGroundFluxesMod.F90 +++ b/src/biogeophys/BareGroundFluxesMod.F90 @@ -208,9 +208,9 @@ subroutine BareGroundFluxes(bounds, num_noexposedvegp, filter_noexposedvegp, & ram1 => frictionvel_inst%ram1_patch , & ! Output: [real(r8) (:) ] aerodynamical resistance (s/m) htvp => energyflux_inst%htvp_col , & ! Input: [real(r8) (:) ] latent heat of evaporation (/sublimation) [J/kg] - qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! Output: [real(r8) (:) ] evaporation flux from snow (W/m**2) [+ to atm] - qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! Output: [real(r8) (:) ] evaporation flux from soil (W/m**2) [+ to atm] - qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! Output: [real(r8) (:) ] evaporation flux from h2osfc (W/m**2) [+ to atm] + qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! Output: [real(r8) (:) ] evaporation flux from snow (mm H2O/s) [+ to atm] + qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! Output: [real(r8) (:) ] evaporation flux from soil (mm H2O/s) [+ to atm] + qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! Output: [real(r8) (:) ] evaporation flux from h2osfc (mm H2O/s) [+ to atm] qflx_evap_soi => waterflux_inst%qflx_evap_soi_patch , & ! Output: [real(r8) (:) ] soil evaporation (mm H2O/s) (+ = to atm) qflx_evap_tot => waterflux_inst%qflx_evap_tot_patch , & ! Output: [real(r8) (:) ] qflx_evap_soi + qflx_evap_can + qflx_tran_veg diff --git a/src/biogeophys/CMakeLists.txt b/src/biogeophys/CMakeLists.txt index e915762c44..55ad7e1c65 100644 --- a/src/biogeophys/CMakeLists.txt +++ b/src/biogeophys/CMakeLists.txt @@ -12,9 +12,12 @@ list(APPEND clm_sources RootBiophysMod.F90 SnowHydrologyMod.F90 SnowSnicarMod.F90 + SoilHydrologyType.F90 SoilStateType.F90 SoilWaterRetentionCurveMod.F90 TemperatureType.F90 + TotalWaterAndHeatMod.F90 + UrbanParamsType.F90 WaterfluxType.F90 WaterStateType.F90 ) diff --git a/src/biogeophys/CanopyFluxesMod.F90 b/src/biogeophys/CanopyFluxesMod.F90 index 7adeed6627..7ddf8047b2 100644 --- a/src/biogeophys/CanopyFluxesMod.F90 +++ b/src/biogeophys/CanopyFluxesMod.F90 @@ -13,7 +13,7 @@ module CanopyFluxesMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun - use clm_varctl , only : iulog, use_cn, use_lch4, use_c13, use_c14, use_cndv, use_ed, & + use clm_varctl , only : iulog, use_cn, use_lch4, use_c13, use_c14, use_cndv, use_fates, & use_luna, use_hydrstress use clm_varpar , only : nlevgrnd, nlevsno use clm_varcon , only : namep @@ -422,8 +422,8 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, displa => canopystate_inst%displa_patch , & ! Input: [real(r8) (:) ] displacement height (m) htop => canopystate_inst%htop_patch , & ! Input: [real(r8) (:) ] canopy top(m) altmax_lastyear_indx => canopystate_inst%altmax_lastyear_indx_col , & ! Input: [integer (:) ] prior year maximum annual depth of thaw - altmax_indx => canopystate_inst%altmax_indx_col , & ! Input: [integer (:) ] maximum annual depth of thaw - rscanopy => canopystate_inst%rscanopy_patch , & ! Output: [real(r8) (:,:)] canopy resistance s/m (ED) + altmax_indx => canopystate_inst%altmax_indx_col , & ! Input: [integer (:) ] maximum annual depth of thaw + dleaf_patch => canopystate_inst%dleaf_patch , & ! Output: [real(r8) (:) ] mean leaf diameter for this patch/pft watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) (constant) watdry => soilstate_inst%watdry_col , & ! Input: [real(r8) (:,:) ] btran parameter for btran=0 (constant) @@ -480,9 +480,9 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, qflx_tran_veg => waterflux_inst%qflx_tran_veg_patch , & ! Output: [real(r8) (:) ] vegetation transpiration (mm H2O/s) (+ = to atm) qflx_evap_veg => waterflux_inst%qflx_evap_veg_patch , & ! Output: [real(r8) (:) ] vegetation evaporation (mm H2O/s) (+ = to atm) qflx_evap_soi => waterflux_inst%qflx_evap_soi_patch , & ! Output: [real(r8) (:) ] soil evaporation (mm H2O/s) (+ = to atm) - qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! Output: [real(r8) (:) ] evaporation flux from snow (W/m**2) [+ to atm] - qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! Output: [real(r8) (:) ] evaporation flux from soil (W/m**2) [+ to atm] - qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! Output: [real(r8) (:) ] evaporation flux from h2osfc (W/m**2) [+ to atm] + qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! Output: [real(r8) (:) ] evaporation flux from snow (mm H2O/s) [+ to atm] + qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! Output: [real(r8) (:) ] evaporation flux from soil (mm H2O/s) [+ to atm] + qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! Output: [real(r8) (:) ] evaporation flux from h2osfc (mm H2O/s) [+ to atm] rssun => photosyns_inst%rssun_patch , & ! Output: [real(r8) (:) ] leaf sunlit stomatal resistance (s/m) (output from Photosynthesis) rssha => photosyns_inst%rssha_patch , & ! Output: [real(r8) (:) ] leaf shaded stomatal resistance (s/m) (output from Photosynthesis) @@ -567,7 +567,9 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, ! frac_veg_nosno_patch > 0 ! ----------------------------------------------------------------- - call clm_fates%prep_canopyfluxes(nc, fn, filterp, photosyns_inst) + if (use_fates) then + call clm_fates%prep_canopyfluxes(nc, fn, filterp, photosyns_inst) + end if ! Initialize @@ -640,7 +642,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, ! values require knowledge of the belowground root structure. ! -------------------------------------------------------------------------- - if(use_ed)then + if(use_fates)then call clm_fates%wrap_btran(nc, fn, filterc_tmp(1:fn), soilstate_inst, waterstate_inst, & temperature_inst, energyflux_inst, soil_water_retention_curve) @@ -724,7 +726,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, end do if (found) then - if ( .not. use_ed ) then + if ( .not. use_fates ) then write(iulog,*)'Error: Forcing height is below canopy height for patch index ' call endrun(decomp_index=index, clmlevel=namep, msg=errmsg(sourcefile, __LINE__)) end if @@ -760,6 +762,10 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, temp1(begp:endp), temp2(begp:endp), temp12m(begp:endp), temp22m(begp:endp), fm(begp:endp), & frictionvel_inst) + + + + do f = 1, fn p = filterp(f) c = patch%column(p) @@ -777,7 +783,16 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, ! Bulk boundary layer resistance of leaves uaf(p) = um(p)*sqrt( 1._r8/(ram1(p)*um(p)) ) - cf = 0.01_r8/(sqrt(uaf(p))*sqrt(dleaf(patch%itype(p)))) + + ! Use pft parameter for leaf characteristic width + ! dleaf_patch if this is not an fates patch. + ! Otherwise, the value has already been loaded + ! during the FATES dynamics call + if(.not.patch%is_fates(p)) then + dleaf_patch(p) = dleaf(patch%itype(p)) + end if + + cf = 0.01_r8/(sqrt(uaf(p))*sqrt( dleaf_patch(p) )) rb(p) = 1._r8/(cf*uaf(p)) rb1(p) = rb(p) @@ -822,14 +837,14 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, rhaf(p) = eah(p)/svpts(p) end do - if ( use_ed ) then + if ( use_fates ) then call clm_fates%wrap_photosynthesis(nc, bounds, fn, filterp(1:fn), & svpts(begp:endp), eah(begp:endp), o2(begp:endp), & co2(begp:endp), rb(begp:endp), dayl_factor(begp:endp), & atm2lnd_inst, temperature_inst, canopystate_inst, photosyns_inst) - else ! not use_ed + else ! not use_fates if ( use_hydrstress ) then call PhotosynthesisHydraulicStress (bounds, fn, filterp, & @@ -866,7 +881,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, phase='sha') end if - end if ! end of if use_ed + end if ! end of if use_fates do f = 1, fn p = filterp(f) @@ -1248,75 +1263,79 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, end do - if ( use_ed ) then + if ( use_fates ) then + call clm_fates%wrap_accumulatefluxes(nc,fn,filterp(1:fn)) - end if - + call clm_fates%wrap_hydraulics_drive(bounds,nc,soilstate_inst, & + waterstate_inst,waterflux_inst,solarabs_inst,energyflux_inst) - ! Determine total photosynthesis - - call PhotosynthesisTotal(fn, filterp, & - atm2lnd_inst, canopystate_inst, photosyns_inst) + else - ! Calculate ozone stress. This needs to be done after rssun and rsshade are - ! computed by the Photosynthesis routine. However, Photosynthesis also uses the - ! ozone stress computed here. Thus, the ozone stress computed in timestep i is - ! applied in timestep (i+1). - - ! COMPILER_BUG(wjs, 2014-11-29, pgi 14.7) The following dummy variable assignment is - ! needed with pgi 14.7 on yellowstone; without it, forc_pbot_downscaled_col gets - ! resized inappropriately in the following subroutine call, due to a compiler bug. - dummy_to_make_pgi_happy = ubound(atm2lnd_inst%forc_pbot_downscaled_col, 1) - call ozone_inst%CalcOzoneStress( & - bounds, fn, filterp, & - forc_pbot = atm2lnd_inst%forc_pbot_downscaled_col(bounds%begc:bounds%endc), & - forc_th = atm2lnd_inst%forc_th_downscaled_col(bounds%begc:bounds%endc), & - rssun = photosyns_inst%rssun_patch(bounds%begp:bounds%endp), & - rssha = photosyns_inst%rssha_patch(bounds%begp:bounds%endp), & - rb = frictionvel_inst%rb1_patch(bounds%begp:bounds%endp), & - ram = frictionvel_inst%ram1_patch(bounds%begp:bounds%endp), & - tlai = canopystate_inst%tlai_patch(bounds%begp:bounds%endp)) - - !--------------------------------------------------------- - !update Vc,max and Jmax by LUNA model - if(use_luna)then - call Acc24_Climate_LUNA(bounds, fn, filterp, & - canopystate_inst, photosyns_inst, & - surfalb_inst, solarabs_inst, & - temperature_inst) - - if(is_end_day)then - - call Acc240_Climate_LUNA(bounds, fn, filterp, & - o2(begp:endp), & - co2(begp:endp), & - rb(begp:endp), & - rhaf(begp:endp),& - temperature_inst, & - photosyns_inst, & - surfalb_inst, & - solarabs_inst, & - waterstate_inst,& - frictionvel_inst) - - call Update_Photosynthesis_Capacity(bounds, fn, filterp, & - dayl_factor(begp:endp), & - atm2lnd_inst, & - temperature_inst, & - canopystate_inst, & - photosyns_inst, & - surfalb_inst, & - solarabs_inst, & - waterstate_inst,& - frictionvel_inst) - - call Clear24_Climate_LUNA(bounds, fn, filterp, & - canopystate_inst, photosyns_inst, & - surfalb_inst, solarabs_inst, & - temperature_inst) - endif - - endif + ! Determine total photosynthesis + + call PhotosynthesisTotal(fn, filterp, & + atm2lnd_inst, canopystate_inst, photosyns_inst) + + ! Calculate ozone stress. This needs to be done after rssun and rsshade are + ! computed by the Photosynthesis routine. However, Photosynthesis also uses the + ! ozone stress computed here. Thus, the ozone stress computed in timestep i is + ! applied in timestep (i+1). + + ! COMPILER_BUG(wjs, 2014-11-29, pgi 14.7) The following dummy variable assignment is + ! needed with pgi 14.7 on yellowstone; without it, forc_pbot_downscaled_col gets + ! resized inappropriately in the following subroutine call, due to a compiler bug. + dummy_to_make_pgi_happy = ubound(atm2lnd_inst%forc_pbot_downscaled_col, 1) + call ozone_inst%CalcOzoneStress( & + bounds, fn, filterp, & + forc_pbot = atm2lnd_inst%forc_pbot_downscaled_col(bounds%begc:bounds%endc), & + forc_th = atm2lnd_inst%forc_th_downscaled_col(bounds%begc:bounds%endc), & + rssun = photosyns_inst%rssun_patch(bounds%begp:bounds%endp), & + rssha = photosyns_inst%rssha_patch(bounds%begp:bounds%endp), & + rb = frictionvel_inst%rb1_patch(bounds%begp:bounds%endp), & + ram = frictionvel_inst%ram1_patch(bounds%begp:bounds%endp), & + tlai = canopystate_inst%tlai_patch(bounds%begp:bounds%endp)) + + !--------------------------------------------------------- + !update Vc,max and Jmax by LUNA model + if(use_luna)then + call Acc24_Climate_LUNA(bounds, fn, filterp, & + canopystate_inst, photosyns_inst, & + surfalb_inst, solarabs_inst, & + temperature_inst) + + if(is_end_day)then + + call Acc240_Climate_LUNA(bounds, fn, filterp, & + o2(begp:endp), & + co2(begp:endp), & + rb(begp:endp), & + rhaf(begp:endp),& + temperature_inst, & + photosyns_inst, & + surfalb_inst, & + solarabs_inst, & + waterstate_inst,& + frictionvel_inst) + + call Update_Photosynthesis_Capacity(bounds, fn, filterp, & + dayl_factor(begp:endp), & + atm2lnd_inst, & + temperature_inst, & + canopystate_inst, & + photosyns_inst, & + surfalb_inst, & + solarabs_inst, & + waterstate_inst,& + frictionvel_inst) + + call Clear24_Climate_LUNA(bounds, fn, filterp, & + canopystate_inst, photosyns_inst, & + surfalb_inst, solarabs_inst, & + temperature_inst) + endif + + endif + end if ! Filter out patches which have small energy balance errors; report others diff --git a/src/biogeophys/CanopyHydrologyMod.F90 b/src/biogeophys/CanopyHydrologyMod.F90 index 099edeffba..b9c59e7cf5 100644 --- a/src/biogeophys/CanopyHydrologyMod.F90 +++ b/src/biogeophys/CanopyHydrologyMod.F90 @@ -157,7 +157,7 @@ subroutine CanopyHydrology(bounds, & ! !USES: use clm_varcon , only : hfus, denice, zlnd, rpi, spval, tfrz, int_snow_max use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall - use landunit_varcon , only : istcrop, istice, istwet, istsoil, istice_mec + use landunit_varcon , only : istcrop, istwet, istsoil, istice_mec use clm_varctl , only : subgridflag use clm_varpar , only : nlevsoi,nlevsno use clm_time_manager , only : get_step_size @@ -393,7 +393,7 @@ subroutine CanopyHydrology(bounds, & end if end if - else if (lun%itype(l)==istice .or. lun%itype(l)==istice_mec) then + else if (lun%itype(l)==istice_mec) then h2ocan(p) = 0._r8 qflx_candrip(p) = 0._r8 diff --git a/src/biogeophys/CanopyStateType.F90 b/src/biogeophys/CanopyStateType.F90 index 70282156db..4c1650c06d 100644 --- a/src/biogeophys/CanopyStateType.F90 +++ b/src/biogeophys/CanopyStateType.F90 @@ -10,7 +10,7 @@ module CanopyStateType use landunit_varcon , only : istsoil, istcrop use clm_varpar , only : nlevcan, nvegwcs use clm_varcon , only : spval - use clm_varctl , only : iulog, use_cn, use_ed, use_hydrstress + use clm_varctl , only : iulog, use_cn, use_fates, use_hydrstress use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch @@ -51,7 +51,8 @@ module CanopyStateType integer , pointer :: altmax_lastyear_indx_col (:) ! col prior year maximum annual depth of thaw real(r8) , pointer :: dewmx_patch (:) ! patch maximum allowed dew [mm] - + real(r8) , pointer :: dleaf_patch (:) ! patch characteristic leaf width (diameter) [m] + ! for non-ED/FATES this is the same as pftcon%dleaf() real(r8) , pointer :: rscanopy_patch (:) ! patch canopy stomatal resistance (s/m) (ED specific) real(r8) , pointer :: vegwp_patch (:,:) ! patch vegetation water matric potential (mm) @@ -141,7 +142,7 @@ subroutine InitAllocate(this, bounds) allocate(this%altmax_lastyear_indx_col (begc:endc)) ; this%altmax_lastyear_indx_col (:) = huge(1) allocate(this%dewmx_patch (begp:endp)) ; this%dewmx_patch (:) = nan - + allocate(this%dleaf_patch (begp:endp)) ; this%dleaf_patch (:) = nan allocate(this%rscanopy_patch (begp:endp)) ; this%rscanopy_patch (:) = nan ! allocate(this%gccanopy_patch (begp:endp)) ; this%gccanopy_patch (:) = 0.0_r8 allocate(this%vegwp_patch (begp:endp,1:nvegwcs)) ; this%vegwp_patch (:,:) = nan @@ -197,7 +198,7 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='shaded projected leaf area index', & ptr_patch=this%laisha_patch, set_urb=0._r8) - if (use_cn .or. use_ed) then + if (use_cn .or. use_fates) then this%fsun_patch(begp:endp) = spval call hist_addfld1d (fname='FSUN', units='proportion', & avgflag='A', long_name='sunlit fraction of canopy', & @@ -238,7 +239,7 @@ subroutine InitHistory(this, bounds) this%altmax_lastyear_col(begc:endc) = spval call hist_addfld1d (fname='ALTMAX_LASTYEAR', units='m', & avgflag='A', long_name='maximum prior year active layer thickness', & - ptr_col=this%altmax_lastyear_col) + ptr_col=this%altmax_lastyear_col, default='inactive') end if ! Allow active layer fields to be optionally output even if not running CN @@ -279,10 +280,12 @@ subroutine InitHistory(this, bounds) ptr_patch=this%elai240_patch, default='inactive') ! Ed specific field - this%rscanopy_patch(begp:endp) = spval - call hist_addfld1d (fname='RSCANOPY', units=' s m-1', & - avgflag='A', long_name='canopy resistance', & - ptr_patch=this%rscanopy_patch, set_lake=0._r8, set_urb=0._r8) + if ( use_fates ) then + this%rscanopy_patch(begp:endp) = spval + call hist_addfld1d (fname='RSCANOPY', units=' s m-1', & + avgflag='A', long_name='canopy resistance', & + ptr_patch=this%rscanopy_patch, set_lake=0._r8, set_urb=0._r8) + end if ! call hist_addfld1d (fname='GCCANOPY', units='none', & ! avgflag='A', long_name='Canopy Conductance: mmol m-2 s-1', & @@ -597,6 +600,7 @@ subroutine Restart(this, bounds, ncid, flag) call restartvar(ncid=ncid, flag=flag, varname='fsun', xtype=ncd_double, & dim1name='pft', long_name='sunlit fraction of canopy', units='', & interpinic_flag='interp', readvar=readvar, data=this%fsun_patch) + if (flag=='read' )then do p = bounds%begp,bounds%endp if (shr_infnan_isnan(this%fsun_patch(p)) ) then @@ -605,7 +609,7 @@ subroutine Restart(this, bounds, ncid, flag) end do end if - if (use_cn .or. use_ed) then + if (use_cn .or. use_fates) then call restartvar(ncid=ncid, flag=flag, varname='altmax', xtype=ncd_double, & dim1name='column', long_name='', units='', & interpinic_flag='interp', readvar=readvar, data=this%altmax_col) diff --git a/src/biogeophys/CanopyTemperatureMod.F90 b/src/biogeophys/CanopyTemperatureMod.F90 index b858e63184..97fc45884f 100644 --- a/src/biogeophys/CanopyTemperatureMod.F90 +++ b/src/biogeophys/CanopyTemperatureMod.F90 @@ -16,7 +16,7 @@ module CanopyTemperatureMod use shr_const_mod , only : SHR_CONST_PI use decompMod , only : bounds_type use abortutils , only : endrun - use clm_varctl , only : iulog + use clm_varctl , only : iulog, use_fates use PhotosynthesisMod , only : Photosynthesis, PhotosynthesisTotal, Fractionation use SurfaceResistanceMod , only : calc_soilevap_resis use pftconMod , only : pftcon @@ -45,8 +45,9 @@ module CanopyTemperatureMod !------------------------------------------------------------------------------ subroutine CanopyTemperature(bounds, & num_nolakec, filter_nolakec, num_nolakep, filter_nolakep, & + clm_fates, & atm2lnd_inst, canopystate_inst, soilstate_inst, frictionvel_inst, & - waterstate_inst, waterflux_inst, energyflux_inst, temperature_inst) + waterstate_inst, waterflux_inst, energyflux_inst, temperature_inst ) ! ! !DESCRIPTION: ! This is the main subroutine to execute the calculation of leaf temperature @@ -74,8 +75,11 @@ subroutine CanopyTemperature(bounds, & use clm_varcon , only : denh2o, denice, roverg, hvap, hsub, zlnd, zsno, tfrz, spval use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_imperv, icol_road_perv - use landunit_varcon , only : istice, istice_mec, istwet, istsoil, istdlak, istcrop, istdlak + use landunit_varcon , only : istice_mec, istwet, istsoil, istdlak, istcrop, istdlak use clm_varpar , only : nlevgrnd, nlevurb, nlevsno, nlevsoi + use clm_varctl , only : use_fates + use CLMFatesInterfaceMod, only : hlm_fates_interface_type + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -83,6 +87,7 @@ subroutine CanopyTemperature(bounds, & integer , intent(in) :: filter_nolakec(:) ! column filter for non-lake points integer , intent(in) :: num_nolakep ! number of column non-lake points in patch filter integer , intent(in) :: filter_nolakep(:) ! patch filter for non-lake points + type(hlm_fates_interface_type), intent(inout) :: clm_fates type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(canopystate_type) , intent(inout) :: canopystate_inst type(soilstate_type) , intent(inout) :: soilstate_inst @@ -245,8 +250,7 @@ subroutine CanopyTemperature(bounds, & ! Saturated vapor pressure, specific humidity and their derivatives ! at ground surface qred = 1._r8 - if (lun%itype(l)/=istwet .AND. lun%itype(l)/=istice & - .AND. lun%itype(l)/=istice_mec) then + if (lun%itype(l)/=istwet .AND. lun%itype(l)/=istice_mec) then if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then wx = (h2osoi_liq(c,1)/denh2o+h2osoi_ice(c,1)/denice)/dz(c,1) @@ -357,7 +361,7 @@ subroutine CanopyTemperature(bounds, & ! Urban emissivities are currently read in from data file if (.not. urbpoi(l)) then - if (lun%itype(l)==istice .or. lun%itype(l)==istice_mec) then + if (lun%itype(l)==istice_mec) then emg(c) = 0.97_r8 else emg(c) = (1._r8-frac_sno(c))*0.96_r8 + frac_sno(c)*0.97_r8 @@ -390,8 +394,25 @@ subroutine CanopyTemperature(bounds, & end do ! (end of columns loop) - ! Initialization + ! Set roughness and displacement + ! Note that FATES passes back z0m and displa at the end + ! of its dynamics call. If and when crops are + ! enabled simultaneously with FATES, we will + ! have to apply a filter here. + if(use_fates) then + call clm_fates%TransferZ0mDisp(bounds,frictionvel_inst,canopystate_inst) + end if + + do fp = 1,num_nolakep + p = filter_nolakep(fp) + if( .not.(patch%is_fates(p))) then + z0m(p) = z0mr(patch%itype(p)) * htop(p) + displa(p) = displar(patch%itype(p)) * htop(p) + end if + end do + + ! Initialization do fp = 1,num_nolakep p = filter_nolakep(fp) @@ -428,9 +449,6 @@ subroutine CanopyTemperature(bounds, & ! Roughness lengths over vegetation - z0m(p) = z0mr(patch%itype(p)) * htop(p) - displa(p) = displar(patch%itype(p)) * htop(p) - z0mv(p) = z0m(p) z0hv(p) = z0mv(p) z0qv(p) = z0mv(p) @@ -453,9 +471,7 @@ subroutine CanopyTemperature(bounds, & forc_hgt_t_patch(p) = forc_hgt_t(g) + z0m(p) + displa(p) forc_hgt_q_patch(p) = forc_hgt_q(g) + z0m(p) + displa(p) end if - - else if (lun%itype(l) == istwet .or. lun%itype(l) == istice & - .or. lun%itype(l) == istice_mec) then + else if (lun%itype(l) == istwet .or. lun%itype(l) == istice_mec) then forc_hgt_u_patch(p) = forc_hgt_u(g) + z0mg(c) forc_hgt_t_patch(p) = forc_hgt_t(g) + z0mg(c) forc_hgt_q_patch(p) = forc_hgt_q(g) + z0mg(c) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index 8f66eb086e..9a51987258 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -276,7 +276,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp) ! !USES: use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use clm_varpar , only : nlevsno, nlevgrnd - use clm_varctl , only : use_cn + use clm_varctl , only : use_cn, use_hydrstress use histFileMod , only : hist_addfld1d, hist_addfld2d, no_snow_normal use ncdio_pio , only : ncd_inqvdlen implicit none @@ -322,12 +322,12 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp) this%eflx_snomelt_r_col(begc:endc) = spval call hist_addfld1d (fname='FSM_R', units='W/m^2', & avgflag='A', long_name='Rural snow melt heat flux', & - ptr_col=this%eflx_snomelt_r_col, set_spec=spval) + ptr_col=this%eflx_snomelt_r_col, set_spec=spval, default='inactive') this%eflx_snomelt_u_col(begc:endc) = spval call hist_addfld1d (fname='FSM_U', units='W/m^2', & avgflag='A', long_name='Urban snow melt heat flux', & - ptr_col=this%eflx_snomelt_u_col, c2l_scale_type='urbanf', set_nourb=spval) + ptr_col=this%eflx_snomelt_u_col, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') this%eflx_lwrad_net_patch(begp:endp) = spval call hist_addfld1d (fname='FIRA', units='W/m^2', & @@ -450,12 +450,12 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp) this%eflx_soil_grnd_r_patch(begp:endp) = spval call hist_addfld1d (fname='FGR_R', units='W/m^2', & avgflag='A', long_name='Rural heat flux into soil/snow including snow melt and snow light transmission', & - ptr_patch=this%eflx_soil_grnd_r_patch, set_spec=spval) + ptr_patch=this%eflx_soil_grnd_r_patch, set_spec=spval, default='inactive') this%eflx_lwrad_net_u_patch(begp:endp) = spval call hist_addfld1d (fname='FIRA_U', units='W/m^2', & avgflag='A', long_name='Urban net infrared (longwave) radiation', & - ptr_patch=this%eflx_lwrad_net_u_patch, c2l_scale_type='urbanf', set_nourb=spval) + ptr_patch=this%eflx_lwrad_net_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') this%eflx_soil_grnd_patch(begp:endp) = spval call hist_addfld1d (fname='EFLX_SOIL_GRND', units='W/m^2', & @@ -465,12 +465,12 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp) this%eflx_lwrad_out_u_patch(begp:endp) = spval call hist_addfld1d (fname='FIRE_U', units='W/m^2', & avgflag='A', long_name='Urban emitted infrared (longwave) radiation', & - ptr_patch=this%eflx_lwrad_out_u_patch, c2l_scale_type='urbanf', set_nourb=spval) + ptr_patch=this%eflx_lwrad_out_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') this%eflx_sh_tot_u_patch(begp:endp) = spval call hist_addfld1d (fname='FSH_U', units='W/m^2', & avgflag='A', long_name='Urban sensible heat', & - ptr_patch=this%eflx_sh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval) + ptr_patch=this%eflx_sh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') this%eflx_sh_precip_conversion_col(begc:endc) = spval call hist_addfld1d (fname = 'FSH_PRECIP_CONVERSION', units='W/m^2', & @@ -480,12 +480,12 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp) this%eflx_lh_tot_u_patch(begp:endp) = spval call hist_addfld1d (fname='EFLX_LH_TOT_U', units='W/m^2', & avgflag='A', long_name='Urban total evaporation', & - ptr_patch=this%eflx_lh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval) + ptr_patch=this%eflx_lh_tot_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') this%eflx_soil_grnd_u_patch(begp:endp) = spval call hist_addfld1d (fname='FGR_U', units='W/m^2', & avgflag='A', long_name='Urban heat flux into soil/snow including snow melt', & - ptr_patch=this%eflx_soil_grnd_u_patch, c2l_scale_type='urbanf', set_nourb=spval) + ptr_patch=this%eflx_soil_grnd_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') this%netrad_patch(begp:endp) = spval call hist_addfld1d (fname='Rnet', units='W/m^2', & @@ -627,9 +627,12 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp) ptr_patch=this%tauy_patch) this%btran_patch(begp:endp) = spval - call hist_addfld1d (fname='BTRAN', units='unitless', & - avgflag='A', long_name='transpiration beta factor', & - ptr_patch=this%btran_patch, set_lake=spval, set_urb=spval) + if (.not. use_hydrstress) then + call hist_addfld1d (fname='BTRAN', units='unitless', & + avgflag='A', long_name='transpiration beta factor', & + ptr_patch=this%btran_patch, set_lake=spval, set_urb=spval) + end if + this%btran_min_patch(begp:endp) = spval call hist_addfld1d (fname='BTRANMN', units='unitless', & avgflag='A', long_name='daily minimum of transpiration beta factor', & @@ -811,14 +814,14 @@ subroutine Restart(this, bounds, ncid, flag, is_simple_buildtemp, is_prog_buildt ! don't read it (instead give it a default value). This is needed to support older initial ! conditions for which this variable had a different size (column-level). if (flag == 'read') then - call ncd_inqvdlen(ncid, 'URBAN_AC', 1, dimlen, err_code) + call ncd_inqvdlen(ncid, 'URBAN_AC_L', 1, dimlen, err_code) if (dimlen /= numl_global) then do_io = .false. readvar = .false. end if end if if (do_io) then - call restartvar(ncid=ncid, flag=flag, varname='URBAN_AC', xtype=ncd_double, & + call restartvar(ncid=ncid, flag=flag, varname='URBAN_AC_L', xtype=ncd_double, & dim1name='landunit',& long_name='urban air conditioning flux', units='watt/m^2', & interpinic_flag='interp', readvar=readvar, data=this%eflx_urban_ac_lun) @@ -831,14 +834,14 @@ subroutine Restart(this, bounds, ncid, flag, is_simple_buildtemp, is_prog_buildt ! don't read it (instead give it a default value). This is needed to support older initial ! conditions for which this variable had a different size (column-level). if (flag == 'read') then - call ncd_inqvdlen(ncid, 'URBAN_HEAT', 1, dimlen, err_code) + call ncd_inqvdlen(ncid, 'URBAN_HEAT_L', 1, dimlen, err_code) if (dimlen /= numl_global) then do_io = .false. readvar = .false. end if end if if (do_io) then - call restartvar(ncid=ncid, flag=flag, varname='URBAN_HEAT', xtype=ncd_double, & + call restartvar(ncid=ncid, flag=flag, varname='URBAN_HEAT_L', xtype=ncd_double, & dim1name='landunit',& long_name='urban heating flux', units='watt/m^2', & interpinic_flag='interp', readvar=readvar, data=this%eflx_urban_heat_lun) diff --git a/src/biogeophys/FrictionVelocityMod.F90 b/src/biogeophys/FrictionVelocityMod.F90 index b5df6e1c94..ce793aa9bc 100644 --- a/src/biogeophys/FrictionVelocityMod.F90 +++ b/src/biogeophys/FrictionVelocityMod.F90 @@ -182,12 +182,10 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='10-m wind (ice landunits only)', & ptr_patch=this%u10_clm_patch, l2g_scale_type='ice', default='inactive') - if (use_cn) then - this%u10_patch(begp:endp) = spval - call hist_addfld1d (fname='U10_DUST', units='m/s', & - avgflag='A', long_name='10-m wind for dust model', & - ptr_patch=this%u10_patch, default='inactive') - end if + this%u10_patch(begp:endp) = spval + call hist_addfld1d (fname='U10_DUST', units='m/s', & + avgflag='A', long_name='10-m wind for dust model', & + ptr_patch=this%u10_patch) if (use_cn) then this%ram1_patch(begp:endp) = spval diff --git a/src/biogeophys/GlacierSurfaceMassBalanceMod.F90 b/src/biogeophys/GlacierSurfaceMassBalanceMod.F90 index 5f1419cd1a..22cf2a3a56 100644 --- a/src/biogeophys/GlacierSurfaceMassBalanceMod.F90 +++ b/src/biogeophys/GlacierSurfaceMassBalanceMod.F90 @@ -107,7 +107,6 @@ end subroutine InitAllocate subroutine InitHistory(this, bounds) ! ! !USES: - use clm_varctl , only : create_glacier_mec_landunit, use_cn use histFileMod , only : hist_addfld1d ! ! !ARGUMENTS: @@ -120,26 +119,20 @@ subroutine InitHistory(this, bounds) begc = bounds%begc; endc = bounds%endc - if (create_glacier_mec_landunit) then - this%qflx_glcice_col(begc:endc) = spval - call hist_addfld1d (fname='QICE', units='mm/s', & - avgflag='A', long_name='ice growth/melt', & - ptr_col=this%qflx_glcice_col, l2g_scale_type='ice') - end if - - if (create_glacier_mec_landunit) then - this%qflx_glcice_frz_col(begc:endc) = spval - call hist_addfld1d (fname='QICE_FRZ', units='mm/s', & - avgflag='A', long_name='ice growth', & - ptr_col=this%qflx_glcice_frz_col, l2g_scale_type='ice') - end if - - if (create_glacier_mec_landunit) then - this%qflx_glcice_melt_col(begc:endc) = spval - call hist_addfld1d (fname='QICE_MELT', units='mm/s', & - avgflag='A', long_name='ice melt', & - ptr_col=this%qflx_glcice_melt_col, l2g_scale_type='ice') - end if + this%qflx_glcice_col(begc:endc) = spval + call hist_addfld1d (fname='QICE', units='mm/s', & + avgflag='A', long_name='ice growth/melt', & + ptr_col=this%qflx_glcice_col, l2g_scale_type='ice') + + this%qflx_glcice_frz_col(begc:endc) = spval + call hist_addfld1d (fname='QICE_FRZ', units='mm/s', & + avgflag='A', long_name='ice growth', & + ptr_col=this%qflx_glcice_frz_col, l2g_scale_type='ice') + + this%qflx_glcice_melt_col(begc:endc) = spval + call hist_addfld1d (fname='QICE_MELT', units='mm/s', & + avgflag='A', long_name='ice melt', & + ptr_col=this%qflx_glcice_melt_col, l2g_scale_type='ice') end subroutine InitHistory @@ -314,18 +307,18 @@ subroutine ComputeSurfaceMassBalance(this, bounds, num_allc, filter_allc, & qflx_glcice(c) = qflx_glcice_frz(c) - qflx_glcice_melt(c) - ! For glc_dyn_runoff_routing = T: - ! (1) Excess snow (from snow capping) has been incorporated in qflx_glcice_frz. - ! This flux must be included here to complete the water balance, because it is - ! a sink of water as far as CLM is concerned (this water will now be owned by - ! CISM). + ! For glc_dyn_runoff_routing > 0:: + ! (1) All or part of the excess snow (from snow capping) has been incorporated in + ! qflx_glcice_frz. This flux must be included here to complete the water + ! balance, because it is a sink of water as far as CLM is concerned (this water + ! will now be owned by CISM). ! (2) Meltwater from ice (qflx_glcice_melt) is allowed to run off and is included ! in qflx_qrgwl, but the water content of the ice column has not changed ! because an equivalent ice mass has been "borrowed" from the base of the ! column. So this borrowing is a source of water as far as CLM is concerned. - ! - ! For glc_dyn_runoff_routing = F: Point (2) is the same as for the - ! glc_dyn_runoff_routing = T case: there is a source of water equal to + ! + ! For glc_dyn_runoff_routing = 0: Point (2) is the same as for the + ! glc_dyn_runoff_routing > 0 case: there is a source of water equal to ! qflx_glcice_melt. However, in this case, the sink of water is also equal to ! qflx_glcice_melt: We have simply replaced some liquid water with an equal amount ! of solid ice. Another way to think about this is: @@ -338,9 +331,7 @@ subroutine ComputeSurfaceMassBalance(this, bounds, num_allc, filter_allc, & ! because an equivalent ice mass has been "borrowed" from the base of the ! column. So this borrowing is a source of water as far as CLM is concerned. ! These two corrections cancel out, so nothing is done here. - if (glc_dyn_runoff_routing(g)) then - qflx_glcice_dyn_water_flux(c) = qflx_glcice_melt(c) - qflx_glcice_frz(c) - end if + qflx_glcice_dyn_water_flux(c) = glc_dyn_runoff_routing(g) * (qflx_glcice_melt(c) - qflx_glcice_frz(c)) end do end associate @@ -380,7 +371,7 @@ subroutine AdjustRunoffTerms(this, bounds, num_do_smb_c, filter_do_smb_c, & associate( & qflx_glcice_frz => this%qflx_glcice_frz_col , & ! Input: [real(r8) (:)] ice growth (positive definite) (mm H2O/s) qflx_glcice_melt => this%qflx_glcice_melt_col , & ! Input: [real(r8) (:)] ice melt (positive definite) (mm H2O/s) - glc_dyn_runoff_routing => glc2lnd_inst%glc_dyn_runoff_routing_grc & ! Input: [real(r8) (:)] whether we're doing runoff routing appropriate for having a dynamic icesheet + glc_dyn_runoff_routing => glc2lnd_inst%glc_dyn_runoff_routing_grc & ! Input: [real(r8) (:)] gridcell fraction coupled to dynamic ice sheet ) ! Note that, because the following code only operates over the do_smb filter, that @@ -394,51 +385,64 @@ subroutine AdjustRunoffTerms(this, bounds, num_do_smb_c, filter_do_smb_c, & ! Melt is only generated for glacier columns. But it doesn't hurt to do this for ! all columns in the do_smb filter: this melt term will be 0 for other columns. + ! Note: Ice melt is added to the runoff whether or not the column is coupled + ! to a dynamic glacier model. + qflx_qrgwl(c) = qflx_qrgwl(c) + qflx_glcice_melt(c) - if (glc_dyn_runoff_routing(g)) then - ! In places where we are coupled to a dynamic glacier model, the glacier model - ! handles the fate of capped snow, so we do not want it sent to runoff. + ! For the part of the column that is coupled to a dynamic glacier model, + ! the glacier model handles the fate of capped snow, so we do not want it sent to runoff. + qflx_ice_runoff_snwcp(c) = qflx_ice_runoff_snwcp(c) - glc_dyn_runoff_routing(g)*qflx_glcice_frz(c) + + ! In places where we are not coupled to a dynamic glacier model, CLM sends all of + ! the snow capping to the ocean as an ice runoff term. (This is essentially a crude + ! parameterization of calving, assuming steady state - i.e., all ice gain is + ! balanced by an ice loss.) But each unit of melt that happens is an indication + ! that 1 unit of the ice shouldn't have made it to the ocean - but instead melted + ! before it got there. So we need to correct for that by removing 1 unit of ice + ! runoff for each unit of melt. Note that, for a given point in space & time, this + ! can result in negative ice runoff. However, we expect that, in a temporally and + ! spatially-integrated sense (if we're near equilibrium), this will just serve to + ! decrease the too-high positive ice runoff. + ! + ! Another way to think about this is: ice melt removes mass; the snow capping flux + ! also removes mass. If both the accumulation and melt remove mass, there is a + ! double-counting. So we need to correct that by: for each unit of ice melt + ! (resulting in 1 unit of liquid runoff), remove 1 unit of ice runoff. (This is not + ! an issue for parts of the column coupled to the dynamic glacier model, because + ! then the snow capping mass is retained in the LND-GLC coupled system.) + ! + ! The alternative of simply not adding ice melt to the runoff stream where + ! glc_dyn_runoff_routing = 0 conserves mass, but fails to conserve energy, for a + ! similar reason: Ice melt in CLM removes energy; also, the ocean's melting of the + ! snow capping flux removes energy. If both the accumulation and melting remove + ! energy, there is a double-counting. + ! + ! Yet another way to think about this is: When ice melted, we let the liquid run + ! off, and replaced it with new ice from below. But that new ice needed to come + ! from somewhere to keep the system in water balance. We "request" the new ice from + ! the ocean by generating a negataive ice runoff equivalent to the amount we have + ! melted (i.e., equivalent to the amount of new ice that we created from below). + + ! As above: Melt is only generated for glacier columns. But it doesn't hurt to do + ! this for all columns in the do_smb filter: this melt term will be 0 for other + ! columns. + + qflx_ice_runoff_snwcp(c) = qflx_ice_runoff_snwcp(c) - (1.0_r8 - glc_dyn_runoff_routing(g)) * qflx_glcice_melt(c) + + ! Recall that glc_dyn_runoff_routing = min(lfrac, Sg_icemask_coupled_fluxes_l) / lfrac. + ! + ! Consider a cell with lfrac = 0.8 and Sg_icemask_coupled_fluxes_l = 0.4. (For + ! instance, the cell might have half its land coverage in Greenland and the other + ! half in Ellemere.) Given qflx_ice_runoff_snwcp(c) = 1 m/yr, half the flux (0.5 + ! m/yr) will be sent to the runoff model, where it will be multiplied by lfrac to + ! give a net flux of 0.4 m/yr times the cell area. + ! + ! The full SMB of 1 m/yr will be sent to the coupler's prep_glc_mod, but it will be + ! weighted by 0.4 when integrating over the whole ice sheet. So a net flux of 0.4 + ! m/yr will also be applied to the ice sheet model. The total flux of 0.8 m/yr, + ! split evenly between runoff and ice sheet, is what we want. - qflx_ice_runoff_snwcp(c) = qflx_ice_runoff_snwcp(c) - qflx_glcice_frz(c) - else - ! In places where we are not coupled to a dynamic glacier model, CLM sends all - ! of the snow capping to the ocean as an ice runoff term. (This is essentially a - ! crude parameterization of calving, assuming steady state - i.e., all ice gain - ! is balanced by an ice loss.) But each unit of melt that happens is an - ! indication that 1 unit of the ice shouldn't have made it to the ocean - but - ! instead melted before it got there. So we need to correct for that by removing - ! 1 unit of ice runoff for each unit of melt. Note that, for a given point in - ! space & time, this can result in negative ice runoff. However, we expect that, - ! in a temporally and spatially-integrated sense (if we're near equilibrium), - ! this will just serve to decrease the too-high positive ice runoff. - ! - ! Another way to think about this is: ice melt removes mass; the snow capping - ! flux also removes mass. If both the accumulation and melt remove mass, there - ! is a double-counting. So we need to correct that by: for each unit of ice melt - ! (resulting in 1 unit of liquid runoff), remove 1 unit of ice runoff. (This is - ! not an issue in the case of glc_dyn_runoff_routing=T, because then the snow - ! capping mass is retained in the LND-GLC coupled system.) - ! - ! The alternative of simply not adding ice melt to the runoff stream if - ! glc_dyn_runoff_routing=F conserves mass, but fails to conserve energy, for a - ! similar reason: Ice melt in CLM removes energy; also, the ocean's melting of - ! the snow capping flux removes energy. If both the accumulation and melting - ! remove energy, there is a double-counting. - ! - ! Yet another way to think about this is: When ice melted, we let the liquid run - ! off, and replaced it with new ice from below. But that new ice needed to come - ! from somewhere to keep the system in water balance. We "request" the new ice - ! from the ocean by generating a negataive ice runoff equivalent to the amount - ! we have melted (i.e., equivalent to the amount of new ice that we created from - ! below). - - ! As above: Melt is only generated for glacier columns. But it doesn't hurt to - ! do this for all columns in the do_smb filter: this melt term will be 0 for - ! other columns. - - qflx_ice_runoff_snwcp(c) = qflx_ice_runoff_snwcp(c) - qflx_glcice_melt(c) - end if end do end associate diff --git a/src/biogeophys/HumanIndexMod.F90 b/src/biogeophys/HumanIndexMod.F90 index 5dc56b4baa..b2f3d8abff 100644 --- a/src/biogeophys/HumanIndexMod.F90 +++ b/src/biogeophys/HumanIndexMod.F90 @@ -253,17 +253,17 @@ subroutine InitHistory(this, bounds) this%appar_temp_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='APPAR_TEMP', units='C', & avgflag='A', long_name='2 m apparent temperature', & - ptr_patch=this%appar_temp_ref2m_patch) + ptr_patch=this%appar_temp_ref2m_patch, default='inactive') this%appar_temp_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='APPAR_TEMP_U', units='C', & avgflag='A', long_name='Urban 2 m apparent temperature', & - ptr_patch=this%appar_temp_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%appar_temp_ref2m_u_patch, set_nourb=spval, default='inactive') this%appar_temp_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='APPAR_TEMP_R', units='C', & avgflag='A', long_name='Rural 2 m apparent temperature', & - ptr_patch=this%appar_temp_ref2m_r_patch, set_spec=spval) + ptr_patch=this%appar_temp_ref2m_r_patch, set_spec=spval, default='inactive') this%swbgt_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='SWBGT', units='C', & @@ -313,77 +313,77 @@ subroutine InitHistory(this, bounds) this%wb_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='WBA', units='C', & avgflag='A', long_name='2 m Wet Bulb', & - ptr_patch=this%wb_ref2m_patch) + ptr_patch=this%wb_ref2m_patch, default='inactive') this%wb_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='WBA_U', units='C', & avgflag='A', long_name='Urban 2 m Wet Bulb', & - ptr_patch=this%wb_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%wb_ref2m_u_patch, set_nourb=spval, default='inactive') this%wb_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='WBA_R', units='C', & avgflag='A', long_name='Rural 2 m Wet Bulb', & - ptr_patch=this%wb_ref2m_r_patch, set_spec=spval) + ptr_patch=this%wb_ref2m_r_patch, set_spec=spval, default='inactive') this%teq_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='TEQ', units='K', & avgflag='A', long_name='2 m Equiv Temp', & - ptr_patch=this%teq_ref2m_patch) + ptr_patch=this%teq_ref2m_patch, default='inactive') this%teq_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='TEQ_U', units='K', & avgflag='A', long_name='Urban 2 m Equiv Temp', & - ptr_patch=this%teq_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%teq_ref2m_u_patch, set_nourb=spval, default='inactive') this%teq_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='TEQ_R', units='K', & avgflag='A', long_name='Rural 2 m Equiv Temp', & - ptr_patch=this%teq_ref2m_r_patch, set_spec=spval) + ptr_patch=this%teq_ref2m_r_patch, set_spec=spval, default='inactive') this%ept_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='EPT', units='K', & avgflag='A', long_name='2 m Equiv Pot Temp', & - ptr_patch=this%ept_ref2m_patch) + ptr_patch=this%ept_ref2m_patch, default='inactive') this%ept_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='EPT_U', units='K', & avgflag='A', long_name='Urban 2 m Equiv Pot Temp', & - ptr_patch=this%ept_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%ept_ref2m_u_patch, set_nourb=spval, default='inactive') this%ept_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='EPT_R', units='K', & avgflag='A', long_name='Rural 2 m Equiv Pot Temp', & - ptr_patch=this%ept_ref2m_r_patch, set_spec=spval) + ptr_patch=this%ept_ref2m_r_patch, set_spec=spval, default='inactive') this%discomf_index_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='DISCOI', units='C', & avgflag='A', long_name='2 m Discomfort Index', & - ptr_patch=this%discomf_index_ref2m_patch) + ptr_patch=this%discomf_index_ref2m_patch, default='inactive') this%discomf_index_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='DISCOI_U', units='C', & avgflag='A', long_name='Urban 2 m Discomfort Index', & - ptr_patch=this%discomf_index_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%discomf_index_ref2m_u_patch, set_nourb=spval, default='inactive') this%discomf_index_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='DISCOI_R', units='C', & avgflag='A', long_name='Rural 2 m Discomfort Index', & - ptr_patch=this%discomf_index_ref2m_r_patch, set_spec=spval) + ptr_patch=this%discomf_index_ref2m_r_patch, set_spec=spval, default='inactive') this%discomf_index_ref2mS_patch(begp:endp) = spval call hist_addfld1d (fname='DISCOIS', units='C', & avgflag='A', long_name='2 m Stull Discomfort Index', & - ptr_patch=this%discomf_index_ref2mS_patch) + ptr_patch=this%discomf_index_ref2mS_patch, default='inactive') this%discomf_index_ref2mS_u_patch(begp:endp) = spval call hist_addfld1d (fname='DISCOIS_U', units='C', & avgflag='A', long_name='Urban 2 m Stull Discomfort Index', & - ptr_patch=this%discomf_index_ref2mS_u_patch, set_nourb=spval) + ptr_patch=this%discomf_index_ref2mS_u_patch, set_nourb=spval, default='inactive') this%discomf_index_ref2mS_r_patch(begp:endp) = spval call hist_addfld1d (fname='DISCOIS_R', units='C', & avgflag='A', long_name='Rural 2 m Stull Discomfort Index', & - ptr_patch=this%discomf_index_ref2mS_r_patch, set_spec=spval) + ptr_patch=this%discomf_index_ref2mS_r_patch, set_spec=spval, default='inactive') this%nws_hi_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='HIA', units='C', & @@ -403,62 +403,62 @@ subroutine InitHistory(this, bounds) this%thip_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='THIP', units='C', & avgflag='A', long_name='2 m Temp Hum Index Physiology', & - ptr_patch=this%thip_ref2m_patch) + ptr_patch=this%thip_ref2m_patch, default='inactive') this%thip_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='THIP_U', units='C', & avgflag='A', long_name='Urban 2 m Temp Hum Index Physiology', & - ptr_patch=this%thip_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%thip_ref2m_u_patch, set_nourb=spval, default='inactive') this%thip_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='THIP_R', units='C', & avgflag='A', long_name='Rural 2 m Temp Hum Index Physiology', & - ptr_patch=this%thip_ref2m_r_patch, set_spec=spval) + ptr_patch=this%thip_ref2m_r_patch, set_spec=spval, default='inactive') this%thic_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='THIC', units='C', & avgflag='A', long_name='2 m Temp Hum Index Comfort', & - ptr_patch=this%thic_ref2m_patch) + ptr_patch=this%thic_ref2m_patch, default='inactive') this%thic_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='THIC_U', units='C', & avgflag='A', long_name='Urban 2 m Temp Hum Index Comfort', & - ptr_patch=this%thic_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%thic_ref2m_u_patch, set_nourb=spval, default='inactive') this%thic_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='THIC_R', units='C', & avgflag='A', long_name='Rural 2 m Temp Hum Index Comfort', & - ptr_patch=this%thic_ref2m_r_patch, set_spec=spval) + ptr_patch=this%thic_ref2m_r_patch, set_spec=spval, default='inactive') this%swmp65_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='SWMP65', units='C', & avgflag='A', long_name='2 m Swamp Cooler Temp 65% Eff', & - ptr_patch=this%swmp65_ref2m_patch) + ptr_patch=this%swmp65_ref2m_patch, default='inactive') this%swmp65_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='SWMP65_U', units='C', & avgflag='A', long_name='Urban 2 m Swamp Cooler Temp 65% Eff', & - ptr_patch=this%swmp65_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%swmp65_ref2m_u_patch, set_nourb=spval, default='inactive') this%swmp65_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='SWMP65_R', units='C', & avgflag='A', long_name='Rural 2 m Swamp Cooler Temp 65% Eff', & - ptr_patch=this%swmp65_ref2m_r_patch, set_spec=spval) + ptr_patch=this%swmp65_ref2m_r_patch, set_spec=spval, default='inactive') this%swmp80_ref2m_patch(begp:endp) = spval call hist_addfld1d (fname='SWMP80', units='C', & avgflag='A', long_name='2 m Swamp Cooler Temp 80% Eff', & - ptr_patch=this%swmp80_ref2m_patch) + ptr_patch=this%swmp80_ref2m_patch, default='inactive') this%swmp80_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='SWMP80_U', units='C', & avgflag='A', long_name='Urban 2 m Swamp Cooler Temp 80% Eff', & - ptr_patch=this%swmp80_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%swmp80_ref2m_u_patch, set_nourb=spval, default='inactive') this%swmp80_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='SWMP80_R', units='C', & avgflag='A', long_name='Rural 2 m Swamp Cooler Temp 80% Eff', & - ptr_patch=this%swmp80_ref2m_r_patch, set_spec=spval) + ptr_patch=this%swmp80_ref2m_r_patch, set_spec=spval, default='inactive') end subroutine InitHistory @@ -945,8 +945,8 @@ subroutine Wet_Bulb (Tin_1,vape,pin,relhum,qin,Teq,epott,wb_it) wb_it = wb_temp else wb_it = T1 - C ! Place Holder. wet bulb temperature same as dry bulb (C) - write(iulog,*) 'WARNING: Wet_Bulb algorithm failed to converge. Setting to T: WB, P, & - T, RH, Q, VaporP: ',wb_it, pin, T1, relhum, qin, vape + write(iulog,*) 'WARNING: Wet_Bulb algorithm failed to converge. Setting to T: WB, P, T, RH, Q, VaporP: ', & + wb_it, pin, T1, relhum, qin, vape endif end subroutine Wet_Bulb diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index b8b4696ff3..98299075b5 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -18,6 +18,7 @@ module HydrologyDrainageMod use WaterstateType , only : waterstate_type use IrrigationMod , only : irrigation_type use GlacierSurfaceMassBalanceMod, only : glacier_smb_type + use TotalWaterAndHeatMod, only : ComputeWaterMassNonLake use LandunitType , only : lun use ColumnType , only : col @@ -50,7 +51,7 @@ subroutine HydrologyDrainage(bounds, & ! Calculates soil/snow hydrology with drainage (subsurface runoff) ! ! !USES: - use landunit_varcon , only : istice, istwet, istsoil, istice_mec, istcrop + use landunit_varcon , only : istwet, istsoil, istice_mec, istcrop use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv, icol_sunwall, icol_shadewall use clm_varcon , only : denh2o, denice use clm_varctl , only : use_vichydro, use_hillslope @@ -91,40 +92,42 @@ subroutine HydrologyDrainage(bounds, & real(r8) :: dtime ! land model time step (sec) !----------------------------------------------------------------------- - - associate( & - dz => col%dz , & ! Input: [real(r8) (:,:) ] layer thickness depth (m) - ctype => col%itype , & ! Input: [integer (:) ] column type - - qflx_floodg => atm2lnd_inst%forc_flood_grc , & ! Input: [real(r8) (:) ] gridcell flux of flood water from RTM - forc_rain => atm2lnd_inst%forc_rain_downscaled_col , & ! Input: [real(r8) (:) ] rain rate [mm/s] - forc_snow => atm2lnd_inst%forc_snow_downscaled_col , & ! Input: [real(r8) (:) ] snow rate [mm/s] - wa => soilhydrology_inst%wa_col , & ! Input: [real(r8) (:) ] water in the unconfined aquifer (mm) - - h2ocan => waterstate_inst%h2ocan_col , & ! Input: [real(r8) (:) ] canopy water (mm H2O) - h2osfc => waterstate_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) - h2osno => waterstate_inst%h2osno_col , & ! Input: [real(r8) (:) ] snow water (mm H2O) - begwb => waterstate_inst%begwb_col , & ! Input: [real(r8) (:) ] water mass begining of the time step - endwb => waterstate_inst%endwb_col , & ! Output: [real(r8) (:) ] water mass end of the time step - h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) - h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) - h2osoi_vol => waterstate_inst%h2osoi_vol_col , & ! Output: [real(r8) (:,:) ] volumetric soil water (0<=h2osoi_vol<=watsat) [m3/m3] - - qflx_evap_tot => waterflux_inst%qflx_evap_tot_col , & ! Input: [real(r8) (:) ] qflx_evap_soi + qflx_evap_can + qflx_tran_veg - qflx_snwcp_ice => waterflux_inst%qflx_snwcp_ice_col , & ! Input: [real(r8) (:) ] excess solid h2o due to snow capping (outgoing) (mm H2O /s) [+]` - qflx_h2osfc_surf => waterflux_inst%qflx_h2osfc_surf_col , & ! Output: [real(r8) (:) ] surface water runoff (mm/s) - qflx_drain_perched => waterflux_inst%qflx_drain_perched_col , & ! Output: [real(r8) (:) ] sub-surface runoff from perched zwt (mm H2O /s) - qflx_rsub_sat => waterflux_inst%qflx_rsub_sat_col , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] - qflx_drain => waterflux_inst%qflx_drain_col , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) - qflx_surf => waterflux_inst%qflx_surf_col , & ! Output: [real(r8) (:) ] surface runoff (mm H2O /s) - qflx_infl => waterflux_inst%qflx_infl_col , & ! Output: [real(r8) (:) ] infiltration (mm H2O /s) - qflx_qrgwl => waterflux_inst%qflx_qrgwl_col , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes - qflx_runoff => waterflux_inst%qflx_runoff_col , & ! Output: [real(r8) (:) ] total runoff (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) - qflx_runoff_u => waterflux_inst%qflx_runoff_u_col , & ! Output: [real(r8) (:) ] Urban total runoff (qflx_drain+qflx_surf) (mm H2O /s) - qflx_runoff_r => waterflux_inst%qflx_runoff_r_col , & ! Output: [real(r8) (:) ] Rural total runoff (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) - qflx_ice_runoff_snwcp => waterflux_inst%qflx_ice_runoff_snwcp_col, & ! Output: [real(r8) (:)] solid runoff from snow capping (mm H2O /s) - qflx_irrig => irrigation_inst%qflx_irrig_col & ! Input: [real(r8) (:) ] irrigation flux (mm H2O /s) + associate( & ! Input: layer thickness depth (m) + dz => col%dz , & ! Input: column type + ctype => col%itype , & ! Input: gridcell flux of flood water from RTM + qflx_floodg => atm2lnd_inst%forc_flood_grc , & ! Input: rain rate [mm/s] + forc_rain => atm2lnd_inst%forc_rain_downscaled_col , & ! Input: snow rate [mm/s] + forc_snow => atm2lnd_inst%forc_snow_downscaled_col , & ! Input: water mass begining of the time step + begwb => waterstate_inst%begwb_col , & ! Output:water mass end of the time step + endwb => waterstate_inst%endwb_col , & ! Output:water mass end of the time step + h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Output: ice lens (kg/m2) + h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Output: liquid water (kg/m2) + h2osoi_vol => waterstate_inst%h2osoi_vol_col , & ! Output: volumetric soil water + ! (0<=h2osoi_vol<=watsat) [m3/m3] + qflx_evap_tot => waterflux_inst%qflx_evap_tot_col , & ! Input: qflx_evap_soi + qflx_evap_can + qflx_tran_veg + qflx_snwcp_ice => waterflux_inst%qflx_snwcp_ice_col , & ! Input: excess solid h2o due to snow + ! capping (outgoing) (mm H2O /s) [+] + qflx_snwcp_discarded_ice => waterflux_inst%qflx_snwcp_discarded_ice_col, & ! excess solid h2o due to snow capping, + ! which we simply discard in order to reset + ! the snow pack (mm H2O /s) [+] + qflx_snwcp_discarded_liq => waterflux_inst%qflx_snwcp_discarded_liq_col, & ! excess liquid h2o due to snow capping, + ! which we simply discard in order to reset + ! the snow pack (mm H2O /s) [+] + qflx_h2osfc_surf => waterflux_inst%qflx_h2osfc_surf_col , & ! surface water runoff (mm/s) + qflx_drain_perched => waterflux_inst%qflx_drain_perched_col , & ! sub-surface runoff from perched zwt (mm H2O /s) + qflx_rsub_sat => waterflux_inst%qflx_rsub_sat_col , & ! soil saturation excess [mm h2o/s] + qflx_drain => waterflux_inst%qflx_drain_col , & ! sub-surface runoff (mm H2O /s) + qflx_surf => waterflux_inst%qflx_surf_col , & ! surface runoff (mm H2O /s) + qflx_infl => waterflux_inst%qflx_infl_col , & ! infiltration (mm H2O /s) + qflx_qrgwl => waterflux_inst%qflx_qrgwl_col , & ! qflx_surf at glaciers, wetlands, lakes + qflx_runoff => waterflux_inst%qflx_runoff_col , & ! total runoff + ! (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) + qflx_runoff_u => waterflux_inst%qflx_runoff_u_col , & ! Urban total runoff (qflx_drain+qflx_surf) (mm H2O /s) + qflx_runoff_r => waterflux_inst%qflx_runoff_r_col , & ! Rural total runoff + ! (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) + qflx_ice_runoff_snwcp => waterflux_inst%qflx_ice_runoff_snwcp_col, & ! solid runoff from snow capping (mm H2O /s) + qflx_irrig => irrigation_inst%qflx_irrig_col & ! irrigation flux (mm H2O /s) ) ! Determine time step and step size @@ -178,31 +181,11 @@ subroutine HydrologyDrainage(bounds, & end do end do - do fc = 1, num_nolakec - c = filter_nolakec(fc) - l = col%landunit(c) - - if (ctype(c) == icol_roof .or. ctype(c) == icol_sunwall & - .or. ctype(c) == icol_shadewall .or. ctype(c) == icol_road_imperv) then - endwb(c) = h2ocan(c) + h2osno(c) - else - ! add h2osfc to water balance - endwb(c) = h2ocan(c) + h2osno(c) + h2osfc(c) + wa(c) - - end if - end do + call ComputeWaterMassNonLake(bounds, num_nolakec, filter_nolakec, & + soilhydrology_inst, waterstate_inst, endwb(bounds%begc:bounds%endc)) - do j = 1, nlevgrnd - do fc = 1, num_nolakec - c = filter_nolakec(fc) - if ((ctype(c) == icol_sunwall .or. ctype(c) == icol_shadewall & - .or. ctype(c) == icol_roof) .and. j > nlevurb) then - else - endwb(c) = endwb(c) + h2osoi_ice(c,j) + h2osoi_liq(c,j) - end if - end do - end do + ! Determine wetland and land ice hydrology (must be placed here ! since need snow updated from CombineSnowLayers) @@ -213,8 +196,7 @@ subroutine HydrologyDrainage(bounds, & l = col%landunit(c) g = col%gridcell(c) - if (lun%itype(l)==istwet .or. lun%itype(l)==istice & - .or. lun%itype(l)==istice_mec) then + if (lun%itype(l)==istwet .or. lun%itype(l)==istice_mec) then qflx_drain(c) = 0._r8 qflx_drain_perched(c) = 0._r8 @@ -222,6 +204,7 @@ subroutine HydrologyDrainage(bounds, & qflx_surf(c) = 0._r8 qflx_infl(c) = 0._r8 qflx_qrgwl(c) = forc_rain(c) + forc_snow(c) + qflx_floodg(g) - qflx_evap_tot(c) - qflx_snwcp_ice(c) - & + qflx_snwcp_discarded_ice(c) - qflx_snwcp_discarded_liq(c) - & (endwb(c)-begwb(c))/dtime else if (lun%urbpoi(l) .and. ctype(c) /= icol_road_perv) then @@ -262,6 +245,6 @@ subroutine HydrologyDrainage(bounds, & end associate - end subroutine HydrologyDrainage + end subroutine HydrologyDrainage end module HydrologyDrainageMod diff --git a/src/biogeophys/HydrologyNoDrainageMod.F90 b/src/biogeophys/HydrologyNoDrainageMod.F90 index 7eb6c0f3dc..5d9bdff771 100644 --- a/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -7,8 +7,9 @@ Module HydrologyNoDrainageMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type - use clm_varctl , only : iulog, use_vichydro + use clm_varctl , only : iulog, use_vichydro, use_fates use clm_varcon , only : e_ice, denh2o, denice, rpi, spval + use CLMFatesInterfaceMod, only : hlm_fates_interface_type use atm2lndType , only : atm2lnd_type use AerosolMod , only : aerosol_type use EnergyFluxType , only : energyflux_type @@ -20,6 +21,7 @@ Module HydrologyNoDrainageMod use CanopyStateType , only : canopystate_type use LandunitType , only : lun use ColumnType , only : col + use TopoMod, only : topo_type ! ! !PUBLIC TYPES: implicit none @@ -40,10 +42,11 @@ subroutine HydrologyNoDrainage(bounds, & num_urbanc, filter_urbanc, & num_snowc, filter_snowc, & num_nosnowc, filter_nosnowc, & + clm_fates, & atm2lnd_inst, soilstate_inst, energyflux_inst, temperature_inst, & waterflux_inst, waterstate_inst, & soilhydrology_inst, aerosol_inst, & - canopystate_inst, soil_water_retention_curve) + canopystate_inst, soil_water_retention_curve, topo_inst) ! ! !DESCRIPTION: ! This is the main subroutine to execute the calculation of soil/snow @@ -74,7 +77,8 @@ subroutine HydrologyNoDrainage(bounds, & use SoilWaterMovementMod , only : SoilWater use SoilWaterRetentionCurveMod, only : soil_water_retention_curve_type use SoilWaterMovementMod , only : use_aquifer_layer - + use SoilWaterPlantSinkMod , only : Compute_EffecRootFrac_And_VertTranSink + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -90,6 +94,7 @@ subroutine HydrologyNoDrainage(bounds, & integer , intent(inout) :: filter_nosnowc(:) ! column filter for non-snow points integer , intent(in) :: num_hillslope ! number of hillslope soil cols integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. + type(hlm_fates_interface_type), intent(inout) :: clm_fates type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(soilstate_type) , intent(inout) :: soilstate_inst @@ -101,6 +106,7 @@ subroutine HydrologyNoDrainage(bounds, & type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(canopystate_type) , intent(inout) :: canopystate_inst class(soil_water_retention_curve_type), intent(in) :: soil_water_retention_curve + class(topo_type) , intent(in) :: topo_inst ! ! !LOCAL VARIABLES: integer :: g,l,c,j,fc ! indices @@ -138,7 +144,6 @@ subroutine HydrologyNoDrainage(bounds, & snowdp => waterstate_inst%snowdp_col , & ! Input: [real(r8) (:) ] area-averaged snow height (m) frac_sno_eff => waterstate_inst%frac_sno_eff_col , & ! Input: [real(r8) (:) ] eff. snow cover fraction (col) [frc] frac_h2osfc => waterstate_inst%frac_h2osfc_col , & ! Input: [real(r8) (:) ] fraction of ground covered by surface water (0 to 1) - begwb => waterstate_inst%begwb_col , & ! Input: [real(r8) (:) ] water mass begining of the time step snw_rds => waterstate_inst%snw_rds_col , & ! Output: [real(r8) (:,:) ] effective snow grain radius (col,lyr) [microns, m^-6] snw_rds_top => waterstate_inst%snw_rds_top_col , & ! Output: [real(r8) (:) ] effective snow grain size, top layer(col) [microns] sno_liq_top => waterstate_inst%sno_liq_top_col , & ! Output: [real(r8) (:) ] liquid water fraction in top snow layer (col) [frc] @@ -148,6 +153,8 @@ subroutine HydrologyNoDrainage(bounds, & h2osoi_liqice_10cm => waterstate_inst%h2osoi_liqice_10cm_col , & ! Output: [real(r8) (:) ] liquid water + ice lens in top 10cm of soil (kg/m2) h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) + h2osoi_ice_tot => waterstate_inst%h2osoi_ice_tot_col , & ! Output: [real(r8) (:) ] vertically summed ice lens (kg/m2) + h2osoi_liq_tot => waterstate_inst%h2osoi_liq_tot_col , & ! Output: [real(r8) (:) ] vertically summed liquid water (kg/m2) h2osoi_vol => waterstate_inst%h2osoi_vol_col , & ! Output: [real(r8) (:,:) ] volumetric soil water (0<=h2osoi_vol<=watsat) [m3/m3] h2osno_top => waterstate_inst%h2osno_top_col , & ! Output: [real(r8) (:) ] mass of snow in top layer (col) [kg] wf => waterstate_inst%wf_col , & ! Output: [real(r8) (:) ] soil water as frac. of whc for top 0.05 m @@ -192,9 +199,14 @@ subroutine HydrologyNoDrainage(bounds, & energyflux_inst, soilhydrology_inst, soilstate_inst, & temperature_inst, waterflux_inst, waterstate_inst) + call Compute_EffecRootFrac_And_VertTranSink(bounds, num_hydrologyc, & + filter_hydrologyc, soilstate_inst, canopystate_inst, waterflux_inst, energyflux_inst) + + if ( use_fates ) call clm_fates%ComputeRootSoilFlux(bounds, num_hydrologyc, filter_hydrologyc, soilstate_inst, waterflux_inst) + call SoilWater(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filter_urbanc, & - soilhydrology_inst, soilstate_inst, waterflux_inst, waterstate_inst, temperature_inst, & - canopystate_inst, energyflux_inst, soil_water_retention_curve) + soilhydrology_inst, soilstate_inst, waterflux_inst, waterstate_inst, temperature_inst, & + canopystate_inst, energyflux_inst, soil_water_retention_curve) if (use_vichydro) then ! mapping soilmoist from CLM to VIC layers for runoff calculations @@ -224,7 +236,7 @@ subroutine HydrologyNoDrainage(bounds, & ! Snow capping call SnowCapping(bounds, num_nolakec, filter_nolakec, num_snowc, filter_snowc, & - aerosol_inst, waterflux_inst, waterstate_inst) + aerosol_inst, waterflux_inst, waterstate_inst, topo_inst) ! Natural compaction and metamorphosis. call SnowCompaction(bounds, num_snowc, filter_snowc, & @@ -304,6 +316,8 @@ subroutine HydrologyNoDrainage(bounds, & t_soi_10cm(c) = 0._r8 tsoi17(c) = 0._r8 h2osoi_liqice_10cm(c) = 0._r8 + h2osoi_liq_tot(c) = 0._r8 + h2osoi_ice_tot(c) = 0._r8 end if end do do j = 1, nlevsoi @@ -337,6 +351,10 @@ subroutine HydrologyNoDrainage(bounds, & fracl end if end if + + h2osoi_liq_tot(c) = h2osoi_liq_tot(c) + h2osoi_liq(c,j) + h2osoi_ice_tot(c) = h2osoi_ice_tot(c) + h2osoi_ice(c,j) + end if end do end do diff --git a/src/biogeophys/IrrigationMod.F90 b/src/biogeophys/IrrigationMod.F90 index 21475734d8..cccb8dbc6b 100644 --- a/src/biogeophys/IrrigationMod.F90 +++ b/src/biogeophys/IrrigationMod.F90 @@ -1033,7 +1033,7 @@ subroutine CalcIrrigationNeeded(this, bounds, num_exposedvegp, filter_exposedveg end subroutine CalcIrrigationNeeded !----------------------------------------------------------------------- - pure function PointNeedsCheckForIrrig(this, pft_type, elai, time_prev, londeg) & + function PointNeedsCheckForIrrig(this, pft_type, elai, time_prev, londeg) & result(check_for_irrig) ! ! !DESCRIPTION: diff --git a/src/biogeophys/LakeHydrologyMod.F90 b/src/biogeophys/LakeHydrologyMod.F90 index b0212dfe63..fcdec39861 100644 --- a/src/biogeophys/LakeHydrologyMod.F90 +++ b/src/biogeophys/LakeHydrologyMod.F90 @@ -30,6 +30,7 @@ module LakeHydrologyMod use TemperatureType , only : temperature_type use WaterfluxType , only : waterflux_type use WaterstateType , only : waterstate_type + use TotalWaterAndHeatMod , only : ComputeWaterMassLake ! ! !PUBLIC TYPES: implicit none @@ -47,7 +48,7 @@ subroutine LakeHydrology(bounds, & num_lakec, filter_lakec, num_lakep, filter_lakep, & num_shlakesnowc, filter_shlakesnowc, num_shlakenosnowc, filter_shlakenosnowc, & atm2lnd_inst, temperature_inst, soilstate_inst, waterstate_inst, waterflux_inst, & - energyflux_inst, aerosol_inst, lakestate_inst) + energyflux_inst, aerosol_inst, lakestate_inst, topo_inst) ! ! !DESCRIPTION: ! WARNING: This subroutine assumes lake columns have one and only one pft. @@ -74,6 +75,7 @@ subroutine LakeHydrology(bounds, & use SnowHydrologyMod, only : SnowCompaction, CombineSnowLayers, SnowWater, BuildSnowFilter, SnowCapping use SnowHydrologyMod, only : DivideSnowLayers, NewSnowBulkDensity use LakeCon , only : lsadz + use TopoMod, only : topo_type ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -93,6 +95,7 @@ subroutine LakeHydrology(bounds, & type(energyflux_type) , intent(inout) :: energyflux_inst type(aerosol_type) , intent(inout) :: aerosol_inst type(lakestate_type) , intent(inout) :: lakestate_inst + class(topo_type) , intent(in) :: topo_inst ! ! !LOCAL VARIABLES: integer :: p,fp,g,l,c,j,fc,jtop ! indices @@ -177,6 +180,8 @@ subroutine LakeHydrology(bounds, & qflx_snow_grnd_col => waterflux_inst%qflx_snow_grnd_col , & ! Output: [real(r8) (:) ] snow on ground after interception (mm H2O/s) [+] qflx_evap_tot_col => waterflux_inst%qflx_evap_tot_col , & ! Output: [real(r8) (:) ] pft quantity averaged to the column (assuming one pft) qflx_snwcp_ice => waterflux_inst%qflx_snwcp_ice_col , & ! Output: [real(r8) (:) ] excess solid h2o due to snow capping (outgoing) (mm H2O /s) [+] + qflx_snwcp_discarded_ice => waterflux_inst%qflx_snwcp_discarded_ice_col, & ! Input: [real(r8) (:) ] excess solid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) [+] + qflx_snwcp_discarded_liq => waterflux_inst%qflx_snwcp_discarded_liq_col, & ! Input: [real(r8) (:) ] excess liquid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) [+] qflx_drain_perched => waterflux_inst%qflx_drain_perched_col , & ! Output: [real(r8) (:) ] perched wt sub-surface runoff (mm H2O /s) !TODO - move this to somewhere else qflx_h2osfc_surf => waterflux_inst%qflx_h2osfc_surf_col , & ! Output: [real(r8) (:) ] surface water runoff (mm H2O /s) qflx_snow_drain => waterflux_inst%qflx_snow_drain_col , & ! Output: [real(r8) (:) ] drainage from snow pack @@ -205,14 +210,6 @@ subroutine LakeHydrology(bounds, & ! Determine step size dtime = get_step_size() - ! Add soil water to water balance. - do j = 1, nlevgrnd - do fc = 1, num_lakec - c = filter_lakec(fc) - begwb(c) = begwb(c) + h2osoi_ice(c,j) + h2osoi_liq(c,j) - end do - end do - !!!!!!!!!!!!!!!!!!!!!!!!!!! ! Do precipitation onto ground, etc., from CanopyHydrology @@ -392,7 +389,7 @@ subroutine LakeHydrology(bounds, & atm2lnd_inst, waterflux_inst, waterstate_inst, aerosol_inst) call SnowCapping(bounds, num_lakec, filter_lakec, num_shlakesnowc, filter_shlakesnowc, & - aerosol_inst, waterflux_inst, waterstate_inst) + aerosol_inst, waterflux_inst, waterstate_inst, topo_inst) ! Determine soil hydrology ! Here this consists only of making sure that soil is saturated even as it melts and @@ -607,15 +604,12 @@ subroutine LakeHydrology(bounds, & ! Determine ending water balance and volumetric soil water - do fc = 1, num_lakec - c = filter_lakec(fc) - endwb(c) = h2osno(c) - end do + call ComputeWaterMassLake(bounds, num_lakec, filter_lakec, & + waterstate_inst, endwb(bounds%begc:bounds%endc)) do j = 1, nlevgrnd do fc = 1, num_lakec c = filter_lakec(fc) - endwb(c) = endwb(c) + h2osoi_ice(c,j) + h2osoi_liq(c,j) h2osoi_vol(c,j) = h2osoi_liq(c,j)/(dz(c,j)*denh2o) + h2osoi_ice(c,j)/(dz(c,j)*denice) end do end do @@ -635,6 +629,7 @@ subroutine LakeHydrology(bounds, & ! Insure water balance using qflx_qrgwl ! qflx_snwcp_ice(c) has been computed in routine SnowCapping qflx_qrgwl(c) = forc_rain(c) + forc_snow(c) - qflx_evap_tot(p) - qflx_snwcp_ice(c) - & + qflx_snwcp_discarded_ice(c) - qflx_snwcp_discarded_liq(c) - & (endwb(c)-begwb(c))/dtime + qflx_floodg(g) qflx_floodc(c) = qflx_floodg(g) qflx_runoff(c) = qflx_drain(c) + qflx_qrgwl(c) diff --git a/src/biogeophys/LakeStateType.F90 b/src/biogeophys/LakeStateType.F90 index b4397c7fba..11074aaae1 100644 --- a/src/biogeophys/LakeStateType.F90 +++ b/src/biogeophys/LakeStateType.F90 @@ -32,6 +32,7 @@ module LakeStateType real(r8), pointer :: betaprime_col (:) ! col effective beta: sabg_lyr(p,jtop) for snow layers, beta otherwise real(r8), pointer :: savedtke1_col (:) ! col top level eddy conductivity from previous timestep (W/mK) real(r8), pointer :: lake_icefrac_col (:,:) ! col mass fraction of lake layer that is frozen + real(r8), pointer :: lake_icefracsurf_col(:) ! col mass fraction of surface lake layer that is frozen real(r8), pointer :: lake_icethick_col (:) ! col ice thickness (m) (integrated if lakepuddling) real(r8), pointer :: lakeresist_col (:) ! col [s/m] (Needed for calc. of grnd_ch4_cond) real(r8), pointer :: ram1_lake_patch (:) ! patch aerodynamical resistance (s/m) @@ -93,9 +94,10 @@ subroutine InitAllocate(this, bounds) allocate(this%lakeresist_col (begc:endc)) ; this%lakeresist_col (:) = nan allocate(this%savedtke1_col (begc:endc)) ; this%savedtke1_col (:) = spval allocate(this%lake_icefrac_col (begc:endc,1:nlevlak)) ; this%lake_icefrac_col (:,:) = nan + allocate(this%lake_icefracsurf_col (begc:endc)) ; this%lake_icefracsurf_col (:) = nan allocate(this%lake_icethick_col (begc:endc)) ; this%lake_icethick_col (:) = nan allocate(this%ust_lake_col (begc:endc)) ; this%ust_lake_col (:) = spval - allocate(this%ram1_lake_patch (begp:endp)) ; this%ram1_lake_patch (:) = nan + allocate(this%ram1_lake_patch (begp:endp)) ; this%ram1_lake_patch (:) = nan allocate(this%lake_raw_col (begc:endc)) ; this%lake_raw_col (:) = nan allocate(this%ks_col (begc:endc)) ; this%ks_col (:) = nan allocate(this%ws_col (begc:endc)) ; this%ws_col (:) = nan @@ -127,7 +129,12 @@ subroutine InitHistory(this, bounds) this%lake_icefrac_col(begc:endc,:) = spval call hist_addfld2d (fname='LAKEICEFRAC', units='unitless', type2d='levlak', & avgflag='A', long_name='lake layer ice mass fraction', & - ptr_col=this%lake_icefrac_col) + ptr_col=this%lake_icefrac_col, default='inactive') + + this%lake_icefracsurf_col(begc:endc) = spval + call hist_addfld1d (fname='LAKEICEFRAC_SURF', units='unitless', & + avgflag='A', long_name='surface lake layer ice mass fraction', & + ptr_col=this%lake_icefracsurf_col, set_nolake=spval) this%lake_icethick_col(begc:endc) = spval ! This will be more useful than LAKEICEFRAC for many users. call hist_addfld1d (fname='LAKEICETHICK', units='m', & diff --git a/src/biogeophys/LakeTemperatureMod.F90 b/src/biogeophys/LakeTemperatureMod.F90 index 2c24373a45..bcb2965afa 100644 --- a/src/biogeophys/LakeTemperatureMod.F90 +++ b/src/biogeophys/LakeTemperatureMod.F90 @@ -246,11 +246,10 @@ subroutine LakeTemperature(bounds, num_lakec, filter_lakec, num_lakep, filter_la t_grnd => temperature_inst%t_grnd_col , & ! Input: [real(r8) (:) ] ground temperature (Kelvin) t_soisno => temperature_inst%t_soisno_col , & ! Output: [real(r8) (:,:) ] soil (or snow) temperature (Kelvin) t_lake => temperature_inst%t_lake_col , & ! Output: [real(r8) (:,:) ] col lake temperature (Kelvin) - hc_soi => temperature_inst%hc_soi_col , & ! Output: [real(r8) (:) ] soil heat content (MJ/m2) - hc_soisno => temperature_inst%hc_soisno_col , & ! Output: [real(r8) (:) ] soil plus snow plus lake heat content (MJ/m2) beta => lakestate_inst%betaprime_col , & ! Output: [real(r8) (:) ] col effective beta: sabg_lyr(p,jtop) for snow layers, beta otherwise lake_icefrac => lakestate_inst%lake_icefrac_col , & ! Output: [real(r8) (:,:) ] col mass fraction of lake layer that is frozen + lake_icefracsurf => lakestate_inst%lake_icefracsurf_col , & ! Output: [real(r8) (:,:) ] col mass fraction of surface lake layer that is frozen lake_icethick => lakestate_inst%lake_icethick_col , & ! Output: [real(r8) (:) ] col ice thickness (m) (integrated if lakepuddling) savedtke1 => lakestate_inst%savedtke1_col , & ! Output: [real(r8) (:) ] col top level eddy conductivity (W/mK) lakeresist => lakestate_inst%lakeresist_col , & ! Output: [real(r8) (:) ] col (Needed for calc. of grnd_ch4_cond) (s/m) @@ -292,8 +291,6 @@ subroutine LakeTemperature(bounds, num_lakec, filter_lakec, num_lakep, filter_la ncvts(c) = 0._r8 esum1(c) = 0._r8 esum2(c) = 0._r8 - hc_soisno(c) = 0._r8 - hc_soi(c) = 0._r8 if (use_lch4) then jconvect(c) = 0 jconvectbot(c) = nlevlak+1 @@ -934,6 +931,7 @@ subroutine LakeTemperature(bounds, num_lakec, filter_lakec, num_lakep, filter_la lake_icefrac(c,i) = 0._r8 t_lake(c,i) = tav_unfr(c) + tfrz end if + zsum(c) = zsum(c) + dz_lake(c,i) rhow(c,i) = (1._r8 - lake_icefrac(c,i)) * & @@ -997,8 +995,6 @@ subroutine LakeTemperature(bounds, num_lakec, filter_lakec, num_lakep, filter_la ncvts(c) = ncvts(c) + cv_lake(c,j)*(t_lake(c,j)-tfrz) & + cfus*dz_lake(c,j)*(1._r8-lake_icefrac(c,j)) fin(c) = fin(c) + phi(c,j) - ! New for CLM 4 - hc_soisno(c) = hc_soisno(c) + cv_lake(c,j)*t_lake(c,j)/1.e6 end do end do @@ -1013,8 +1009,6 @@ subroutine LakeTemperature(bounds, num_lakec, filter_lakec, num_lakep, filter_la if (j == 1 .and. h2osno(c) > 0._r8 .and. j == jtop(c)) then ncvts(c) = ncvts(c) - h2osno(c)*hfus end if - hc_soisno(c) = hc_soisno(c) + cv(c,j)*t_soisno(c,j)/1.e6 - if (j >= 1) hc_soi(c) = hc_soi(c) + cv(c,j)*t_soisno(c,j)/1.e6 end if if (j == 1) fin(c) = fin(c) + phi_soil(c) end do @@ -1040,12 +1034,13 @@ subroutine LakeTemperature(bounds, num_lakec, filter_lakec, num_lakep, filter_la end do ! This loop assumes only one point per column. - ! lake_icethick diagnostic. + ! lake_icethickness and lake_icefraction at surface diagnostic. do j = 1, nlevlak do fc = 1, num_lakec c = filter_lakec(fc) if (j == 1) lake_icethick(c) = 0._r8 + if (j == 1) lake_icefracsurf(c) = lake_icefrac(c,1) lake_icethick(c) = lake_icethick(c) + lake_icefrac(c,j)*dz_lake(c,j)*denh2o/denice ! Convert from nominal to physical thickness diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index e4396eed1b..4124ced958 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -315,7 +315,7 @@ subroutine CalcOzoneStress(this, bounds, num_exposedvegp, filter_exposedvegp, & ! Calculate ozone stress. ! ! !USES: - use PatchType , only : patch + use PatchType , only : patch ! ! !ARGUMENTS: class(ozone_type) , intent(inout) :: this @@ -361,21 +361,38 @@ subroutine CalcOzoneStress(this, bounds, num_exposedvegp, filter_exposedvegp, & p = filter_exposedvegp(fp) c = patch%column(p) - ! Ozone stress for shaded leaves - call CalcOzoneStressOnePoint( & - forc_ozone=forc_ozone, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & - rs=rssha(p), rb=rb(p), ram=ram(p), & - tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & - o3uptake=o3uptakesha(p), o3coefv=o3coefvsha(p), o3coefg=o3coefgsha(p)) - - ! Ozone stress for sunlit leaves - call CalcOzoneStressOnePoint( & - forc_ozone=forc_ozone, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & - rs=rssun(p), rb=rb(p), ram=ram(p), & - tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & - o3uptake=o3uptakesun(p), o3coefv=o3coefvsun(p), o3coefg=o3coefgsun(p)) - - tlai_old(p) = tlai(p) +! if (.not.patch%is_fates(p)) then ! When FATES coexists with other vegetation, + ! or when it has an ozone compatible module, this + ! logic will likely come into play + + ! Ozone stress for shaded leaves + call CalcOzoneStressOnePoint( & + forc_ozone=forc_ozone, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + rs=rssha(p), rb=rb(p), ram=ram(p), & + tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & + o3uptake=o3uptakesha(p), o3coefv=o3coefvsha(p), o3coefg=o3coefgsha(p)) + + ! Ozone stress for sunlit leaves + call CalcOzoneStressOnePoint( & + forc_ozone=forc_ozone, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + rs=rssun(p), rb=rb(p), ram=ram(p), & + tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & + o3uptake=o3uptakesun(p), o3coefv=o3coefvsun(p), o3coefg=o3coefgsun(p)) + + tlai_old(p) = tlai(p) + +! else +! ! FATES is fundamentlaly incompatible with this type of patch-level +! ! association with plant functional type, so for the time +! ! being, fates patches will just push these values to invalid +! o3uptakesha(p) = spval +! o3coefvsha(p) = spval +! o3coefgsha(p) = spval +! o3uptakesun(p) = spval +! o3coefvsun(p) = spval +! o3coefgsun(p) = spval +! +! end if end do diff --git a/src/biogeophys/PhotosynthesisMod.F90 b/src/biogeophys/PhotosynthesisMod.F90 index 4c15c2efdd..8b6e708606 100644 --- a/src/biogeophys/PhotosynthesisMod.F90 +++ b/src/biogeophys/PhotosynthesisMod.F90 @@ -14,14 +14,14 @@ module PhotosynthesisMod use shr_log_mod , only : errMsg => shr_log_errMsg use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use abortutils , only : endrun - use clm_varctl , only : use_c13, use_c14, use_cn, use_cndv, use_ed, use_luna, use_hydrstress + use clm_varctl , only : use_c13, use_c14, use_cn, use_cndv, use_fates, use_luna, use_hydrstress use clm_varctl , only : iulog use clm_varpar , only : nlevcan, nvegwcs, mxpft use clm_varcon , only : namep, c14ratio, spval use decompMod , only : bounds_type use QuadraticMod , only : quadratic use pftconMod , only : pftcon - use C14BombSpikeMod , only : C14BombSpike, use_c14_bombspike + use CIsoAtmTimeseriesMod, only : C14BombSpike, use_c14_bombspike, C13TimeSeries, use_c13_timeseries, nsectors_c14 use atm2lndType , only : atm2lnd_type use CanopyStateType , only : canopystate_type use WaterStateType , only : waterstate_type @@ -33,6 +33,7 @@ module PhotosynthesisMod use OzoneBaseMod , only : ozone_base_type use LandunitType , only : lun use PatchType , only : patch + use GridcellType , only : grc ! implicit none private @@ -74,6 +75,8 @@ module PhotosynthesisMod integer, parameter, private :: root=4 ! index for root integer, parameter, private :: veg=0 ! index for vegetation integer, parameter, private :: soil=1 ! index for soil + integer, parameter, private :: stomatalcond_mtd_bb1987 = 1 ! Ball-Berry 1987 method for photosynthesis + integer, parameter, private :: stomatalcond_mtd_medlyn2011 = 2 ! Medlyn 2011 method for photosynthesis ! !PUBLIC VARIABLES: type :: photo_params_type @@ -166,10 +169,11 @@ module PhotosynthesisMod real(r8), pointer, private :: rssha_z_patch (:,:) ! patch canopy layer: shaded leaf stomatal resistance (s/m) real(r8), pointer, public :: rssun_patch (:) ! patch sunlit stomatal resistance (s/m) real(r8), pointer, public :: rssha_patch (:) ! patch shaded stomatal resistance (s/m) + real(r8), pointer, public :: luvcmax25top_patch (:) ! vcmax25 ! (umol/m2/s) + real(r8), pointer, public :: lujmax25top_patch (:) ! vcmax25 (umol/m2/s) + real(r8), pointer, public :: lutpu25top_patch (:) ! vcmax25 (umol/m2/s) +!! - ! ED specific variables -! real(r8), pointer, public :: psncanopy_patch (:) ! patch sunlit leaf photosynthesis (umol CO2 /m**2/ s) (ED specific) -! real(r8), pointer, public :: lmrcanopy_patch (:) ! sunlit leaf maintenance respiration rate (umol CO2/m**2/s) (ED specific) ! LUNA specific variables real(r8), pointer, public :: vcmx25_z_patch (:,:) ! patch leaf Vc,max25 (umol CO2/m**2/s) for canopy layer @@ -182,6 +186,8 @@ module PhotosynthesisMod logical, public :: rootstem_acc ! Respiratory acclimation for roots and stems logical, private :: light_inhibit ! If light should inhibit respiration integer, private :: leafresp_method ! leaf maintencence respiration at 25C for canopy top method to use + integer, private :: stomatalcond_mtd ! Stomatal conduction method type + logical, private :: modifyphoto_and_lmr_forcrop ! Modify photosynthesis and LMR for crop contains ! Public procedures @@ -303,7 +309,10 @@ subroutine InitAllocate(this, bounds) allocate(this%rssha_z_patch (begp:endp,1:nlevcan)) ; this%rssha_z_patch (:,:) = nan allocate(this%rssun_patch (begp:endp)) ; this%rssun_patch (:) = nan allocate(this%rssha_patch (begp:endp)) ; this%rssha_patch (:) = nan - + allocate(this%luvcmax25top_patch(begp:endp)) ; this%luvcmax25top_patch(:) = nan + allocate(this%lujmax25top_patch (begp:endp)) ; this%lujmax25top_patch(:) = nan + allocate(this%lutpu25top_patch (begp:endp)) ; this%lutpu25top_patch(:) = nan +!! ! allocate(this%psncanopy_patch (begp:endp)) ; this%psncanopy_patch (:) = nan ! allocate(this%lmrcanopy_patch (begp:endp)) ; this%lmrcanopy_patch (:) = nan if(use_luna)then @@ -345,25 +354,37 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='leaf N concentration', & ptr_patch=this%lnca_patch, set_spec=spval) - this%fpsn_patch(begp:endp) = spval - call hist_addfld1d (fname='FPSN', units='umol/m2s', & - avgflag='A', long_name='photosynthesis', & - ptr_patch=this%fpsn_patch, set_lake=0._r8, set_urb=0._r8) - - this%fpsn_wc_patch(begp:endp) = spval - call hist_addfld1d (fname='FPSN_WC', units='umol/m2s', & - avgflag='A', long_name='Rubisco-limited photosynthesis', & - ptr_patch=this%fpsn_wc_patch, set_lake=0._r8, set_urb=0._r8) - - this%fpsn_wj_patch(begp:endp) = spval - call hist_addfld1d (fname='FPSN_WJ', units='umol/m2s', & - avgflag='A', long_name='RuBP-limited photosynthesis', & - ptr_patch=this%fpsn_wj_patch, set_lake=0._r8, set_urb=0._r8) - - this%fpsn_wp_patch(begp:endp) = spval - call hist_addfld1d (fname='FPSN_WP', units='umol/m2s', & - avgflag='A', long_name='Product-limited photosynthesis', & - ptr_patch=this%fpsn_wp_patch, set_lake=0._r8, set_urb=0._r8) + ! Don't output photosynthesis variables when FATES is on as they aren't calculated + if (.not. use_fates) then + this%fpsn_patch(begp:endp) = spval + call hist_addfld1d (fname='FPSN', units='umol/m2s', & + avgflag='A', long_name='photosynthesis', & + ptr_patch=this%fpsn_patch, set_lake=0._r8, set_urb=0._r8) + + ! Don't by default output this rate limiting step as only makes sense if you are outputing + ! the others each time-step + this%fpsn_wc_patch(begp:endp) = spval + call hist_addfld1d (fname='FPSN_WC', units='umol/m2s', & + avgflag='I', long_name='Rubisco-limited photosynthesis', & + ptr_patch=this%fpsn_wc_patch, set_lake=0._r8, set_urb=0._r8, & + default='inactive') + + ! Don't by default output this rate limiting step as only makes sense if you are outputing + ! the others each time-step + this%fpsn_wj_patch(begp:endp) = spval + call hist_addfld1d (fname='FPSN_WJ', units='umol/m2s', & + avgflag='I', long_name='RuBP-limited photosynthesis', & + ptr_patch=this%fpsn_wj_patch, set_lake=0._r8, set_urb=0._r8, & + default='inactive') + + ! Don't by default output this rate limiting step as only makes sense if you are outputing + ! the others each time-step + this%fpsn_wp_patch(begp:endp) = spval + call hist_addfld1d (fname='FPSN_WP', units='umol/m2s', & + avgflag='I', long_name='Product-limited photosynthesis', & + ptr_patch=this%fpsn_wp_patch, set_lake=0._r8, set_urb=0._r8, & + default='inactive') + end if if (use_cn) then this%psnsun_patch(begp:endp) = spval @@ -435,12 +456,35 @@ subroutine InitHistory(this, bounds) this%rssun_patch(begp:endp) = spval call hist_addfld1d (fname='RSSUN', units='s/m', & avgflag='M', long_name='sunlit leaf stomatal resistance', & - ptr_patch=this%rssun_patch, set_lake=spval, set_urb=spval, default='inactive') + ptr_patch=this%rssun_patch, set_lake=spval, set_urb=spval) this%rssha_patch(begp:endp) = spval call hist_addfld1d (fname='RSSHA', units='s/m', & avgflag='M', long_name='shaded leaf stomatal resistance', & - ptr_patch=this%rssha_patch, set_lake=spval, set_urb=spval, default='inactive') + ptr_patch=this%rssha_patch, set_lake=spval, set_urb=spval) + + this%gs_mol_sun_patch(begp:endp,:) = spval + this%gs_mol_sha_patch(begp:endp,:) = spval + if (nlevcan>1) then + call hist_addfld2d (fname='GSSUN', units='umol H20/m2/s', type2d='nlevcan', & + avgflag='A', long_name='sunlit leaf stomatal conductance', & + ptr_patch=this%gs_mol_sun_patch, set_lake=spval, set_urb=spval) + + call hist_addfld2d (fname='GSSHA', units='umol H20/m2/s', type2d='nlevcan', & + avgflag='A', long_name='shaded leaf stomatal conductance', & + ptr_patch=this%gs_mol_sha_patch, set_lake=spval, set_urb=spval) + else + ptr_1d => this%gs_mol_sun_patch(begp:endp,1) + call hist_addfld1d (fname='GSSUN', units='umol H20/m2/s', & + avgflag='A', long_name='sunlit leaf stomatal conductance', & + ptr_patch=ptr_1d) + + ptr_1d => this%gs_mol_sha_patch(begp:endp,1) + call hist_addfld1d (fname='GSSHA', units='umol H20/m2/s', & + avgflag='A', long_name='shaded leaf stomatal conductance', & + ptr_patch=ptr_1d) + + endif if(use_luna)then if(nlevcan>1)then @@ -469,11 +513,26 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='Proportion of nitrogen allocated for light capture', & ptr_patch=ptr_1d,default='inactive') + this%luvcmax25top_patch(begp:endp) = spval + call hist_addfld1d (fname='VCMX25T', units='umol/m2/s', & + avgflag='M', long_name='canopy profile of vcmax25', & + ptr_patch=this%luvcmax25top_patch, set_lake=spval, set_urb=spval) + + this%lujmax25top_patch(begp:endp) = spval + call hist_addfld1d (fname='JMX25T', units='umol/m2/s', & + avgflag='M', long_name='canopy profile of jmax', & + ptr_patch=this%lujmax25top_patch, set_lake=spval, set_urb=spval) + + this%lutpu25top_patch(begp:endp) = spval + call hist_addfld1d (fname='TPU25T', units='umol/m2/s', & + avgflag='M', long_name='canopy profile of tpu', & + ptr_patch=this%lutpu25top_patch, set_lake=spval, set_urb=spval) + endif - this%fpsn24_patch = spval - call hist_addfld1d (fname='FPSN24', units='umol CO2/m**2 ground/day',& - avgflag='A', long_name='24 hour accumulative patch photosynthesis starting from mid-night', & - ptr_patch=this%fpsn24_patch,default='inactive') + this%fpsn24_patch = spval + call hist_addfld1d (fname='FPSN24', units='umol CO2/m**2 ground/day',& + avgflag='A', long_name='24 hour accumulative patch photosynthesis starting from mid-night', & + ptr_patch=this%fpsn24_patch, default='inactive') endif @@ -615,13 +674,15 @@ subroutine ReadNML(this, NLFilename) character(len=*), parameter :: subname = 'Photosyn::ReadNML' character(len=*), parameter :: nmlname = 'photosyns_inparm' - logical :: rootstem_acc = .false. ! Respiratory acclimation for roots and stems - logical :: light_inhibit = .false. ! If light should inhibit respiration - integer :: leafresp_method = leafresp_mtd_ryan1991 ! leaf maintencence respiration at 25C for canopy top method to use + logical :: rootstem_acc = .false. ! Respiratory acclimation for roots and stems + logical :: light_inhibit = .false. ! If light should inhibit respiration + integer :: leafresp_method = leafresp_mtd_ryan1991 ! leaf maintencence respiration at 25C for canopy top method to use + logical :: modifyphoto_and_lmr_forcrop = .false. ! Modify photosynthesis and LMR for crop + character(len=50) :: stomatalcond_method = 'Ball-Berry1987' ! Photosynthesis method string !----------------------------------------------------------------------- namelist /photosyns_inparm/ leafresp_method, light_inhibit, & - rootstem_acc + rootstem_acc, stomatalcond_method, modifyphoto_and_lmr_forcrop ! Initialize options to default values, in case they are not specified in ! the namelist @@ -643,11 +704,21 @@ subroutine ReadNML(this, NLFilename) this%rootstem_acc = rootstem_acc this%leafresp_method = leafresp_method this%light_inhibit = light_inhibit + this%modifyphoto_and_lmr_forcrop = modifyphoto_and_lmr_forcrop + if ( trim(stomatalcond_method) == 'Ball-Berry1987' ) then + this%stomatalcond_mtd = stomatalcond_mtd_bb1987 + else if ( trim(stomatalcond_method) == 'Medlyn2011' ) then + this%stomatalcond_mtd = stomatalcond_mtd_medlyn2011 + else + call endrun(msg="ERROR bad value for stomtalcond_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if end if call shr_mpi_bcast (this%rootstem_acc , mpicom) call shr_mpi_bcast (this%leafresp_method, mpicom) call shr_mpi_bcast (this%light_inhibit , mpicom) + call shr_mpi_bcast (this%stomatalcond_mtd, mpicom) + call shr_mpi_bcast (this%modifyphoto_and_lmr_forcrop, mpicom) if (masterproc) then write(iulog,*) ' ' @@ -690,9 +761,20 @@ subroutine Restart(this, bounds, ncid, flag) interpinic_flag='interp', readvar=readvar, data=this%rc13_psnsha_patch) endif + call restartvar(ncid=ncid, flag=flag, varname='GSSUN', xtype=ncd_double, & + dim1name='pft', dim2name='levcan', switchdim=.true., & + long_name='sunlit leaf stomatal conductance', units='umol H20/m2/s', & + interpinic_flag='interp', readvar=readvar, data=this%gs_mol_sun_patch) + + call restartvar(ncid=ncid, flag=flag, varname='GSSHA', xtype=ncd_double, & + dim1name='pft', dim2name='levcan', switchdim=.true., & + long_name='shaded leaf stomatal conductance', units='umol H20/m2/s', & + interpinic_flag='interp', readvar=readvar, data=this%gs_mol_sha_patch) + call restartvar(ncid=ncid, flag=flag, varname='lnca', xtype=ncd_double, & dim1name='pft', long_name='leaf N concentration', units='gN leaf/m^2', & interpinic_flag='interp', readvar=readvar, data=this%lnca_patch) + if(use_luna) then call restartvar(ncid=ncid, flag=flag, varname='vcmx25_z', xtype=ncd_double, & dim1name='pft', dim2name='levcan', switchdim=.true., & @@ -714,6 +796,20 @@ subroutine Restart(this, bounds, ncid, flag) dim1name='pft', long_name='accumulative gross primary production', units='umol CO2/m**2 ground/day', & interpinic_flag='interp', readvar=readvar, data=this%fpsn24_patch) endif + call restartvar(ncid=ncid, flag=flag, varname='vcmx25t', xtype=ncd_double, & + dim1name='pft', long_name='canopy profile of vcmax25', & + units='umol/m2/s', & + interpinic_flag='interp', readvar=readvar, data=this%luvcmax25top_patch) + + call restartvar(ncid=ncid, flag=flag, varname='jmx25t', xtype=ncd_double, & + dim1name='pft', long_name='canopy profile of jmax', & + units='umol/m2/s', & + interpinic_flag='interp', readvar=readvar, data=this%lujmax25top_patch) + + call restartvar(ncid=ncid, flag=flag, varname='tpu25t', xtype=ncd_double, & + dim1name='pft', long_name='canopy profile of tpu', & + units='umol/m2/s', & + interpinic_flag='interp', readvar=readvar, data=this%lutpu25top_patch) end subroutine Restart @@ -723,7 +819,7 @@ subroutine TimeStepInit (this, bounds) ! Time step initialization ! ! !USES: - use landunit_varcon, only : istsoil, istcrop, istice, istice_mec, istwet + use landunit_varcon, only : istsoil, istcrop, istice_mec, istwet ! ! !ARGUMENTS: class(photosyns_type) :: this @@ -763,7 +859,7 @@ subroutine TimeStepInit (this, bounds) endif end if if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop & - .or. lun%itype(l) == istice .or. lun%itype(l) == istice_mec & + .or. lun%itype(l) == istice_mec & .or. lun%itype(l) == istwet) then if (use_c13) then this%rc13_canair_patch(p) = 0._r8 @@ -1030,6 +1126,7 @@ subroutine Photosynthesis ( bounds, fn, filterp, & lnc => photosyns_inst%lnca_patch , & ! Output: [real(r8) (:) ] top leaf layer leaf N concentration (gN leaf/m^2) light_inhibit=> photosyns_inst%light_inhibit , & ! Input: [logical ] flag if light should inhibit respiration leafresp_method=> photosyns_inst%leafresp_method , & ! Input: [integer ] method type to use for leaf-maint.-respiration at 25C canopy top + stomatalcond_mtd=> photosyns_inst%stomatalcond_mtd , & ! Input: [integer ] method type to use for stomatal conductance.GC.fnlprmsn15_r22845 leaf_mr_vcm => canopystate_inst%leaf_mr_vcm & ! Input: [real(r8) ] scalar constant of leaf respiration with Vcmax ) @@ -1171,6 +1268,9 @@ subroutine Photosynthesis ( bounds, fn, filterp, & if (lnc_opt .eqv. .false.) then ! Leaf nitrogen concentration at the top of the canopy (g N leaf / m**2 leaf) + if ( (slatop(patch%itype(p)) *leafcn(patch%itype(p))) .le. 0.0_r8)then + call endrun( "ERROR: slatop or leafcn is zero" ) + end if lnc(p) = 1._r8 / (slatop(patch%itype(p)) * leafcn(patch%itype(p))) end if @@ -1264,7 +1364,7 @@ subroutine Photosynthesis ( bounds, fn, filterp, & ! But not used as defined here if using sun/shade big leaf code. Instead, ! will use canopy integrated scaling factors from SurfaceAlbedo. - if (dayl_factor(p) .eq. 0._r8) then + if (dayl_factor(p) < 1.0e-12_r8) then kn(p) = 0._r8 else kn(p) = exp(0.00963_r8 * vcmax25top/dayl_factor(p) - 2.43_r8) @@ -1458,7 +1558,12 @@ subroutine Photosynthesis ( bounds, fn, filterp, & !now the constraint is no longer needed, Jinyun Tang ceair = min( eair(p), esat_tv(p) ) - rh_can = ceair / esat_tv(p) + if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + rh_can = ceair / esat_tv(p) + else if ( stomatalcond_mtd == stomatalcond_mtd_medlyn2011 )then + ! Put some constraints on RH in the canopy when Medlyn stomatal conductance is being used + rh_can = max((esat_tv(p) - ceair), 50._r8) * 0.001_r8 + end if ! Electron transport rate for C3 plants. Convert par from W/m2 to ! umol photons/m**2/s using the factor 4.6 @@ -1616,7 +1721,9 @@ subroutine PhotosynthesisTotal (fn, filterp, & ! ! !LOCAL VARIABLES: integer :: f,fp,p,l,g ! indices - real(r8) :: rc14_atm + + real(r8) :: rc14_atm(nsectors_c14), rc13_atm + integer :: sector_c14 !----------------------------------------------------------------------- associate( & @@ -1654,7 +1761,13 @@ subroutine PhotosynthesisTotal (fn, filterp, & if (use_c14_bombspike) then call C14BombSpike(rc14_atm) else - rc14_atm = c14ratio + rc14_atm(:) = c14ratio + end if + end if + + if ( use_c13 ) then + if (use_c13_timeseries) then + call C13TimeSeries(rc13_atm) end if end if @@ -1662,9 +1775,7 @@ subroutine PhotosynthesisTotal (fn, filterp, & p = filterp(f) g = patch%gridcell(p) - ! INTERFACE-TODO: EDACCUMULATEFLUXES PERFORMS AN ALTERNATIVE TO THIS - ! THEY SHOULD BE IN-LINE SOMEWHERE - if (.not. use_ed) then + if (.not. use_fates) then fpsn(p) = psnsun(p) *laisun(p) + psnsha(p) *laisha(p) fpsn_wc(p) = psnsun_wc(p)*laisun(p) + psnsha_wc(p)*laisha(p) fpsn_wj(p) = psnsun_wj(p)*laisun(p) + psnsha_wj(p)*laisha(p) @@ -1673,7 +1784,11 @@ subroutine PhotosynthesisTotal (fn, filterp, & if (use_cn) then if ( use_c13 ) then - rc13_canair(p) = forc_pc13o2(g)/(forc_pco2(g) - forc_pc13o2(g)) + if (use_c13_timeseries) then + rc13_canair(p) = rc13_atm + else + rc13_canair(p) = forc_pc13o2(g)/(forc_pco2(g) - forc_pc13o2(g)) + endif rc13_psnsun(p) = rc13_canair(p)/alphapsnsun(p) rc13_psnsha(p) = rc13_canair(p)/alphapsnsha(p) c13_psnsun(p) = psnsun(p) * (rc13_psnsun(p)/(1._r8+rc13_psnsun(p))) @@ -1684,8 +1799,18 @@ subroutine PhotosynthesisTotal (fn, filterp, & ! c13_psnsha(p) = 0.01095627 * psnsha(p) endif if ( use_c14 ) then - c14_psnsun(p) = rc14_atm * psnsun(p) - c14_psnsha(p) = rc14_atm * psnsha(p) + + ! determine latitute sector for radiocarbon bomb spike inputs + if ( grc%latdeg(g) .ge. 30._r8 ) then + sector_c14 = 1 + else if ( grc%latdeg(g) .ge. -30._r8 ) then + sector_c14 = 2 + else + sector_c14 = 3 + endif + + c14_psnsun(p) = rc14_atm(sector_c14) * psnsun(p) + c14_psnsha(p) = rc14_atm(sector_c14) * psnsha(p) endif end if @@ -1703,6 +1828,10 @@ subroutine Fractionation(bounds, fn, filterp, downreg, & ! !DESCRIPTION: ! C13 fractionation during photosynthesis is calculated here after the nitrogen ! limitation is taken into account in the CNAllocation module. + ! + ! As of CLM5, nutrient downregulation occurs prior to photosynthesis via leafcn, so we may + ! ignore the downregulation term in this and assume that the Ci/Ca used in the photosynthesis + ! calculation is consistent with that in the isotope calculation ! !!USES: use clm_varctl , only : use_hydrstress @@ -1774,7 +1903,7 @@ subroutine Fractionation(bounds, fn, filterp, downreg, & if (par_z(p,iv) <= 0._r8) then ! night time alphapsn(p) = 1._r8 else ! day time - ci = co2(p) - ((an(p,iv) * (1._r8-downreg(p)) ) * & + ci = co2(p) - (an(p,iv) * & forc_pbot(c) * & (1.4_r8*gs_mol(p,iv)+1.6_r8*gb_mol(p)) / (gb_mol(p)*gs_mol(p,iv))) alphapsn(p) = 1._r8 + (((c3psn(patch%itype(p)) * & @@ -2245,6 +2374,7 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & use clm_varpar , only : nlevsoi use pftconMod , only : nbrdlf_dcd_tmp_shrub, npcropmin use ColumnType , only : col + use shr_infnan_mod , only : shr_infnan_isnan ! ! !ARGUMENTS: @@ -2441,6 +2571,10 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & real(r8) :: root_conductance ! root hydraulic conductance [1/s] real(r8) :: rai(nlevsoi) ! root area index [m2/m2] real(r8) :: fs(nlevsoi) ! root conductance scale factor (reduction in conductance due to decreasing (more negative) root water potential) + real(r8) :: gsminsun ! Minimum stomatal conductance sunlit + real(r8) :: gsminsha ! Minimum stomatal conductance shaded + real(r8) :: gs_slope_sun ! Slope stomatal conductance sunlit + real(r8) :: gs_slope_sha ! Slope stomatal conductance shaded real(r8), parameter :: croot_lateral_length = 0.25_r8 ! specified lateral coarse root length [m] real(r8), parameter :: c_to_b = 2.0_r8 !(g biomass /g C) !Note that root density is for dry biomass not carbon. CLM provides root biomass as carbon. The conversion is 0.5 g C / g biomass @@ -2494,6 +2628,8 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & i_flnr => pftcon%i_flnr , & ! Input: [real(r8) (:) ] s_flnr => pftcon%s_flnr , & ! Input: [real(r8) (:) ] mbbopt => pftcon%mbbopt , & + medlynintercept=> pftcon%medlynintercept , & ! Input: [real(r8) (:) ] Intercept for Medlyn stomatal conductance model method + medlynslope=> pftcon%medlynslope , & ! Input: [real(r8) (:) ] Slope for Medlyn stomatal conductance model method forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] atmospheric pressure (Pa) ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type @@ -2509,6 +2645,10 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & ap => photosyns_inst%ap_phs_patch , & ! Output: [real(r8) (:,:,:) ] product-limited (C3) or CO2-limited (C4) gross photosynthesis (umol CO2/m**2/s) ag => photosyns_inst%ag_phs_patch , & ! Output: [real(r8) (:,:,:) ] co-limited gross leaf photosynthesis (umol CO2/m**2/s) vcmax_z => photosyns_inst%vcmax_z_phs_patch , & ! Output: [real(r8) (:,:,:) ] maximum rate of carboxylation (umol co2/m**2/s) + luvcmax25top => photosyns_inst%luvcmax25top_patch , & ! Output: [real(r8) (:) ] maximum rate of carboxylation (umol co2/m**2/s) + lujmax25top => photosyns_inst%lujmax25top_patch , & ! Output: [real(r8) (:) ] maximum rate of carboxylation (umol co2/m**2/s) + lutpu25top => photosyns_inst%lutpu25top_patch , & ! Output: [real(r8) (:) ] maximum rate of carboxylation (umol co2/m**2/s) +!!! tpu_z => photosyns_inst%tpu_z_phs_patch , & ! Output: [real(r8) (:,:,:) ] triose phosphate utilization rate (umol CO2/m**2/s) kp_z => photosyns_inst%kp_z_phs_patch , & ! Output: [real(r8) (:,:,:) ] initial slope of CO2 response curve (C4 plants) gb_mol => photosyns_inst%gb_mol_patch , & ! Output: [real(r8) (:) ] leaf boundary layer conductance (umol H2O/m**2/s) @@ -2523,6 +2663,8 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & lnc => photosyns_inst%lnca_patch , & ! Output: [real(r8) (:) ] top leaf layer leaf N concentration (gN leaf/m^2) light_inhibit=> photosyns_inst%light_inhibit , & ! Input: [logical ] flag if light should inhibit respiration leafresp_method=> photosyns_inst%leafresp_method , & ! Input: [integer ] method type to use for leaf-maint.-respiration at 25C canopy top + stomatalcond_mtd=> photosyns_inst%stomatalcond_mtd , & ! Input: [integer ] method type to use for stomatal conductance + modifyphoto_and_lmr_forcrop=> photosyns_inst%modifyphoto_and_lmr_forcrop, & ! Input: [logical ] modifyphoto_and_lmr_forcrop leaf_mr_vcm => canopystate_inst%leaf_mr_vcm , & ! Input: [real(r8) ] scalar constant of leaf respiration with Vcmax vegwp => canopystate_inst%vegwp_patch , & ! Input/Output: [real(r8) (:,:) ] vegetation water matric potential (mm) an_sun => photosyns_inst%an_sun_patch , & ! Output: [real(r8) (:,:) ] net sunlit leaf photosynthesis (umol CO2/m**2/s) @@ -2683,9 +2825,11 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & bbbopt(p) = 40000._r8 end if - ! Soil water stress applied to Ball-Berry parameters later in ci_func_PHS - bbb(p) = bbbopt(p) - mbb(p) = mbbopt(patch%itype(p)) + if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + ! Soil water stress applied to Ball-Berry parameters later in ci_func_PHS + bbb(p) = bbbopt(p) + mbb(p) = mbbopt(patch%itype(p)) + end if ! kc, ko, cp, from: Bernacchi et al (2001) Plant, Cell and Environment 24:253-259 ! ! kc25 = 404.9 umol/mol @@ -2760,7 +2904,7 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & end if end if - + lnc(p) = min(lnc(p),10._r8) ! reduce_dayl_factor .eqv. .false. if (reduce_dayl_factor .eqv. .true.) then @@ -2801,6 +2945,9 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & jmax25top = (2.59_r8 - 0.035_r8*min(max((t10(p)-tfrz),11._r8),35._r8)) * vcmax25top tpu25top = 0.167_r8 * vcmax25top kp25top = 20000._r8 * vcmax25top + luvcmax25top(p) = vcmax25top + lujmax25top(p) = jmax25top + lutpu25top(p)=tpu25top ! Nitrogen scaling factor. Bonan et al (2011) JGR, 116, doi:10.1029/2010JG001593 used ! kn = 0.11. Here, derive kn from vcmax25 as in Lloyd et al (2010) Biogeosciences, 7, 1833-1859 @@ -2902,6 +3049,10 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & lmr_z_sha(p,iv) = lmr_z_sha(p,iv) / (1._r8 + exp( 1.3_r8*(t_veg(p)-(tfrz+55._r8)) )) end if + ! Reduce lmr w/ low lai + lmr_z_sun(p,iv) = lmr_z_sun(p,iv)*min((0.2_r8*exp(3.218_r8*tlai_z(p,iv))),1._r8) + lmr_z_sha(p,iv) = lmr_z_sha(p,iv)*min((0.2_r8*exp(3.218_r8*tlai_z(p,iv))),1._r8) + if (par_z_sun(p,iv) <= 0._r8) then ! night time vcmax_z(p,sun,iv) = 0._r8 @@ -3011,7 +3162,17 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & !zqz temporary signal for night time vegwp(p,sun)=1._r8 - call calcstress(p,c,vegwp(p,:),bsun(p),bsha(p),gb_mol(p),bbb(p),bbb(p), & + if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + gsminsun = bbb(p) + gsminsha = bbb(p) + else if ( stomatalcond_mtd == stomatalcond_mtd_medlyn2011 )then + gsminsun = medlynintercept(patch%itype(p)) + gsminsha = medlynintercept(patch%itype(p)) + else + gsminsun = nan + gsminsha = nan + end if + call calcstress(p,c,vegwp(p,:),bsun(p),bsha(p),gb_mol(p),gsminsun, gsminsha, & qsatl(p),qaf(p), atm2lnd_inst,canopystate_inst,waterstate_inst, & soilstate_inst,temperature_inst, waterflux_inst) @@ -3019,12 +3180,19 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & aj(p,sun,iv) = 0._r8 ap(p,sun,iv) = 0._r8 ag(p,sun,iv) = 0._r8 - an_sun(p,iv) = ag(p,sun,iv) - bsun(p) * lmr_z_sun(p,iv) +!KO an_sun(p,iv) = ag(p,sun,iv) - bsun(p) * lmr_z_sun(p,iv) +!KO + if(crop(patch%itype(p))== 0 .or. .not. modifyphoto_and_lmr_forcrop) then + an_sun(p,iv) = ag(p,sun,iv) - bsun(p) * lmr_z_sun(p,iv) + else + an_sun(p,iv) = ag(p,sun,iv) - lmr_z_sun(p,iv) + endif +!KO psn_z_sun(p,iv) = 0._r8 psn_wc_z_sun(p,iv) = 0._r8 psn_wj_z_sun(p,iv) = 0._r8 psn_wp_z_sun(p,iv) = 0._r8 - rs_z_sun(p,iv) = min(rsmax0, 1._r8/(max( bsun(p)*bbb(p), 1._r8 )) * cf) + rs_z_sun(p,iv) = min(rsmax0, 1._r8/(max( bsun(p)*gsminsun, 1._r8 )) * cf) ci_z_sun(p,iv) = 0._r8 rh_leaf_sun(p) = 0._r8 @@ -3032,12 +3200,19 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & aj(p,sha,iv) = 0._r8 ap(p,sha,iv) = 0._r8 ag(p,sha,iv) = 0._r8 - an_sha(p,iv) = ag(p,sha,iv) - bsha(p) * lmr_z_sha(p,iv) +!KO an_sha(p,iv) = ag(p,sha,iv) - bsha(p) * lmr_z_sha(p,iv) +!KO + if(crop(patch%itype(p))== 0 .or. .not. modifyphoto_and_lmr_forcrop) then + an_sha(p,iv) = ag(p,sha,iv) - bsha(p) * lmr_z_sha(p,iv) + else + an_sha(p,iv) = ag(p,sha,iv) - lmr_z_sha(p,iv) + endif +!KO psn_z_sha(p,iv) = 0._r8 psn_wc_z_sha(p,iv) = 0._r8 psn_wj_z_sha(p,iv) = 0._r8 psn_wp_z_sha(p,iv) = 0._r8 - rs_z_sha(p,iv) = min(rsmax0, 1._r8/(max( bsha(p)*bbb(p), 1._r8 )) * cf) + rs_z_sha(p,iv) = min(rsmax0, 1._r8/(max( bsha(p)*gsminsha, 1._r8 )) * cf) ci_z_sha(p,iv) = 0._r8 rh_leaf_sha(p) = 0._r8 @@ -3045,7 +3220,12 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & !now the constraint is no longer needed, Jinyun Tang ceair = min( eair(p), esat_tv(p) ) - rh_can = ceair / esat_tv(p) + if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + rh_can = ceair / esat_tv(p) + else if ( stomatalcond_mtd == stomatalcond_mtd_medlyn2011 )then + ! Put some constraints on RH in the canopy when Medlyn stomatal conductance is being used + rh_can = max((esat_tv(p) - ceair), 50._r8) * 0.001_r8 + end if ! Electron transport rate for C3 plants. Convert par from W/m2 to ! umol photons/m**2/s using the factor 4.6 @@ -3082,11 +3262,22 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & par_z_sun(p,iv), par_z_sha(p,iv), rh_can, gs_mol_sun(p,iv), gs_mol_sha(p,iv), & qsatl(p), qaf(p), iter1, iter2, atm2lnd_inst, photosyns_inst, & canopystate_inst, waterstate_inst, soilstate_inst, temperature_inst, waterflux_inst) + if ( stomatalcond_mtd == stomatalcond_mtd_medlyn2011 )then + gsminsun = medlynintercept(patch%itype(p)) + gsminsha = medlynintercept(patch%itype(p)) + gs_slope_sun = medlynslope(patch%itype(p)) + gs_slope_sha = medlynslope(patch%itype(p)) + else if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + gsminsun = bbb(p) + gsminsha = bbb(p) + gs_slope_sun = mbb(p) + gs_slope_sha = mbb(p) + end if ! End of ci iteration. Check for an < 0, in which case gs_mol = bbb - if (an_sun(p,iv) < 0._r8) gs_mol_sun(p,iv) = max( bsun(p)*bbb(p), 1._r8 ) - if (an_sha(p,iv) < 0._r8) gs_mol_sha(p,iv) = max( bsha(p)*bbb(p), 1._r8 ) + if (an_sun(p,iv) < 0._r8) gs_mol_sun(p,iv) = max( bsun(p)*gsminsun, 1._r8 ) + if (an_sha(p,iv) < 0._r8) gs_mol_sha(p,iv) = max( bsha(p)*gsminsha, 1._r8 ) ! Final estimates for cs and ci (needed for early exit of ci iteration when an < 0) @@ -3163,18 +3354,18 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & hs = (gb_mol(p)*ceair + gs_mol_sun(p,iv)*esat_tv(p)) / ((gb_mol(p)+gs_mol_sun(p,iv))*esat_tv(p)) rh_leaf_sun(p) = hs - gs_mol_err = mbb(p)*max(an_sun(p,iv), 0._r8)*hs/cs_sun*forc_pbot(c) + max( bsun(p)*bbb(p), 1._r8 ) + gs_mol_err = gs_slope_sun*max(an_sun(p,iv), 0._r8)*hs/cs_sun*forc_pbot(c) + max( bsun(p)*gsminsun, 1._r8 ) - if (abs(gs_mol_sun(p,iv)-gs_mol_err) > 1.e-01_r8) then + if (abs(gs_mol_sun(p,iv)-gs_mol_err) > 1.e-01_r8 .and. (stomatalcond_mtd == stomatalcond_mtd_bb1987) ) then write (iulog,*) 'Ball-Berry error check - sunlit stomatal conductance error:' write (iulog,*) gs_mol_sun(p,iv), gs_mol_err end if hs = (gb_mol(p)*ceair + gs_mol_sha(p,iv)*esat_tv(p)) / ((gb_mol(p)+gs_mol_sha(p,iv))*esat_tv(p)) rh_leaf_sha(p) = hs - gs_mol_err = mbb(p)*max(an_sha(p,iv), 0._r8)*hs/cs_sha*forc_pbot(c) + max( bsha(p)*bbb(p), 1._r8) + gs_mol_err = gs_slope_sha*max(an_sha(p,iv), 0._r8)*hs/cs_sha*forc_pbot(c) + max( bsha(p)*gsminsha, 1._r8) - if (abs(gs_mol_sha(p,iv)-gs_mol_err) > 1.e-01_r8) then + if (abs(gs_mol_sha(p,iv)-gs_mol_err) > 1.e-01_r8 .and. (stomatalcond_mtd == stomatalcond_mtd_bb1987) ) then write (iulog,*) 'Ball-Berry error check - shaded stomatal conductance error:' write (iulog,*) gs_mol_sha(p,iv), gs_mol_err end if @@ -3206,7 +3397,17 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & psncan_wc_sun = psncan_wc_sun + psn_wc_z_sun(p,iv) * lai_z_sun(p,iv) psncan_wj_sun = psncan_wj_sun + psn_wj_z_sun(p,iv) * lai_z_sun(p,iv) psncan_wp_sun = psncan_wp_sun + psn_wp_z_sun(p,iv) * lai_z_sun(p,iv) - lmrcan_sun = lmrcan_sun + lmr_z_sun(p,iv) * lai_z_sun(p,iv) +!KO lmrcan_sun = lmrcan_sun + lmr_z_sun(p,iv) * lai_z_sun(p,iv) +!KO +! lmrcan_sun = lmrcan_sun + lmr_z_sun(p,iv) * lai_z_sun(p,iv) * bsun(p) +!KO +!KO + if(crop(patch%itype(p))== 0 .and. modifyphoto_and_lmr_forcrop) then + lmrcan_sun = lmrcan_sun + lmr_z_sun(p,iv) * lai_z_sun(p,iv) * bsun(p) + else + lmrcan_sun = lmrcan_sun + lmr_z_sun(p,iv) * lai_z_sun(p,iv) + endif +!KO gscan_sun = gscan_sun + lai_z_sun(p,iv) / (rb(p)+rs_z_sun(p,iv)) laican_sun = laican_sun + lai_z_sun(p,iv) end do @@ -3237,7 +3438,17 @@ subroutine PhotosynthesisHydraulicStress ( bounds, fn, filterp, & psncan_wc_sha = psncan_wc_sha + psn_wc_z_sha(p,iv) * lai_z_sha(p,iv) psncan_wj_sha = psncan_wj_sha + psn_wj_z_sha(p,iv) * lai_z_sha(p,iv) psncan_wp_sha = psncan_wp_sha + psn_wp_z_sha(p,iv) * lai_z_sha(p,iv) - lmrcan_sha = lmrcan_sha + lmr_z_sha(p,iv) * lai_z_sha(p,iv) +!KO lmrcan_sha = lmrcan_sha + lmr_z_sha(p,iv) * lai_z_sha(p,iv) +!KO +! lmrcan_sha = lmrcan_sha + lmr_z_sha(p,iv) * lai_z_sha(p,iv) * bsha(p) +!KO +!KO + if(crop(patch%itype(p))== 0 .and. modifyphoto_and_lmr_forcrop) then + lmrcan_sha = lmrcan_sha + lmr_z_sha(p,iv) * lai_z_sha(p,iv) * bsha(p) + else + lmrcan_sha = lmrcan_sha + lmr_z_sha(p,iv) * lai_z_sha(p,iv) + endif +!KO gscan_sha = gscan_sha + lai_z_sha(p,iv) / (rb(p)+rs_z_sha(p,iv)) laican_sha = laican_sha + lai_z_sha(p,iv) end do @@ -3718,12 +3929,16 @@ subroutine ci_func_PHS(x,cisun, cisha, fvalsun, fvalsha, p, iv, c, bsun, bsha, b real(r8) :: fnps ! fraction of light absorbed by non-photosynthetic pigments real(r8) :: theta_psii ! empirical curvature parameter for electron transport rate real(r8) :: theta_ip ! empirical curvature parameter for ap photosynthesis co-limitation + real(r8) :: term ! intermediate in Medlyn stomatal model ! !------------------------------------------------------------------------------ associate( & forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] atmospheric pressure (Pa) c3flag => photosyns_inst%c3flag_patch , & ! Input: [logical (:) ] true if C3 and false if C4 + medlynslope=> pftcon%medlynslope , & ! Input: [real(r8) (:) ] Slope for Medlyn stomatal conductance model method + medlynintercept=> pftcon%medlynintercept , & ! Input: [real(r8) (:) ] Intercept for Medlyn stomatal conductance model method + stomatalcond_mtd=> photosyns_inst%stomatalcond_mtd , & ! Input: [integer ] method type to use for stomatal conductance.GC.fnlprmsn15_r22845 ac => photosyns_inst%ac_phs_patch , & ! Output: [real(r8) (:,:,:) ] Rubisco-limited gross photosynthesis (umol CO2/m**2/s) aj => photosyns_inst%aj_phs_patch , & ! Output: [real(r8) (:,:,:) ] RuBP-limited gross photosynthesis (umol CO2/m**2/s) ap => photosyns_inst%ap_phs_patch , & ! Output: [real(r8) (:,:,:) ] product-limited (C3) or CO2-limited (C4) gross photosynthesis (umol CO2/m**2/s) @@ -3816,11 +4031,25 @@ subroutine ci_func_PHS(x,cisun, cisha, fvalsun, fvalsha, p, iv, c, bsun, bsha, b an_sha(p,iv) = ag(p,sha,iv) - bsha * lmr_z_sha if (an_sun(p,iv) < 0._r8) then - gs_mol_sun = max( bsun*bbb(p), 1._r8) + if ( stomatalcond_mtd == stomatalcond_mtd_medlyn2011 )then + gs_mol_sun = medlynintercept(patch%itype(p)) + else if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + gs_mol_sun = bbb(p) + else + gs_mol_sun = nan + end if + gs_mol_sun = max( bsun*gs_mol_sun, 1._r8) fvalsun = 0._r8 ! really tho? zqz endif if (an_sha(p,iv) < 0._r8) then - gs_mol_sha = max( bsha*bbb(p), 1._r8) + if ( stomatalcond_mtd == stomatalcond_mtd_medlyn2011 )then + gs_mol_sha = medlynintercept(patch%itype(p)) + else if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + gs_mol_sha = bbb(p) + else + gs_mol_sha = nan + end if + gs_mol_sha = max( bsha*gs_mol_sha, 1._r8) fvalsha = 0._r8 endif if ((an_sun(p,iv) < 0._r8) .AND. (an_sha(p,iv) < 0._r8)) then @@ -3833,22 +4062,50 @@ subroutine ci_func_PHS(x,cisun, cisha, fvalsun, fvalsha, p, iv, c, bsun, bsha, b ! Sunlit cs_sun = cair - 1.4_r8/gb_mol * an_sun(p,iv) * forc_pbot(c) cs_sun = max(cs_sun,10.e-06_r8) + + if ( stomatalcond_mtd == stomatalcond_mtd_medlyn2011 )then + term = 1.6_r8 * an_sun(p,iv) / (cs_sun / forc_pbot(c) * 1.e06_r8) + aquad = 1.0_r8 + bquad = -(2.0 * (medlynintercept(patch%itype(p))*1.e-06_r8 + term) + (medlynslope(patch%itype(p)) * term)**2 / & + (gb_mol*1.e-06_r8 * rh_can)) + cquad = medlynintercept(patch%itype(p))*medlynintercept(patch%itype(p))*1.e-12_r8 + & + (2.0*medlynintercept(patch%itype(p))*1.e-06_r8 + term * & + (1.0 - medlynslope(patch%itype(p))* medlynslope(patch%itype(p)) / rh_can)) * term + + call quadratic (aquad, bquad, cquad, r1, r2) + gs_mol_sun = max(r1,r2) * 1.e06_r8 + + ! Shaded + cs_sha = cair - 1.4_r8/gb_mol * an_sha(p,iv) * forc_pbot(c) + cs_sha = max(cs_sha,10.e-06_r8) + + term = 1.6_r8 * an_sha(p,iv) / (cs_sha / forc_pbot(c) * 1.e06_r8) + aquad = 1.0_r8 + bquad = -(2.0 * (medlynintercept(patch%itype(p))*1.e-06_r8 + term) + (medlynslope(patch%itype(p)) * term)**2 / & + (gb_mol*1.e-06_r8 * rh_can)) + cquad = medlynintercept(patch%itype(p))*medlynintercept(patch%itype(p))*1.e-12_r8 + & + (2.0*medlynintercept(patch%itype(p))*1.e-06_r8 + term * (1.0 - medlynslope(patch%itype(p))* & + medlynslope(patch%itype(p)) / rh_can)) * term + + call quadratic (aquad, bquad, cquad, r1, r2) + gs_mol_sha = max(r1,r2)* 1.e06_r8 + else if ( stomatalcond_mtd == stomatalcond_mtd_bb1987 )then + aquad = cs_sun + bquad = cs_sun*(gb_mol - max(bsun*bbb(p),1._r8)) - mbb(p)*an_sun(p,iv)*forc_pbot(c) + cquad = -gb_mol*(cs_sun*max(bsun*bbb(p),1._r8) + mbb(p)*an_sun(p,iv)*forc_pbot(c)*rh_can) + call quadratic (aquad, bquad, cquad, r1, r2) + gs_mol_sun = max(r1,r2) - aquad = cs_sun - bquad = cs_sun*(gb_mol - max(bsun*bbb(p),1._r8)) - mbb(p)*an_sun(p,iv)*forc_pbot(c) - cquad = -gb_mol*(cs_sun*max(bsun*bbb(p),1._r8) + mbb(p)*an_sun(p,iv)*forc_pbot(c)*rh_can) - call quadratic (aquad, bquad, cquad, r1, r2) - gs_mol_sun = max(r1,r2) - - ! Shaded - cs_sha = cair - 1.4_r8/gb_mol * an_sha(p,iv) * forc_pbot(c) - cs_sha = max(cs_sha,10.e-06_r8) + ! Shaded + cs_sha = cair - 1.4_r8/gb_mol * an_sha(p,iv) * forc_pbot(c) + cs_sha = max(cs_sha,10.e-06_r8) - aquad = cs_sha - bquad = cs_sha*(gb_mol - max(bsha*bbb(p),1._r8)) - mbb(p)*an_sha(p,iv)*forc_pbot(c) - cquad = -gb_mol*(cs_sha*max(bsha*bbb(p),1._r8) + mbb(p)*an_sha(p,iv)*forc_pbot(c)*rh_can) - call quadratic (aquad, bquad, cquad, r1, r2) - gs_mol_sha = max(r1,r2) + aquad = cs_sha + bquad = cs_sha*(gb_mol - max(bsha*bbb(p),1._r8)) - mbb(p)*an_sha(p,iv)*forc_pbot(c) + cquad = -gb_mol*(cs_sha*max(bsha*bbb(p),1._r8) + mbb(p)*an_sha(p,iv)*forc_pbot(c)*rh_can) + call quadratic (aquad, bquad, cquad, r1, r2) + gs_mol_sha = max(r1,r2) + end if ! Derive new estimate for cisun,cisha if (an_sun(p,iv) >= 0._r8) then diff --git a/src/biogeophys/RootBiophysMod.F90 b/src/biogeophys/RootBiophysMod.F90 index efb6a2da3d..ba05705614 100644 --- a/src/biogeophys/RootBiophysMod.F90 +++ b/src/biogeophys/RootBiophysMod.F90 @@ -183,7 +183,7 @@ function zeng2001_rootfr(bounds, ubj) result(rootfr) use shr_assert_mod , only : shr_assert use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type - use pftconMod , only : noveg, pftcon + use pftconMod , only : pftcon use PatchType , only : patch use ColumnType , only : col ! @@ -205,7 +205,7 @@ function zeng2001_rootfr(bounds, ubj) result(rootfr) do p = bounds%begp,bounds%endp - if (patch%itype(p) /= noveg) then + if (.not. patch%is_fates(p)) then c = patch%column(p) do lev = 1, ubj-1 rootfr(p,lev) = .5_r8*( & @@ -239,7 +239,7 @@ function jackson1996_rootfr(bounds, ubj, varindx, water_carbon) result(rootfr) use shr_assert_mod , only : shr_assert use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type - use pftconMod , only : noveg, pftcon + use pftconMod , only : pftcon use PatchType , only : patch use ColumnType , only : col ! @@ -264,7 +264,7 @@ function jackson1996_rootfr(bounds, ubj, varindx, water_carbon) result(rootfr) rootfr(bounds%begp:bounds%endp, :) = 0._r8 do p = bounds%begp,bounds%endp c = patch%column(p) - if (patch%itype(p) /= noveg) then + if (.not.patch%is_fates(p)) then beta = pftcon%rootprof_beta(patch%itype(p),varindx) do lev = 1, ubj rootfr(p,lev) = ( & @@ -292,7 +292,7 @@ function exponential_rootfr(bounds, ubj) result(rootfr) use shr_assert_mod , only : shr_assert use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type - use pftconMod , only : noveg, pftcon + use pftconMod , only : pftcon use PatchType , only : patch use ColumnType , only : col ! @@ -313,7 +313,7 @@ function exponential_rootfr(bounds, ubj) result(rootfr) rootfr(bounds%begp:bounds%endp, :) = 0._r8 do p = bounds%begp,bounds%endp c = patch%column(p) - if (patch%itype(p) /= noveg) then + if (.not.patch%is_fates(p)) then do lev = 1, ubj rootfr(p,lev) = exp(-rootprof_exp * col%z(c,lev)) * col%dz(c,lev) end do diff --git a/src/biogeophys/SnowHydrologyMod.F90 b/src/biogeophys/SnowHydrologyMod.F90 index 6e289b7c77..15f3f57674 100644 --- a/src/biogeophys/SnowHydrologyMod.F90 +++ b/src/biogeophys/SnowHydrologyMod.F90 @@ -29,7 +29,10 @@ module SnowHydrologyMod use WaterfluxType , only : waterflux_type use WaterstateType , only : waterstate_type use LandunitType , only : lun + use TopoMod, only : topo_type use ColumnType , only : col + use landunit_varcon , only : istsoil, istdlak, istsoil, istwet, istice_mec, istcrop + use clm_time_manager, only : get_step_size, get_nstep ! ! !PUBLIC TYPES: implicit none @@ -48,6 +51,7 @@ module SnowHydrologyMod public :: NewSnowBulkDensity ! Compute bulk density of any newly-fallen snow ! The following are public just for the sake of unit testing: + public :: SnowCappingExcess ! Determine the excess snow that needs to be capped public :: SnowHydrologySetControlForTesting ! Set some of the control settings ! ! !PRIVATE MEMBER FUNCTIONS: @@ -74,6 +78,10 @@ module SnowHydrologyMod real(r8), public, parameter :: scvng_fct_mlt_dst3 = 0.01_r8 ! scavenging factor for dust species 3 inclusion in meltwater [frc] real(r8), public, parameter :: scvng_fct_mlt_dst4 = 0.01_r8 ! scavenging factor for dust species 4 inclusion in meltwater [frc] + ! The following are public for the sake of unit testing + integer, parameter, public :: LoTmpDnsSlater2017 = 2 ! For temperature below -15C use equation from Slater 2017 + integer, parameter, public :: LoTmpDnsTruncatedAnderson1976 = 1 ! Truncate low temp. snow density from the Anderson-1976 version at -15C + ! Definition of snow pack vertical structure ! Hardcoded maximum of 12 snowlayers, this is checked elsewhere (controlMod.F90) ! The bottom layer has no limit on thickness, hence the last element of the dzmax_* @@ -94,9 +102,6 @@ module SnowHydrologyMod integer, parameter :: OverburdenCompactionMethodAnderson1976 = 1 integer, parameter :: OverburdenCompactionMethodVionnet2012 = 2 - integer, parameter :: LoTmpDnsSlater2017 = 2 ! For temperature below -15C use equation from Slater 2017 - integer, parameter :: LoTmpDnsTruncatedAnderson1976 = 1 ! Truncate low temp. snow density from the Anderson-1976 version at -15C - ! If true, the density of new snow depends on wind speed, and there is also ! wind-dependent snow compaction logical :: wind_dependent_snow_density ! If snow density depends on wind or not @@ -106,6 +111,30 @@ module SnowHydrologyMod real(r8) :: overburden_compress_Tfactor = 0.08_r8 ! snow compaction overburden exponential factor (1/K) real(r8) :: min_wind_snowcompact = 5._r8 ! minimum wind speed tht results in compaction (m/s) + ! ------------------------------------------------------------------------ + ! Parameters controlling the resetting of the snow pack + ! ------------------------------------------------------------------------ + + logical :: reset_snow = .false. ! If set to true, we reset the non-glc snow pack, based on the following parameters + logical :: reset_snow_glc = .false. ! If set to true, we reset the glc snow pack, based reset_snow_glc_ela + + ! Default for reset_snow_glc_ela implies that snow will be reset for all glacier columns if reset_snow_glc = .true. + real(r8) :: reset_snow_glc_ela = 1.e9_r8 ! equilibrium line altitude (m); snow is reset for glacier columns below this elevation if reset_snow_glc = .true. (ignored if reset_snow_glc = .false.) + + ! The following are public simply to support unit testing + + ! 35 mm was chosen by Raymond Sellevold, based on finding the location in Greenland + ! with the least amount of snowfall from Sept. 1 (roughly the end of the melt season) + ! and Jan. 1 (when we typically start simulations). This location with the least amount + ! of snowfall had an average of 35 mm snow fall over this 4-month period. + real(r8), parameter, public :: reset_snow_h2osno = 35._r8 ! mm SWE to reset the snow pack to + + ! We scale the number of reset time steps with the number of snow layers, since we can + ! remove up to one layer per time step. In the absence of snow accumulation, we might + ! be able to get away with 1 reset time step per layer. However, we specify a larger + ! number to be more robust. + real(r8), parameter, public :: reset_snow_timesteps_per_layer = 4 + character(len=*), parameter, private :: sourcefile = & __FILE__ !----------------------------------------------------------------------- @@ -139,7 +168,8 @@ subroutine SnowHydrology_readnl( NLFilename) namelist /clm_snowhydrology_inparm/ & wind_dependent_snow_density, snow_overburden_compaction_method, & lotmp_snowdensity_method, upplim_destruct_metamorph, & - overburden_compress_Tfactor, min_wind_snowcompact + overburden_compress_Tfactor, min_wind_snowcompact, & + reset_snow, reset_snow_glc, reset_snow_glc_ela ! Initialize options to default values, in case they are not specified in the namelist wind_dependent_snow_density = .false. @@ -167,6 +197,9 @@ subroutine SnowHydrology_readnl( NLFilename) call shr_mpi_bcast (upplim_destruct_metamorph , mpicom) call shr_mpi_bcast (overburden_compress_Tfactor, mpicom) call shr_mpi_bcast (min_wind_snowcompact , mpicom) + call shr_mpi_bcast (reset_snow , mpicom) + call shr_mpi_bcast (reset_snow_glc , mpicom) + call shr_mpi_bcast (reset_snow_glc_ela , mpicom) if (masterproc) then write(iulog,*) ' ' @@ -214,8 +247,6 @@ subroutine SnowWater(bounds, & ! ! !USES: use clm_varcon , only : denh2o, denice, wimp, ssi - use landunit_varcon , only : istsoil - use clm_time_manager , only : get_step_size use AerosolMod , only : AerosolFluxes ! ! !ARGUMENTS: @@ -551,9 +582,7 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ! fraction after the melting versus before the melting. ! ! !USES: - use clm_time_manager, only : get_step_size use clm_varcon , only : denice, denh2o, tfrz, rpi, int_snow_max - use landunit_varcon , only : istdlak, istsoil, istcrop use clm_varctl , only : subgridflag ! ! !ARGUMENTS: @@ -752,9 +781,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & ! clm\_combo.f90 then executes the combination of mass and energy. ! ! !USES: - use landunit_varcon , only : istsoil, istdlak, istsoil, istwet, istice, istice_mec, istcrop use LakeCon , only : lsadz - use clm_time_manager , only : get_step_size ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -974,7 +1001,7 @@ subroutine CombineSnowLayers(bounds, num_snowc, filter_snowc, & if (ltype(l) == istwet) then h2osoi_liq(c,0) = 0.0_r8 endif - if (ltype(l) == istice .or. ltype(l)==istice_mec) then + if (ltype(l)==istice_mec) then h2osoi_liq(c,0) = 0.0_r8 endif endif @@ -1531,7 +1558,7 @@ end subroutine InitSnowLayers !----------------------------------------------------------------------- subroutine SnowCapping(bounds, num_initc, filter_initc, num_snowc, filter_snowc, & - aerosol_inst, waterflux_inst, waterstate_inst ) + aerosol_inst, waterflux_inst, waterstate_inst, topo_inst ) ! ! !DESCRIPTION: ! Removes mass from bottom snow layer for columns that exceed the maximum snow depth. @@ -1541,9 +1568,6 @@ subroutine SnowCapping(bounds, num_initc, filter_initc, num_snowc, filter_snowc, ! Density and temperature of the layer are conserved (density needs some work, temperature is a state ! variable) ! - ! !USES: - use clm_time_manager , only : get_step_size - ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_initc ! number of column points that need to be initialized @@ -1553,15 +1577,20 @@ subroutine SnowCapping(bounds, num_initc, filter_initc, num_snowc, filter_snowc, type(aerosol_type) , intent(inout) :: aerosol_inst type(waterflux_type) , intent(inout) :: waterflux_inst type(waterstate_type) , intent(inout) :: waterstate_inst + class(topo_type) , intent(in) :: topo_inst ! ! !LOCAL VARIABLES: real(r8) :: dtime ! land model time step (sec) real(r8) :: mss_snwcp_tot ! total snow capping mass [kg/m2] real(r8) :: mss_snow_bottom_lyr ! total snow mass (ice+liquid) in bottom layer [kg/m2] + real(r8) :: snwcp_flux_ice ! snow capping flux (ice) [kg/m2] + real(r8) :: snwcp_flux_liq ! snow capping flux (liquid) [kg/m2] real(r8) :: icefrac ! fraction of ice mass w.r.t. total mass [unitless] real(r8) :: frac_adjust ! fraction of mass remaining after capping real(r8) :: rho ! partial density of ice (not scaled with frac_sno) [kg/m3] integer :: fc, c ! counters + real(r8) :: h2osno_excess(bounds%begc:bounds%endc) ! excess snow that needs to be capped [mm H2O] + logical :: apply_runoff(bounds%begc:bounds%endc) ! for columns with capping, whether the capping flux should be sent to runoff ! Always keep at least this fraction of the bottom snow layer when doing snow capping ! This needs to be slightly greater than 0 to avoid roundoff problems real(r8), parameter :: min_snow_to_keep = 1.e-9 ! fraction of bottom snow layer to keep with capping @@ -1570,6 +1599,8 @@ subroutine SnowCapping(bounds, num_initc, filter_initc, num_snowc, filter_snowc, associate( & qflx_snwcp_ice => waterflux_inst%qflx_snwcp_ice_col , & ! Output: [real(r8) (:) ] excess solid h2o due to snow capping (outgoing) (mm H2O /s) [+] qflx_snwcp_liq => waterflux_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess liquid h2o due to snow capping (outgoing) (mm H2O /s) [+] + qflx_snwcp_discarded_ice => waterflux_inst%qflx_snwcp_discarded_ice_col, & ! Output: [real(r8) (:) ] excess solid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) [+] + qflx_snwcp_discarded_liq => waterflux_inst%qflx_snwcp_discarded_liq_col, & ! Output: [real(r8) (:) ] excess liquid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) [+] h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! In/Out: [real(r8) (:,:) ] ice lens (kg/m2) h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! In/Out: [real(r8) (:,:) ] liquid water (kg/m2) h2osno => waterstate_inst%h2osno_col , & ! Input: [real(r8) (:) ] snow water (mm H2O) @@ -1581,6 +1612,7 @@ subroutine SnowCapping(bounds, num_initc, filter_initc, num_snowc, filter_snowc, mss_dst2 => aerosol_inst%mss_dst2_col , & ! In/Out: [real(r8) (:,:) ] dust species 2 mass in snow (col,lyr) [kg] mss_dst3 => aerosol_inst%mss_dst3_col , & ! In/Out: [real(r8) (:,:) ] dust species 3 mass in snow (col,lyr) [kg] mss_dst4 => aerosol_inst%mss_dst4_col , & ! In/Out: [real(r8) (:,:) ] dust species 4 mass in snow (col,lyr) [kg] + topo => topo_inst%topo_col , & ! Input : [real(r8) (:) ] column surface height (m) dz => col%dz & ! In/Out: [real(r8) (:,:) ] layer depth (m) ) @@ -1592,25 +1624,40 @@ subroutine SnowCapping(bounds, num_initc, filter_initc, num_snowc, filter_snowc, c = filter_initc(fc) qflx_snwcp_ice(c) = 0.0_r8 qflx_snwcp_liq(c) = 0.0_r8 + qflx_snwcp_discarded_ice(c) = 0.0_r8 + qflx_snwcp_discarded_liq(c) = 0.0_r8 end do + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno = h2osno(bounds%begc:bounds%endc), & + topo = topo(bounds%begc:bounds%endc), & + h2osno_excess = h2osno_excess(bounds%begc:bounds%endc), & + apply_runoff = apply_runoff(bounds%begc:bounds%endc)) + loop_columns: do fc = 1, num_snowc c = filter_snowc(fc) - if (h2osno(c) > h2osno_max) then + if (h2osno_excess(c) > 0._r8) then mss_snow_bottom_lyr = h2osoi_ice(c,0) + h2osoi_liq(c,0) - mss_snwcp_tot = min(h2osno(c)-h2osno_max, mss_snow_bottom_lyr * (1._r8 - min_snow_to_keep)) ! Can't remove more mass than available + mss_snwcp_tot = min(h2osno_excess(c), mss_snow_bottom_lyr * (1._r8 - min_snow_to_keep)) ! Can't remove more mass than available ! Ratio of snow/liquid in bottom layer determines partitioning of runoff fluxes icefrac = h2osoi_ice(c,0) / mss_snow_bottom_lyr - qflx_snwcp_ice(c) = mss_snwcp_tot/dtime * icefrac - qflx_snwcp_liq(c) = mss_snwcp_tot/dtime * (1._r8 - icefrac) + snwcp_flux_ice = mss_snwcp_tot/dtime * icefrac + snwcp_flux_liq = mss_snwcp_tot/dtime * (1._r8 - icefrac) + if (apply_runoff(c)) then + qflx_snwcp_ice(c) = snwcp_flux_ice + qflx_snwcp_liq(c) = snwcp_flux_liq + else + qflx_snwcp_discarded_ice(c) = snwcp_flux_ice + qflx_snwcp_discarded_liq(c) = snwcp_flux_liq + end if rho = h2osoi_ice(c,0) / dz(c,0) ! ice only ! Adjust water content - h2osoi_ice(c,0) = h2osoi_ice(c,0) - qflx_snwcp_ice(c)*dtime - h2osoi_liq(c,0) = h2osoi_liq(c,0) - qflx_snwcp_liq(c)*dtime + h2osoi_ice(c,0) = h2osoi_ice(c,0) - snwcp_flux_ice*dtime + h2osoi_liq(c,0) = h2osoi_liq(c,0) - snwcp_flux_liq*dtime ! Scale dz such that ice density (or: pore space) is conserved ! @@ -1647,6 +1694,86 @@ subroutine SnowCapping(bounds, num_initc, filter_initc, num_snowc, filter_snowc, end associate end subroutine SnowCapping + !----------------------------------------------------------------------- + subroutine SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno, topo, h2osno_excess, apply_runoff) + ! + ! !DESCRIPTION: + ! Determine the amount of excess snow that needs to be capped + ! + ! !USES: + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + integer , intent(in) :: num_snowc ! number of column snow points in column filter + integer , intent(in) :: filter_snowc(:) ! column filter for snow points + real(r8) , intent(in) :: h2osno( bounds%begc: ) ! snow water (mm H2O) + real(r8) , intent(in) :: topo( bounds%begc: ) ! column surface height (m) + real(r8) , intent(out) :: h2osno_excess( bounds%begc: ) ! excess snow that needs to be capped (mm H2O) + logical , intent(out) :: apply_runoff( bounds%begc: ) ! whether capped snow should be sent to runoff; only valid where h2osno_excess > 0 + ! + ! !LOCAL VARIABLES: + integer :: fc, c, l + integer :: reset_snow_timesteps + logical :: is_reset_snow_active ! whether snow resetting is active in this time step for at least some points + + character(len=*), parameter :: subname = 'SnowCappingExcess' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(h2osno) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(topo) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(h2osno_excess) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(apply_runoff) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + do fc = 1, num_snowc + c = filter_snowc(fc) + h2osno_excess(c) = 0._r8 + if (h2osno(c) > h2osno_max) then + h2osno_excess(c) = h2osno(c) - h2osno_max + apply_runoff(c) = .true. + end if + end do + + ! Implement snow resetting (i.e., resetting points that have h2osno greater than some + ! value) by applying the snow capping scheme to a value that's smaller than + ! h2osno_max, but NOT sending the resulting capping flux to the coupler. It is easier + ! to implement the resetting this way than to try to manually reset the snow pack, + ! because there are so many snow pack variables that need to be kept consistent if + ! doing this resetting manually. Note that we need to continue to apply the resetting + ! for some number of time steps, because we can remove at most one snow layer per + ! time step. + + ! It is important that this snow resetting comes after the standard check (h2osno(c) > + ! h2osno_max), so that we override any standard capping. + is_reset_snow_active = .false. + if (reset_snow .or. reset_snow_glc) then + reset_snow_timesteps = reset_snow_timesteps_per_layer * nlevsno + if (get_nstep() <= reset_snow_timesteps) then + is_reset_snow_active = .true. + end if + end if + + if (is_reset_snow_active) then + do fc = 1, num_snowc + c = filter_snowc(fc) + l = col%landunit(c) + if ((lun%itype(l) /= istice_mec) .and. & + reset_snow .and. & + (h2osno(c) > reset_snow_h2osno)) then + h2osno_excess(c) = h2osno(c) - reset_snow_h2osno + apply_runoff(c) = .false. + else if ((lun%itype(l) == istice_mec) .and. & + reset_snow_glc .and. & + (h2osno(c) > reset_snow_h2osno) .and. & + (topo(c) <= reset_snow_glc_ela)) then + h2osno_excess(c) = h2osno(c) - reset_snow_h2osno + apply_runoff(c) = .false. + end if + end do + end if + + end subroutine SnowCappingExcess + !----------------------------------------------------------------------- subroutine NewSnowBulkDensity(bounds, num_c, filter_c, atm2lnd_inst, bifall) ! @@ -1668,6 +1795,7 @@ subroutine NewSnowBulkDensity(bounds, num_c, filter_c, atm2lnd_inst, bifall) ! ! !LOCAL VARIABLES: integer :: fc, c, g + real(r8) :: t_for_bifall_degC ! temperature to use in bifall equation (deg C) character(len=*), parameter :: subname = 'NewSnowBulkDensity' !----------------------------------------------------------------------- @@ -1694,7 +1822,14 @@ subroutine NewSnowBulkDensity(bounds, num_c, filter_c, atm2lnd_inst, bifall) ! "blower" powder, but as you get colder the flake size decreases so ! density goes up. e.g. the smaller snow crystals from the Arctic and Antarctic ! winters - bifall(c) = -(50._r8/15._r8 + 0.0333_r8*15_r8)*(forc_t(c)-tfrz) - 0.0333_r8*(forc_t(c)-tfrz)**2 + if (forc_t(c) > tfrz - 57.55_r8) then + t_for_bifall_degC = (forc_t(c)-tfrz) + else + ! Below -57.55 deg C, the following function starts to decrease with + ! decreasing temperatures. Limit the function to avoid this turning over. + t_for_bifall_degC = -57.55_r8 + end if + bifall(c) = -(50._r8/15._r8 + 0.0333_r8*15_r8)*t_for_bifall_degC - 0.0333_r8*t_for_bifall_degC**2 end if if (wind_dependent_snow_density .and. forc_wind(g) > 0.1_r8 ) then @@ -1740,7 +1875,7 @@ pure function OverburdenCompactionAnderson1976(burden, wx, td, bi) & end function OverburdenCompactionAnderson1976 !----------------------------------------------------------------------- - pure function OverburdenCompactionVionnet2012(h2osoi_liq, dz, burden, wx, td, bi) & + function OverburdenCompactionVionnet2012(h2osoi_liq, dz, burden, wx, td, bi) & result(compaction_rate) ! ! !DESCRIPTION: @@ -1816,7 +1951,7 @@ subroutine WindDriftCompaction(bi, forc_wind, dz, & real(r8) :: MO ! Mobility index [-] real(r8) :: SI ! Driftability index [-] real(r8) :: gamma_drift ! Scaling factor for wind drift time scale [-] - real(r8) :: tau ! Effective time scale [s] + real(r8) :: tau_inverse ! Inverse of the effective time scale [1/s] real(r8), parameter :: rho_min = 50._r8 ! wind drift compaction / minimum density [kg/m3] real(r8), parameter :: rho_max = 350._r8 ! wind drift compaction / maximum density [kg/m3] @@ -1839,8 +1974,8 @@ subroutine WindDriftCompaction(bi, forc_wind, dz, & ! the pseudo-node for the sake of the following calculation zpseudo = zpseudo + 0.5_r8 * dz * (3.25_r8 - SI) gamma_drift = SI*exp(-zpseudo/0.1_r8) - tau = tau_ref / gamma_drift - compaction_rate = -max(0.0_r8, rho_max-bi)/tau + tau_inverse = gamma_drift / tau_ref + compaction_rate = -max(0.0_r8, rho_max-bi) * tau_inverse ! Further increase zpseudo to the bottom of the pseudo-node for ! the sake of calculations done on the underlying layer (i.e., ! the next time through the j loop). @@ -1971,7 +2106,8 @@ subroutine BuildSnowFilter(bounds, num_nolakec, filter_nolakec, & end do end subroutine BuildSnowFilter - subroutine SnowHydrologySetControlForTesting( set_winddep_snowdensity, set_new_snow_density ) + subroutine SnowHydrologySetControlForTesting( set_winddep_snowdensity, set_new_snow_density, & + set_reset_snow, set_reset_snow_glc, set_reset_snow_glc_ela) ! ! !DESCRIPTION: ! Sets some of the control settings for SnowHydrologyMod @@ -1980,11 +2116,27 @@ subroutine SnowHydrologySetControlForTesting( set_winddep_snowdensity, set_new_s ! !USES: ! ! !ARGUMENTS: - logical, intent(in) :: set_winddep_snowdensity ! Set wind dependent snow density - integer, intent(in) :: set_new_snow_density ! snow density method + logical, intent(in), optional :: set_winddep_snowdensity ! Set wind dependent snow density + integer, intent(in), optional :: set_new_snow_density ! snow density method + logical, intent(in), optional :: set_reset_snow ! whether to reset the snow pack, non-glc_mec points + logical, intent(in), optional :: set_reset_snow_glc ! whether to reset the snow pack, glc_mec points + real(r8), intent(in), optional :: set_reset_snow_glc_ela ! elevation below which to reset the snow pack if set_reset_snow_glc is true (m) !----------------------------------------------------------------------- - wind_dependent_snow_density = set_winddep_snowdensity - new_snow_density = set_new_snow_density + if (present(set_winddep_snowdensity)) then + wind_dependent_snow_density = set_winddep_snowdensity + end if + if (present(set_new_snow_density)) then + new_snow_density = set_new_snow_density + end if + if (present(set_reset_snow)) then + reset_snow = set_reset_snow + end if + if (present(set_reset_snow_glc)) then + reset_snow_glc = set_reset_snow_glc + end if + if (present(set_reset_snow_glc_ela)) then + reset_snow_glc_ela = set_reset_snow_glc_ela + end if end subroutine SnowHydrologySetControlForTesting diff --git a/src/biogeophys/SnowSnicarMod.F90 b/src/biogeophys/SnowSnicarMod.F90 index 99963739d3..d8a4ebdabb 100644 --- a/src/biogeophys/SnowSnicarMod.F90 +++ b/src/biogeophys/SnowSnicarMod.F90 @@ -12,11 +12,12 @@ module SnowSnicarMod use shr_sys_mod , only : shr_sys_flush use shr_log_mod , only : errMsg => shr_log_errMsg use clm_varctl , only : iulog - use clm_varcon , only : namec + use clm_varcon , only : namec , tfrz use shr_const_mod , only : SHR_CONST_RHOICE use abortutils , only : endrun use decompMod , only : bounds_type use AerosolMod , only : snw_rds_min + use atm2lndType , only : atm2lnd_type use WaterStateType , only : waterstate_type use WaterFluxType , only : waterflux_type use TemperatureType , only : temperature_type @@ -55,6 +56,7 @@ module SnowSnicarMod integer, parameter :: snw_rds_max_tbl = 1500 ! maximum effective radius defined in Mie lookup table [microns] integer, parameter :: snw_rds_min_tbl = 30 ! minimium effective radius defined in Mie lookup table [microns] + integer, parameter :: snw_rds_min_int = nint(snw_rds_min) ! minimum allowed snow effective radius as integer [microns] real(r8), parameter :: snw_rds_max = 1500._r8 ! maximum allowed snow effective radius [microns] real(r8), parameter :: snw_rds_refrz = 1000._r8 ! effective radius of re-frozen snow [microns] @@ -369,7 +371,7 @@ subroutine SNICAR_RT (flg_snw_ice, bounds, num_nourbanc, filter_nourbanc, & snl_lcl = -1 h2osno_ice_lcl(0) = h2osno_lcl h2osno_liq_lcl(0) = 0._r8 - snw_rds_lcl(0) = nint(snw_rds_min) + snw_rds_lcl(0) = snw_rds_min_int else flg_nosnl = 0 snl_lcl = snl(c_idx) @@ -986,7 +988,7 @@ end subroutine SNICAR_RT !----------------------------------------------------------------------- subroutine SnowAge_grain(bounds, & num_snowc, filter_snowc, num_nosnowc, filter_nosnowc, & - waterflux_inst, waterstate_inst, temperature_inst) + waterflux_inst, waterstate_inst, temperature_inst, atm2lnd_inst) ! ! !DESCRIPTION: ! Updates the snow effective grain size (radius). @@ -1036,6 +1038,7 @@ subroutine SnowAge_grain(bounds, & type(waterflux_type) , intent(in) :: waterflux_inst type(waterstate_type) , intent(inout) :: waterstate_inst type(temperature_type) , intent(inout) :: temperature_inst + type(atm2lnd_type) , intent(in) :: atm2lnd_inst ! ! !LOCAL VARIABLES: integer :: snl_top ! top snow layer index [idx] @@ -1065,6 +1068,7 @@ subroutine SnowAge_grain(bounds, & real(r8) :: rhos ! snow density [kg m-3] real(r8) :: h2osno_lyr ! liquid + solid H2O in snow layer [kg m-2] real(r8) :: cdz(-nlevsno+1:0) ! column average layer thickness [m] + real(r8) :: snw_rds_fresh ! fresh snow radius [microns] !--------------------------------------------------------------------------! associate( & @@ -1163,6 +1167,11 @@ subroutine SnowAge_grain(bounds, & bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx) + !LvK extra boundary check, to prevent when using old restart file with lower snw_rds_min than current run + if (snw_rds(c_idx,i) < snw_rds_min) then + snw_rds(c_idx,i) = snw_rds_min + endif + ! change in snow effective radius, using best-fit parameters dr_fresh = snw_rds(c_idx,i)-snw_rds_min dr = (bst_drdt0*(bst_tau/(dr_fresh+bst_tau))**(1/bst_kappa)) * (dtime/3600) @@ -1223,8 +1232,11 @@ subroutine SnowAge_grain(bounds, & frc_oldsnow = 1._r8 - frc_refrz - frc_newsnow endif + ! temperature dependent fresh grain size + snw_rds_fresh = FreshSnowRadius(c_idx, atm2lnd_inst) + ! mass-weighted mean of fresh snow, old snow, and re-frozen snow effective radius - snw_rds(c_idx,i) = (snw_rds(c_idx,i)+dr)*frc_oldsnow + snw_rds_min*frc_newsnow + snw_rds_refrz*frc_refrz + snw_rds(c_idx,i) = (snw_rds(c_idx,i)+dr)*frc_oldsnow + snw_rds_fresh*frc_newsnow + snw_rds_refrz*frc_refrz ! !********** 5. CHECK BOUNDARIES *********** ! @@ -1261,6 +1273,58 @@ subroutine SnowAge_grain(bounds, & end subroutine SnowAge_grain + + !----------------------------------------------------------------------- + real(r8) function FreshSnowRadius(c_idx, atm2lnd_inst) + ! + ! !DESCRIPTION: + ! Returns fresh snow grain radius, which is linearly dependent on temperature. + ! This is implemented to remedy an outstanding bias that SNICAR has in initial + ! grain size. See e.g. Sandells et al, 2017 for a discussion (10.5194/tc-11-229-2017). + ! + ! Yang et al. (2017), 10.1016/j.jqsrt.2016.03.033 + ! discusses grain size observations, which suggest a temperature dependence. + ! + ! !REVISION HISTORY: + ! Author: Leo VanKampenhout + ! + ! !USES: + use AerosolMod , only : fresh_snw_rds_max + ! !ARGUMENTS: + integer, intent(in) :: c_idx ! column index + type(atm2lnd_type) , intent(in) :: atm2lnd_inst ! Forcing from atmosphere + ! + ! !LOCAL VARIABLES: + !----------------------------------------------------------------------- + real(r8), parameter :: tmin = tfrz - 30._r8 ! start of linear ramp + real(r8), parameter :: tmax = tfrz - 0._r8 ! end of linear ramp + real(r8), parameter :: gs_min = snw_rds_min ! minimum value + real(r8) :: gs_max ! maximum value + + associate( & + forc_t => atm2lnd_inst%forc_t_downscaled_col & ! Input: [real(r8) (:) ] atmospheric temperature (Kelvin) + ) + if ( fresh_snw_rds_max <= snw_rds_min )then + FreshSnowRadius = snw_rds_min + else + gs_max = fresh_snw_rds_max + + if (forc_t(c_idx) < tmin) then + FreshSnowRadius = gs_min + else if (forc_t(c_idx) > tmax) then + FreshSnowRadius = gs_max + else + FreshSnowRadius = (tmax-forc_t(c_idx))/(tmax-tmin)*gs_min + & + (forc_t(c_idx)-tmin)/(tmax-tmin)*gs_max + end if + end if + + end associate + + end function FreshSnowRadius + + + !----------------------------------------------------------------------- subroutine SnowOptics_init( ) diff --git a/src/biogeophys/SoilFluxesMod.F90 b/src/biogeophys/SoilFluxesMod.F90 index 7384218eb1..81d05478e8 100644 --- a/src/biogeophys/SoilFluxesMod.F90 +++ b/src/biogeophys/SoilFluxesMod.F90 @@ -126,9 +126,9 @@ subroutine SoilFluxes (bounds, num_urbanl, filter_urbanl, & qflx_sub_snow => waterflux_inst%qflx_sub_snow_patch , & ! Output: [real(r8) (:) ] sublimation rate from snow pack (mm H2O /s) [+] qflx_dew_snow => waterflux_inst%qflx_dew_snow_patch , & ! Output: [real(r8) (:) ] surface dew added to snow pack (mm H2O /s) [+] qflx_dew_grnd => waterflux_inst%qflx_dew_grnd_patch , & ! Output: [real(r8) (:) ] ground surface dew formation (mm H2O /s) [+] - qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! In/Out: [real(r8) (:) ] evaporation flux from snow (W/m**2) [+ to atm] - qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! In/Out: [real(r8) (:) ] evaporation flux from soil (W/m**2) [+ to atm] - qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! In/Out: [real(r8) (:) ] evaporation flux from soil (W/m**2) [+ to atm] + qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! In/Out: [real(r8) (:) ] evaporation flux from snow (mm H2O/s) [+ to atm] + qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! In/Out: [real(r8) (:) ] evaporation flux from soil (mm H2O/s) [+ to atm] + qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! In/Out: [real(r8) (:) ] evaporation flux from soil (mm H2O/s) [+ to atm] eflx_sh_grnd => energyflux_inst%eflx_sh_grnd_patch , & ! Output: [real(r8) (:) ] sensible heat flux from ground (W/m**2) [+ to atm] eflx_sh_veg => energyflux_inst%eflx_sh_veg_patch , & ! Output: [real(r8) (:) ] sensible heat flux from leaves (W/m**2) [+ to atm] diff --git a/src/biogeophys/SoilHydrologyInitTimeConstMod.F90 b/src/biogeophys/SoilHydrologyInitTimeConstMod.F90 index 08426656e3..b399b1042a 100644 --- a/src/biogeophys/SoilHydrologyInitTimeConstMod.F90 +++ b/src/biogeophys/SoilHydrologyInitTimeConstMod.F90 @@ -40,7 +40,8 @@ subroutine SoilHydrologyInitTimeConst(bounds, soilhydrology_inst) use clm_varpar , only : nlevsoifl, toplev_equalspace use clm_varpar , only : nlevsoi, nlevgrnd, nlevsno, nlevlak, nlevurb, nlayer, nlayert use clm_varcon , only : zsoi, dzsoi, zisoi, spval, nlvic, dzvic, pc, grlnd - use landunit_varcon , only : istice, istwet, istsoil, istdlak, istcrop, istice_mec + use clm_varcon , only : aquifer_water_baseline + use landunit_varcon , only : istwet, istsoil, istdlak, istcrop, istice_mec use column_varcon , only : icol_shadewall, icol_road_perv, icol_road_imperv, icol_roof, icol_sunwall use fileutils , only : getfil use organicFileMod , only : organicrd @@ -80,7 +81,7 @@ subroutine SoilHydrologyInitTimeConst(bounds, soilhydrology_inst) ! Initialize frost table ! ----------------------------------------------------------------- - soilhydrology_inst%wa_col(bounds%begc:bounds%endc) = 5000._r8 + soilhydrology_inst%wa_col(bounds%begc:bounds%endc) = aquifer_water_baseline soilhydrology_inst%zwt_col(bounds%begc:bounds%endc) = 0._r8 do c = bounds%begc,bounds%endc @@ -88,6 +89,8 @@ subroutine SoilHydrologyInitTimeConst(bounds, soilhydrology_inst) if (.not. lun%lakpoi(l)) then !not lake if (lun%urbpoi(l)) then if (col%itype(c) == icol_road_perv) then + ! Note that the following hard-coded constants (on the next two lines) + ! seem implicitly related to aquifer_water_baseline soilhydrology_inst%wa_col(c) = 4800._r8 soilhydrology_inst%zwt_col(c) = (25._r8 + col%zi(c,nlevsoi)) - soilhydrology_inst%wa_col(c)/0.2_r8 /1000._r8 ! One meter below soil column else @@ -98,6 +101,8 @@ subroutine SoilHydrologyInitTimeConst(bounds, soilhydrology_inst) soilhydrology_inst%zwt_perched_col(c) = spval soilhydrology_inst%frost_table_col(c) = spval else + ! Note that the following hard-coded constants (on the next two lines) seem + ! implicitly related to aquifer_water_baseline soilhydrology_inst%wa_col(c) = 4000._r8 soilhydrology_inst%zwt_col(c) = (25._r8 + col%zi(c,nlevsoi)) - soilhydrology_inst%wa_col(c)/0.2_r8 /1000._r8 ! One meter below soil column ! initialize frost_table, zwt_perched to bottom of soil column @@ -232,7 +237,7 @@ subroutine SoilHydrologyInitTimeConst(bounds, soilhydrology_inst) l = col%landunit(c) if (lun%itype(l) /= istdlak) then ! soil columns of both urban and non-urban types - if (lun%itype(l)==istwet .or. lun%itype(l)==istice .or. lun%itype(l)==istice_mec) then + if (lun%itype(l)==istwet .or. lun%itype(l)==istice_mec) then ! do nothing else if (lun%urbpoi(l) .and. (col%itype(c) /= icol_road_perv) .and. (col%itype(c) /= icol_road_imperv) )then ! do nothing diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index e94b015263..4dff518f66 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -8,7 +8,7 @@ module SoilHydrologyMod use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use clm_varctl , only : iulog, use_vichydro - use clm_varcon , only : e_ice, denh2o, denice, rpi + use clm_varcon , only : e_ice, denh2o, denice, rpi, aquifer_water_baseline use clm_varcon , only : ispval use EnergyFluxType , only : energyflux_type use SoilHydrologyType , only : soilhydrology_type @@ -401,11 +401,11 @@ subroutine Infiltration(bounds, & h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) h2osfc => waterstate_inst%h2osfc_col , & ! Output: [real(r8) (:) ] surface water (mm) - qflx_ev_soil => waterflux_inst%qflx_ev_soil_col , & ! Input: [real(r8) (:) ] evaporation flux from soil (W/m**2) [+ to atm] + qflx_ev_soil => waterflux_inst%qflx_ev_soil_col , & ! Input: [real(r8) (:) ] evaporation flux from soil (mm H2O/s) [+ to atm] qflx_evap_soi => waterflux_inst%qflx_evap_soi_col , & ! Input: [real(r8) (:) ] ground surface evaporation rate (mm H2O/s) [+] qflx_evap_grnd => waterflux_inst%qflx_evap_grnd_col , & ! Input: [real(r8) (:) ] ground surface evaporation rate (mm H2O/s) [+] qflx_top_soil => waterflux_inst%qflx_top_soil_col , & ! Input: [real(r8) (:) ] net water input into soil from top (mm/s) - qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_col , & ! Input: [real(r8) (:) ] evaporation flux from h2osfc (W/m**2) [+ to atm] + qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_col , & ! Input: [real(r8) (:) ] evaporation flux from h2osfc (mm H2O/s) [+ to atm] qflx_surf => waterflux_inst%qflx_surf_col , & ! Output: [real(r8) (:) ] surface runoff (mm H2O /s) qflx_h2osfc_surf => waterflux_inst%qflx_h2osfc_surf_col , & ! Output: [real(r8) (:) ] surface water runoff (mm/s) qflx_infl => waterflux_inst%qflx_infl_col , & ! Output: [real(r8) (:) ] infiltration (mm H2O /s) @@ -1271,8 +1271,8 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte if(jwt(c) == nlevsoi) then wa(c) = wa(c) - rsub_top(c) * dtime zwt(c) = zwt(c) + (rsub_top(c) * dtime)/1000._r8/rous - h2osoi_liq(c,nlevsoi) = h2osoi_liq(c,nlevsoi) + max(0._r8,(wa(c)-5000._r8)) - wa(c) = min(wa(c), 5000._r8) + h2osoi_liq(c,nlevsoi) = h2osoi_liq(c,nlevsoi) + max(0._r8,(wa(c)-aquifer_water_baseline)) + wa(c) = min(wa(c), aquifer_water_baseline) else !-- water table within soil layers 1-9 ------------------------------------- !============================== RSUB_TOP ========================================= diff --git a/src/biogeophys/SoilHydrologyType.F90 b/src/biogeophys/SoilHydrologyType.F90 index 89991efcca..33aee7efda 100644 --- a/src/biogeophys/SoilHydrologyType.F90 +++ b/src/biogeophys/SoilHydrologyType.F90 @@ -192,7 +192,7 @@ subroutine InitHistory(this, bounds) this%frost_table_col(begc:endc) = spval call hist_addfld1d (fname='FROST_TABLE', units='m', & avgflag='A', long_name='frost table depth (vegetated landunits only)', & - ptr_col=this%frost_table_col, l2g_scale_type='veg') + ptr_col=this%frost_table_col, l2g_scale_type='veg', default='inactive') this%zwt_col(begc:endc) = spval call hist_addfld1d (fname='ZWT', units='m', & diff --git a/src/biogeophys/SoilMoistStressMod.F90 b/src/biogeophys/SoilMoistStressMod.F90 index 2e14bbb6a8..c472d66dbf 100644 --- a/src/biogeophys/SoilMoistStressMod.F90 +++ b/src/biogeophys/SoilMoistStressMod.F90 @@ -210,6 +210,7 @@ subroutine calc_volumetric_h2oliq(bounds, jtop, lbj, ubj, numf, filter,& do fc = 1, numf c = filter(fc) if(j>=jtop(c))then + !volume of liquid is no greater than effective void space vol_liq(c,j) = min(eff_porosity(c,j), h2osoi_liq(c,j)/(col%dz(c,j)*denh2o)) endif @@ -413,20 +414,14 @@ subroutine calc_root_moist_stress_clm45default(bounds, & if ( .not.(use_hydrstress) ) then btran(p) = btran(p) + max(rootr(p,j),0._r8) end if + end if + s_node = max(h2osoi_vol(c,j)/watsat(c,j), 0.01_r8) - !smp_node_lf = max(smpsc(patch%itype(p)), -sucsat(c,j)*(h2osoi_vol(c,j)/watsat(c,j))**(-bsw(c,j))) - s_node = h2osoi_vol(c,j)/watsat(c,j) - -! call soil_water_retention_curve%soil_suction(sucsat(c,j), s_node, bsw(c,j), smp_node_lf) -!scs - call soil_water_retention_curve%soil_suction(c, j, s_node, soilstate_inst, smp_node_lf) -!scs + call soil_water_retention_curve%soil_suction(c, j, s_node, soilstate_inst, smp_node_lf) - !smp_node_lf = -sucsat(c,j)*(h2osoi_vol(c,j)/watsat(c,j))**(-bsw(c,j)) - smp_node_lf = max(smpsc(patch%itype(p)), smp_node_lf) - btran2(p) = btran2(p) +rootfr(p,j)*min((smp_node_lf - smpsc(patch%itype(p))) / & - (smpso(patch%itype(p)) - smpsc(patch%itype(p))), 1._r8) - endif + smp_node_lf = max(smpsc(patch%itype(p)), smp_node_lf) + btran2(p) = btran2(p) +rootfr(p,j)*max(0._r8,min((smp_node_lf - smpsc(patch%itype(p))) / & + (smpso(patch%itype(p)) - smpsc(patch%itype(p))), 1._r8)) end do end do diff --git a/src/biogeophys/SoilStateInitTimeConstMod.F90 b/src/biogeophys/SoilStateInitTimeConstMod.F90 index fc828628db..a157e16bb6 100644 --- a/src/biogeophys/SoilStateInitTimeConstMod.F90 +++ b/src/biogeophys/SoilStateInitTimeConstMod.F90 @@ -99,9 +99,9 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) use clm_varpar , only : nlevsoi, nlevgrnd, nlevlak, nlevsoifl, nlayer, nlayert, nlevurb, nlevsno use clm_varcon , only : zsoi, dzsoi, zisoi, spval use clm_varcon , only : secspday, pc, mu, denh2o, denice, grlnd - use clm_varctl , only : use_cn, use_lch4, use_ed + use clm_varctl , only : use_cn, use_lch4, use_fates use clm_varctl , only : iulog, fsurdat, paramfile, soil_layerstruct - use landunit_varcon , only : istice, istdlak, istwet, istsoil, istcrop, istice_mec + use landunit_varcon , only : istdlak, istwet, istsoil, istcrop, istice_mec use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, icol_road_perv, icol_road_imperv use fileutils , only : getfil use organicFileMod , only : organicrd @@ -185,7 +185,7 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) soilstate_inst%rootfr_road_perv_col(c,lev) = 0._r8 enddo do lev = 1,nlevsoi - soilstate_inst%rootfr_road_perv_col(c,lev) = 0.1_r8 ! uniform profile + soilstate_inst%rootfr_road_perv_col(c,lev) = 1.0_r8/real(nlevsoi,r8) end do ! remove roots below bedrock layer soilstate_inst%rootfr_road_perv_col(c,1:col%nbedrock(c)) = & @@ -209,10 +209,10 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) end do ! Initialize root fraction - ! Note that ED has its own root fraction root fraction routine and should not - ! use the following since it depends on patch%itype - which ED should not use + ! Note that fates has its own root fraction root fraction routine and should not + ! use the following since it depends on patch%itype - which fates should not use - if (.not. use_ed) then + if (.not. use_fates) then call init_vegrootfr(bounds, nlevsoi, nlevgrnd, & soilstate_inst%rootfr_patch(begp:endp,1:nlevgrnd),'water') call init_vegrootfr(bounds, nlevsoi, nlevgrnd, & @@ -333,7 +333,7 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) g = col%gridcell(c) l = col%landunit(c) - if (lun%itype(l)==istwet .or. lun%itype(l)==istice .or. lun%itype(l)==istice_mec) then + if (lun%itype(l)==istwet .or. lun%itype(l)==istice_mec) then do lev = 1,nlevgrnd soilstate_inst%bsw_col(c,lev) = spval @@ -457,7 +457,7 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) om_watsat = max(0.93_r8 - 0.1_r8 *(zsoi(lev)/zsapric), 0.83_r8) om_b = min(2.7_r8 + 9.3_r8 *(zsoi(lev)/zsapric), 12.0_r8) om_sucsat = min(10.3_r8 - 0.2_r8 *(zsoi(lev)/zsapric), 10.1_r8) - om_hksat = max(0.28_r8 - 0.2799_r8*(zsoi(lev)/zsapric), 0.0001_r8) + om_hksat = max(0.28_r8 - 0.2799_r8*(zsoi(lev)/zsapric), xksat) soilstate_inst%bd_col(c,lev) = (1._r8 - soilstate_inst%watsat_col(c,lev))*2.7e3_r8 soilstate_inst%watsat_col(c,lev) = (1._r8 - om_frac) * soilstate_inst%watsat_col(c,lev) + om_watsat*om_frac diff --git a/src/biogeophys/SoilStateType.F90 b/src/biogeophys/SoilStateType.F90 index 3e32e49103..18baac4976 100644 --- a/src/biogeophys/SoilStateType.F90 +++ b/src/biogeophys/SoilStateType.F90 @@ -36,7 +36,6 @@ module SoilStateType real(r8), pointer :: hksat_min_col (:,:) ! col mineral hydraulic conductivity at saturation (hksat) (mm/s) real(r8), pointer :: hk_l_col (:,:) ! col hydraulic conductivity (mm/s) real(r8), pointer :: smp_l_col (:,:) ! col soil matric potential (mm) - real(r8), pointer :: tsink_l_col (:,:) ! col soil transpiration sink by layer (mm H2O /s) real(r8), pointer :: smpmin_col (:) ! col restriction for min of soil potential (mm) real(r8), pointer :: bsw_col (:,:) ! col Clapp and Hornberger "b" (nlevgrnd) real(r8), pointer :: watsat_col (:,:) ! col volumetric soil water at saturation (porosity) @@ -136,7 +135,6 @@ subroutine InitAllocate(this, bounds) allocate(this%hksat_min_col (begc:endc,nlevgrnd)) ; this%hksat_min_col (:,:) = spval allocate(this%hk_l_col (begc:endc,nlevgrnd)) ; this%hk_l_col (:,:) = nan allocate(this%smp_l_col (begc:endc,nlevgrnd)) ; this%smp_l_col (:,:) = nan - allocate(this%tsink_l_col (begc:endc,nlevgrnd)) ; this%tsink_l_col (:,:) = spval allocate(this%smpmin_col (begc:endc)) ; this%smpmin_col (:) = nan allocate(this%bsw_col (begc:endc,nlevgrnd)) ; this%bsw_col (:,:) = nan @@ -211,14 +209,11 @@ subroutine InitHistory(this, bounds) else active = "inactive" end if + call hist_addfld2d (fname='SMP', units='mm', type2d='levgrnd', & avgflag='A', long_name='soil matric potential (vegetated landunits only)', & ptr_col=this%smp_l_col, set_spec=spval, l2g_scale_type='veg') - call hist_addfld2d (fname='TSINK', units='mm/s', type2d='levgrnd', & - avgflag='A', long_name='soil transpiration sink by layer', & - ptr_col=this%tsink_l_col, set_spec=spval, l2g_scale_type='veg') - this%root_conductance_patch(begp:endp,:) = spval call hist_addfld2d (fname='KROOT', units='1/s', type2d='levsoi', & avgflag='A', long_name='root conductance each soil layer', & @@ -269,7 +264,7 @@ subroutine InitHistory(this, bounds) this%soilpsi_col(begc:endc,:) = spval call hist_addfld2d (fname='SOILPSI', units='MPa', type2d='levgrnd', & avgflag='A', long_name='soil water potential in each soil layer', & - ptr_col=this%soilpsi_col) + ptr_col=this%soilpsi_col, default='inactive') end if this%thk_col(begc:endc,-nlevsno+1:0) = spval @@ -291,12 +286,12 @@ subroutine InitHistory(this, bounds) this%soilalpha_col(begc:endc) = spval call hist_addfld1d (fname='SoilAlpha', units='unitless', & avgflag='A', long_name='factor limiting ground evap', & - ptr_col=this%soilalpha_col, set_urb=spval) + ptr_col=this%soilalpha_col, set_urb=spval, default='inactive' ) this%soilalpha_u_col(begc:endc) = spval call hist_addfld1d (fname='SoilAlpha_U', units='unitless', & avgflag='A', long_name='urban factor limiting ground evap', & - ptr_col=this%soilalpha_u_col, set_nourb=spval) + ptr_col=this%soilalpha_u_col, set_nourb=spval, default='inactive') if (use_cn) then this%watsat_col(begc:endc,:) = spval @@ -372,6 +367,7 @@ subroutine Restart(this, bounds, ncid, flag) ! !LOCAL VARIABLES: integer :: c logical :: readvar + logical :: readrootfr = .false. !------------------------------------------------------------------------ call restartvar(ncid=ncid, flag=flag, varname='DSL', xtype=ncd_double, & @@ -401,9 +397,11 @@ subroutine Restart(this, bounds, ncid, flag) call restartvar(ncid=ncid, flag=flag, varname='rootfr', xtype=ncd_double, & dim1name='pft', dim2name='levgrnd', switchdim=.true., & long_name='root fraction', units='', & - interpinic_flag='interp', readvar=readvar, data=this%rootfr_patch) + interpinic_flag='interp', readvar=readrootfr, data=this%rootfr_patch) + else + readrootfr = .false. end if - if (flag=='read' .and. .not. readvar) then + if (flag=='read' .and. .not. readrootfr ) then if (masterproc) then write(iulog,*) "can't find rootfr in restart (or initial) file..." write(iulog,*) "Initialize rootfr to default" diff --git a/src/biogeophys/SoilTemperatureMod.F90 b/src/biogeophys/SoilTemperatureMod.F90 index eb8cc78b02..2bed2e97b6 100644 --- a/src/biogeophys/SoilTemperatureMod.F90 +++ b/src/biogeophys/SoilTemperatureMod.F90 @@ -222,12 +222,6 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filte frac_h2osfc => waterstate_inst%frac_h2osfc_col , & ! Input: [real(r8) (:) ] fraction of ground covered by surface water (0 to 1) - qflx_evap_soi => waterflux_inst%qflx_evap_soi_patch , & ! Input: [real(r8) (:) ] soil evaporation (mm H2O/s) (+ = to atm) - qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! Input: [real(r8) (:) ] evaporation flux from snow (W/m**2) [+ to atm] - qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! Input: [real(r8) (:) ] evaporation flux from soil (W/m**2) [+ to atm] - qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! Input: [real(r8) (:) ] evaporation flux from h2osfc (W/m**2) [+ to atm] - - sabg_soil => solarabs_inst%sabg_soil_patch , & ! Input: [real(r8) (:) ] solar radiation absorbed by soil (W/m**2) sabg_snow => solarabs_inst%sabg_snow_patch , & ! Input: [real(r8) (:) ] solar radiation absorbed by snow (W/m**2) sabg_chk => solarabs_inst%sabg_chk_patch , & ! Output: [real(r8) (:) ] sum of soil/snow using current fsno, for balance check @@ -244,8 +238,8 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filte eflx_sh_soil => energyflux_inst%eflx_sh_soil_patch , & ! Input: [real(r8) (:) ] sensible heat flux from soil (W/m**2) [+ to atm] eflx_sh_h2osfc => energyflux_inst%eflx_sh_h2osfc_patch , & ! Input: [real(r8) (:) ] sensible heat flux from surface water (W/m**2) [+ to atm] eflx_bot => energyflux_inst%eflx_bot_col , & ! Input: [real(r8) (:) ] heat flux from beneath column (W/m**2) [+ = upward] - eflx_fgr12 => energyflux_inst%eflx_fgr12_col , & ! Input: [real(r8) (:) ] heat flux between soil layer 1 and 2 (W/m2) - eflx_fgr => energyflux_inst%eflx_fgr_col , & ! Input: [real(r8) (:,:) ] (rural) soil downward heat flux (W/m2) (1:nlevgrnd) + eflx_fgr12 => energyflux_inst%eflx_fgr12_col , & ! Output: [real(r8) (:) ] heat flux between soil layer 1 and 2 (W/m2) + eflx_fgr => energyflux_inst%eflx_fgr_col , & ! Output: [real(r8) (:,:) ] (rural) soil downward heat flux (W/m2) (1:nlevgrnd) eflx_traffic => energyflux_inst%eflx_traffic_lun , & ! Input: [real(r8) (:) ] traffic sensible heat flux (W/m**2) eflx_traffic_patch => energyflux_inst%eflx_traffic_patch , & ! Input: [real(r8) (:) ] traffic sensible heat flux (W/m**2) eflx_wasteheat => energyflux_inst%eflx_wasteheat_lun , & ! Input: [real(r8) (:) ] sensible heat flux from urban heating/cooling sources of waste heat (W/m**2) @@ -260,8 +254,6 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filte eflx_urban_heat_col => energyflux_inst%eflx_urban_heat_col , & ! Output: [real(r8) (:) ] urban heating flux (W/m**2) emg => temperature_inst%emg_col , & ! Input: [real(r8) (:) ] ground emissivity - hc_soi => temperature_inst%hc_soi_col , & ! Input: [real(r8) (:) ] soil heat content (MJ/m2) ! TODO: make a module variable - hc_soisno => temperature_inst%hc_soisno_col , & ! Input: [real(r8) (:) ] soil plus snow plus lake heat content (MJ/m2) !TODO: make a module variable tssbef => temperature_inst%t_ssbef_col , & ! Input: [real(r8) (:,:) ] temperature at previous time step [K] t_h2osfc => temperature_inst%t_h2osfc_col , & ! Output: [real(r8) (:) ] surface water temperature t_soisno => temperature_inst%t_soisno_col , & ! Output: [real(r8) (:,:) ] soil temperature (Kelvin) @@ -549,10 +541,6 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filte do fc = 1,num_nolakec c = filter_nolakec(fc) l = col%landunit(c) - if (.not. lun%urbpoi(l)) then - hc_soisno(c) = 0._r8 - hc_soi(c) = 0._r8 - end if eflx_fgr12(c)= 0._r8 end do @@ -572,14 +560,6 @@ subroutine SoilTemperature(bounds, num_urbanl, filter_urbanl, num_nolakec, filte eflx_fgr(c,j) = 0._r8 end if - if (.not. lun%urbpoi(l)) then - if (j >= snl(c)+1) then - hc_soisno(c) = hc_soisno(c) + cv(c,j)*t_soisno(c,j) / 1.e6_r8 - endif - if (j >= 1) then - hc_soi(c) = hc_soi(c) + cv(c,j)*t_soisno(c,j) / 1.e6_r8 - end if - end if end do end do @@ -610,7 +590,7 @@ subroutine SoilThermProp (bounds, num_nolakec, filter_nolakec, & ! !USES: use clm_varpar , only : nlevsno, nlevgrnd, nlevurb, nlevsoi use clm_varcon , only : denh2o, denice, tfrz, tkwat, tkice, tkair, cpice, cpliq, thk_bedrock, csol_bedrock - use landunit_varcon , only : istice, istice_mec, istwet + use landunit_varcon , only : istice_mec, istwet use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, icol_road_perv, icol_road_imperv use clm_varctl , only : iulog ! @@ -693,7 +673,7 @@ subroutine SoilThermProp (bounds, num_nolakec, filter_nolakec, & thk(c,j) = tk_roof(l,j) else if (col%itype(c) == icol_road_imperv .and. j >= 1 .and. j <= nlev_improad(l)) then thk(c,j) = tk_improad(l,j) - else if (lun%itype(l) /= istwet .AND. lun%itype(l) /= istice .AND. lun%itype(l) /= istice_mec & + else if (lun%itype(l) /= istwet .AND. lun%itype(l) /= istice_mec & .AND. col%itype(c) /= icol_sunwall .AND. col%itype(c) /= icol_shadewall .AND. & col%itype(c) /= icol_roof) then @@ -713,7 +693,7 @@ subroutine SoilThermProp (bounds, num_nolakec, filter_nolakec, & thk(c,j) = tkdry(c,j) endif if (j > nbedrock(c)) thk(c,j) = thk_bedrock - else if (lun%itype(l) == istice .OR. lun%itype(l) == istice_mec) then + else if (lun%itype(l) == istice_mec) then thk(c,j) = tkwat if (t_soisno(c,j) < tfrz) thk(c,j) = tkice else if (lun%itype(l) == istwet) then @@ -788,7 +768,7 @@ subroutine SoilThermProp (bounds, num_nolakec, filter_nolakec, & cv(c,j) = cv_roof(l,j) * dz(c,j) else if (col%itype(c) == icol_road_imperv .and. j >= 1 .and. j <= nlev_improad(l)) then cv(c,j) = cv_improad(l,j) * dz(c,j) - else if (lun%itype(l) /= istwet .AND. lun%itype(l) /= istice .AND. lun%itype(l) /= istice_mec & + else if (lun%itype(l) /= istwet .AND. lun%itype(l) /= istice_mec & .AND. col%itype(c) /= icol_sunwall .AND. col%itype(c) /= icol_shadewall .AND. & col%itype(c) /= icol_roof) then cv(c,j) = csol(c,j)*(1-watsat(c,j))*dz(c,j) + (h2osoi_ice(c,j)*cpice + h2osoi_liq(c,j)*cpliq) @@ -796,7 +776,7 @@ subroutine SoilThermProp (bounds, num_nolakec, filter_nolakec, & else if (lun%itype(l) == istwet) then cv(c,j) = (h2osoi_ice(c,j)*cpice + h2osoi_liq(c,j)*cpliq) if (j > nbedrock(c)) cv(c,j) = csol_bedrock*dz(c,j) - else if (lun%itype(l) == istice .OR. lun%itype(l) == istice_mec) then + else if (lun%itype(l) == istice_mec) then cv(c,j) = (h2osoi_ice(c,j)*cpice + h2osoi_liq(c,j)*cpliq) endif if (j == 1) then @@ -1455,9 +1435,9 @@ subroutine ComputeGroundHeatFluxAndDeriv(bounds, num_nolakec, filter_nolakec, & frac_sno_eff => waterstate_inst%frac_sno_eff_col , & ! Input: [real(r8) (:) ] eff. fraction of ground covered by snow (0 to 1) - qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! Input: [real(r8) (:) ] evaporation flux from snow (W/m**2) [+ to atm] - qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! Input: [real(r8) (:) ] evaporation flux from soil (W/m**2) [+ to atm] - qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! Input: [real(r8) (:) ] evaporation flux from h2osfc (W/m**2) [+ to atm] + qflx_ev_snow => waterflux_inst%qflx_ev_snow_patch , & ! Input: [real(r8) (:) ] evaporation flux from snow (mm H2O/s) [+ to atm] + qflx_ev_soil => waterflux_inst%qflx_ev_soil_patch , & ! Input: [real(r8) (:) ] evaporation flux from soil (mm H2O/s) [+ to atm] + qflx_ev_h2osfc => waterflux_inst%qflx_ev_h2osfc_patch , & ! Input: [real(r8) (:) ] evaporation flux from h2osfc (mm H2O/s) [+ to atm] qflx_evap_soi => waterflux_inst%qflx_evap_soi_patch , & ! Input: [real(r8) (:) ] soil evaporation (mm H2O/s) (+ = to atm) qflx_tran_veg => waterflux_inst%qflx_tran_veg_patch , & ! Input: [real(r8) (:) ] vegetation transpiration (mm H2O/s) (+ = to atm) diff --git a/src/biogeophys/SoilWaterMovementMod.F90 b/src/biogeophys/SoilWaterMovementMod.F90 index 19c16d0b1d..e471118dcf 100644 --- a/src/biogeophys/SoilWaterMovementMod.F90 +++ b/src/biogeophys/SoilWaterMovementMod.F90 @@ -10,7 +10,8 @@ module SoilWaterMovementMod use shr_log_mod , only : errMsg => shr_log_errMsg use shr_kind_mod , only : r8 => shr_kind_r8 use shr_sys_mod , only : shr_sys_flush - + use clm_instMod , only : clm_fates + ! implicit none private @@ -22,7 +23,6 @@ module SoilWaterMovementMod private :: soilwater_moisture_form ! private :: soilwater_mixed_form ! private :: soilwater_head_form - private :: compute_hydraulic_properties private :: compute_moisture_fluxes_and_derivs private :: compute_RHS_moisture_form @@ -33,8 +33,6 @@ module SoilWaterMovementMod ! ! The following is only public for the sake of unit testing; it should not be called ! directly by CLM code outside this module - public :: Compute_EffecRootFrac_And_VertTranSink - public :: Compute_VertTranSink_PHS public :: BaseflowSink public :: use_aquifer_layer ! @@ -270,6 +268,7 @@ subroutine SoilWater(bounds, num_hydrologyc, filter_hydrologyc, & h2osoi_vol => waterstate_inst%h2osoi_vol_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) h2osoi_liq => waterstate_inst%h2osoi_liq_col & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) ) + select case(soilwater_movement_method) case (zengdecker_2009) @@ -345,261 +344,6 @@ subroutine SoilWater(bounds, num_hydrologyc, filter_hydrologyc, & end associate end subroutine SoilWater -!#4 - !----------------------------------------------------------------------- - subroutine Compute_EffecRootFrac_And_VertTranSink(bounds, num_hydrologyc, & - filter_hydrologyc, vert_tran_sink, waterflux_inst, soilstate_inst) - ! - ! Generic routine to apply transpiration as a sink condition that - ! is vertically distributed over the soil column. Should be - ! applicable to any Richards solver that is not coupled to plant - ! hydraulics. - ! - !USES: - use decompMod , only : bounds_type - use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varpar , only : nlevsoi, max_patch_per_col - use SoilStateType , only : soilstate_type - use WaterFluxType , only : waterflux_type - use PatchType , only : patch - use ColumnType , only : col - use clm_varctl , only : use_hydrstress - use column_varcon , only : icol_road_perv - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds ! bounds - integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter - integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points - real(r8) , intent(out) :: vert_tran_sink(bounds%begc:,1:) ! vertically distributed transpiration sink (mm H2O/s) (+ = to atm) - type(waterflux_type) , intent(inout) :: waterflux_inst - type(soilstate_type) , intent(inout) :: soilstate_inst - ! - ! !LOCAL VARIABLES: - integer :: p,c,fc,j ! do loop indices - integer :: pi ! patch index - real(r8) :: temp(bounds%begc:bounds%endc) ! accumulator for rootr weighting - !----------------------------------------------------------------------- - - ! Enforce expected array sizes - SHR_ASSERT_ALL((ubound(vert_tran_sink) == (/bounds%endc, nlevsoi/)), errMsg(sourcefile, __LINE__)) - - associate(& - qflx_tran_veg_col => waterflux_inst%qflx_tran_veg_col , & ! Input: [real(r8) (:) ] vegetation transpiration (mm H2O/s) (+ = to atm) - qflx_tran_veg_patch => waterflux_inst%qflx_tran_veg_patch , & ! Input: [real(r8) (:) ] vegetation transpiration (mm H2O/s) (+ = to atm) - tsink => soilstate_inst%tsink_l_col , & ! Output: [real(r8) (:,:) ] col soil transpiration sink by layer (mm H2O /s) - rootr_col => soilstate_inst%rootr_col , & ! Input: [real(r8) (:,:) ] effective fraction of roots in each soil layer - rootr_patch => soilstate_inst%rootr_patch & ! Input: [real(r8) (:,:) ] effective fraction of roots in each soil layer - ) - - ! First step is to calculate the column-level effective rooting - ! fraction in each soil layer. This is done outside the usual - ! PATCH-to-column averaging routines because it is not a simple - ! weighted average of the PATCH level rootr arrays. Instead, the - ! weighting depends on both the per-unit-area transpiration - ! of the PATCH and the PATCHEs area relative to all PATCHES. - - temp(bounds%begc : bounds%endc) = 0._r8 - - ! When hydraulic stress is active, still need to use old approach for - ! urban pervious road - if (use_hydrstress) then - do j = 1, nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (col%itype(c) == icol_road_perv) then - rootr_col(c,j) = 0._r8 - end if - end do - end do - else - do j = 1, nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - rootr_col(c,j) = 0._r8 - end do - end do - end if - - if (use_hydrstress) then - do pi = 1,max_patch_per_col - do j = 1,nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (col%itype(c) == icol_road_perv) then - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & - qflx_tran_veg_patch(p) * patch%wtcol(p) - end if - end if - end if - end do - end do - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (col%itype(c) == icol_road_perv) then - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) - end if - end if - end if - end do - end do - else - do pi = 1,max_patch_per_col - do j = 1,nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & - qflx_tran_veg_patch(p) * patch%wtcol(p) - end if - end if - end do - end do - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (patch%active(p)) then - temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) - end if - end if - end do - end do - end if - - if (use_hydrstress) then - do j = 1, nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (col%itype(c) == icol_road_perv) then - if (temp(c) /= 0._r8) then - rootr_col(c,j) = rootr_col(c,j)/temp(c) - end if - vert_tran_sink(c,j) = rootr_col(c,j)*qflx_tran_veg_col(c) - end if - end do - end do - else - do j = 1, nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (temp(c) /= 0._r8) then - rootr_col(c,j) = rootr_col(c,j)/temp(c) - end if - vert_tran_sink(c,j) = rootr_col(c,j)*qflx_tran_veg_col(c) - tsink(c,j) = vert_tran_sink(c,j) - end do - end do - end if - - end associate - - end subroutine Compute_EffecRootFrac_And_VertTranSink - - !----------------------------------------------------------------------- - subroutine Compute_VertTranSink_PHS(bounds, num_hydrologyc, & - filter_hydrologyc, vert_tran_sink, waterflux_inst, soilstate_inst, & - canopystate_inst, energyflux_inst) - ! - ! Generic routine to apply transpiration as a sink condition that - ! is vertically distributed over the soil column. Plant hydraulic - ! stress version - ! - !USES: - use decompMod , only : bounds_type - use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varpar , only : nlevsoi, max_patch_per_col - use SoilStateType , only : soilstate_type - use WaterFluxType , only : waterflux_type - use CanopyStateType , only : canopystate_type - use EnergyFluxType , only : energyflux_type - use PatchType , only : patch - use ColumnType , only : col - use clm_varctl , only : iulog - use column_varcon , only : icol_road_perv - use shr_infnan_mod , only : isnan => shr_infnan_isnan - - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds ! bounds - integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter - integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points - real(r8) , intent(out) :: vert_tran_sink(bounds%begc:,1:) ! vertically distributed transpiration sink (mm H2O/s) (+ = to atm) - type(waterflux_type) , intent(inout) :: waterflux_inst - type(soilstate_type) , intent(inout) :: soilstate_inst - type(canopystate_type) , intent(inout) :: canopystate_inst - type(energyflux_type), intent(in) :: energyflux_inst - ! - ! !LOCAL VARIABLES: - integer :: p,c,fc,j ! do loop indices - integer :: pi ! patch index - real(r8) :: temp(bounds%begc:bounds%endc) ! accumulator for rootr weighting - real(r8) :: grav2 ! soil layer gravitational potential relative to surface (mm H2O) - integer , parameter :: soil=1,root=4 ! index values - !----------------------------------------------------------------------- - - ! Enforce expected array sizes - SHR_ASSERT_ALL((ubound(vert_tran_sink) == (/bounds%endc, nlevsoi/)), errMsg(sourcefile, __LINE__)) - - associate(& - k_soil_root => soilstate_inst%k_soil_root_patch , & ! Input: [real(r8) (:,:) ] soil-root interface conductance (mm/s) - qflx_phs_neg_col => waterflux_inst%qflx_phs_neg_col , & ! Input: [real(r8) (:) ] net negative hydraulic redistribution flux (mm H2O/s) - qflx_tran_veg_col => waterflux_inst%qflx_tran_veg_col , & ! Input: [real(r8) (:) ] vegetation transpiration (mm H2O/s) (+ = to atm) - qflx_tran_veg_patch => waterflux_inst%qflx_tran_veg_patch , & ! Input: [real(r8) (:) ] vegetation transpiration (mm H2O/s) (+ = to atm) - rootr_col => soilstate_inst%rootr_col , & ! Input: [real(r8) (:,:) ] effective fraction of roots in each soil layer - rootr_patch => soilstate_inst%rootr_patch , & ! Input: [real(r8) (:,:) ] effective fraction of roots in each soil layer - smp => soilstate_inst%smp_l_col , & ! Input: [real(r8) (:,:) ] soil matrix potential [mm] - tsink => soilstate_inst%tsink_l_col , & ! Output: [real(r8) (:,:) ] col soil transpiration sink by layer (mm H2O /s) -! bsw => soilstate_inst%bsw_col , & ! Input: [real(r8) (:,:) ] Clapp and Hornberger "b" -! hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) -! hksat => soilstate_inst%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) -! sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) -! tsai => canopystate_inst%tsai_patch , & ! Input: [real(r8) (:) ] patch canopy one-sided stem area index, no burying by snow -! btran => energyflux_inst%btran_patch , & ! Input: [real(r8) (:) ] transpiration wetness factor (0 to 1) (integrated soil water stress) - frac_veg_nosno => canopystate_inst%frac_veg_nosno_patch , & ! Input: [integer (:) ] fraction of vegetation not covered by snow (0 OR 1) [-] -! rootfr => soilstate_inst%rootfr_patch , & ! Input: [real(r8) (:,:) ] fraction of roots in each soil layer -! ivt => patch%itype , & ! Input: [integer (:) ] patch vegetation type - z => col%z , & ! Input: [real(r8) (:,:) ] layer node depth (m) - vegwp => canopystate_inst%vegwp_patch & ! Input: [real(r8) (:,:) ] vegetation water matric potential (mm) - ) - - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - qflx_phs_neg_col(c) = 0._r8 - if (col%itype(c) /= icol_road_perv) then - do j = 1, nlevsoi - grav2 = z(c,j) * 1000._r8 - temp(c) = 0._r8 - do pi = 1,max_patch_per_col - if (pi <= col%npatches(c)) then - p = col%patchi(c) + pi - 1 - if (patch%active(p).and.frac_veg_nosno(p)>0) then - if (patch%wtcol(p) > 0._r8) then - temp(c) = temp(c) + k_soil_root(p,j) & - * (smp(c,j) - vegwp(p,4) - grav2)* patch%wtcol(p) - endif - end if - end if - end do - vert_tran_sink(c,j) = temp(c) - tsink(c,j) = temp(c) - - if (temp(c) < 0._r8) qflx_phs_neg_col(c) = qflx_phs_neg_col(c) + temp(c) - end do - end if - end do - - end associate - - end subroutine Compute_VertTranSink_PHS - !#5 !----------------------------------------------------------------------- subroutine BaseflowSink(bounds, num_hydrologyc, & @@ -732,6 +476,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & use PatchType , only : patch use ColumnType , only : col use clm_varctl , only : iulog + use SoilWaterPlantSinkMod , only : COmpute_EffecRootFrac_And_VertTranSink ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! bounds @@ -749,6 +494,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & class(soil_water_retention_curve_type), intent(in) :: soil_water_retention_curve ! ! !LOCAL VARIABLES: + character(len=32) :: subname = 'soilwater_zengdecker2009' ! subroutine name integer :: p,c,fc,j ! do loop indices integer :: jtop(bounds%begc:bounds%endc) ! top level at each column real(r8) :: dtime ! land model time step (sec) @@ -796,7 +542,6 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) :: dsmpds !temporary variable real(r8) :: dhkds !temporary variable real(r8) :: hktmp !temporary variable - real(r8) :: vert_trans_sink(bounds%begc:bounds%endc,1:nlevsoi) ! vertically distributed transpiration sink (mm H2O/s) (+ = to atm) integer :: nstep !----------------------------------------------------------------------- @@ -828,7 +573,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & qflx_deficit => waterflux_inst%qflx_deficit_col , & ! Input: [real(r8) (:) ] water deficit to keep non-negative liquid water content qflx_infl => waterflux_inst%qflx_infl_col , & ! Input: [real(r8) (:) ] infiltration (mm H2O /s) - qflx_rootsoi => waterflux_inst%qflx_rootsoi_col , & ! Output: [real(r8) (:,:) ] vegetation/soil water exchange (m H2O/s) (+ = to atm) + qflx_rootsoi_col => waterflux_inst%qflx_rootsoi_col , & ! Output: [real(r8) (:,:) ] vegetation/soil water exchange (mm H2O/s) (+ = to atm) qflx_tran_veg_col => waterflux_inst%qflx_tran_veg_col , & ! Input: [real(r8) (:) ] vegetation transpiration (mm H2O/s) (+ = to atm) rootr_col => soilstate_inst%rootr_col , & ! Input: [real(r8) (:,:) ] effective fraction of roots in each soil layer t_soisno => temperature_inst%t_soisno_col & ! Input: [real(r8) (:,:) ] soil temperature (Kelvin) @@ -839,15 +584,6 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & nstep = get_nstep() dtime = get_step_size() - call Compute_EffecRootFrac_And_VertTranSink(bounds, num_hydrologyc, & - filter_hydrologyc, vert_trans_sink(bounds%begc:bounds%endc, 1:), & - waterflux_inst, soilstate_inst) - - if ( use_hydrstress ) then - call Compute_VertTranSink_PHS(bounds, num_hydrologyc, & - filter_hydrologyc, vert_trans_sink(bounds%begc:bounds%endc, 1:), & - waterflux_inst, soilstate_inst, canopystate_inst, energyflux_inst) - end if ! Because the depths in this routine are in mm, use local ! variable arrays instead of pointers @@ -1042,7 +778,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & qout(c,j) = -hk(c,j)*num/den dqodw1(c,j) = -(-hk(c,j)*dsmpdw(c,j) + num*dhkdw(c,j))/den dqodw2(c,j) = -( hk(c,j)*dsmpdw(c,j+1) + num*dhkdw(c,j))/den - rmx(c,j) = qin(c,j) - qout(c,j) - vert_trans_sink(c,j) + rmx(c,j) = qin(c,j) - qout(c,j) - qflx_rootsoi_col(c,j) amx(c,j) = 0._r8 bmx(c,j) = dzmm(c,j)*(sdamp+1._r8/dtime) + dqodw1(c,j) cmx(c,j) = dqodw2(c,j) @@ -1066,7 +802,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & qout(c,j) = -hk(c,j)*num/den dqodw1(c,j) = -(-hk(c,j)*dsmpdw(c,j) + num*dhkdw(c,j))/den dqodw2(c,j) = -( hk(c,j)*dsmpdw(c,j+1) + num*dhkdw(c,j))/den - rmx(c,j) = qin(c,j) - qout(c,j) - vert_trans_sink(c,j) + rmx(c,j) = qin(c,j) - qout(c,j) - qflx_rootsoi_col(c,j) amx(c,j) = -dqidw0(c,j) bmx(c,j) = dzmm(c,j)/dtime - dqidw1(c,j) + dqodw1(c,j) cmx(c,j) = dqodw2(c,j) @@ -1088,7 +824,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & dqidw1(c,j) = -( hk(c,j-1)*dsmpdw(c,j) + num*dhkdw(c,j-1))/den qout(c,j) = 0._r8 dqodw1(c,j) = 0._r8 - rmx(c,j) = qin(c,j) - qout(c,j) - vert_trans_sink(c,j) + rmx(c,j) = qin(c,j) - qout(c,j) - qflx_rootsoi_col(c,j) amx(c,j) = -dqidw0(c,j) bmx(c,j) = dzmm(c,j)/dtime - dqidw1(c,j) + dqodw1(c,j) cmx(c,j) = 0._r8 @@ -1131,7 +867,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & dqodw1(c,j) = -(-hk(c,j)*dsmpdw(c,j) + num*dhkdw(c,j))/den dqodw2(c,j) = -( hk(c,j)*dsmpdw1 + num*dhkdw(c,j))/den - rmx(c,j) = qin(c,j) - qout(c,j) - vert_trans_sink(c,j) + rmx(c,j) = qin(c,j) - qout(c,j) - qflx_rootsoi_col(c,j) amx(c,j) = -dqidw0(c,j) bmx(c,j) = dzmm(c,j)/dtime - dqidw1(c,j) + dqodw1(c,j) cmx(c,j) = dqodw2(c,j) @@ -1222,14 +958,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & endif enddo enddo - if (use_flexibleCN) then - do j = 1, nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - qflx_rootsoi(c,j) = qflx_tran_veg_col(c) * rootr_col(c,j) * 1.e-3_r8 ![m H2O/s] - enddo - enddo - end if + end associate end subroutine soilwater_zengdecker2009 @@ -1375,7 +1104,6 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & real(r8) :: bmx(bounds%begc:bounds%endc,1:nlevsoi) ! "b" diagonal column for tridiagonal matrix real(r8) :: cmx(bounds%begc:bounds%endc,1:nlevsoi) ! "c" right off diagonal tridiagonal matrix real(r8) :: rmx(bounds%begc:bounds%endc,1:nlevsoi) ! "r" forcing term of tridiagonal matrix - real(r8) :: dLow(1:nlevsoi-1) ! lower diagonal vector real(r8) :: dUpp(1:nlevsoi-1) ! upper diagonal vector real(r8) :: diag(1:nlevsoi) ! diagonal vector @@ -1410,7 +1138,6 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & real(r8) :: vwc_liq_lb(bounds%begc:bounds%endc) ! liquid volumetric water content at lower boundary real(r8) :: vLiqIter(bounds%begc:bounds%endc,1:nlevsoi) ! iteration increment for the volumetric liquid water content (v/v) real(r8) :: vLiqRes(bounds%begc:bounds%endc,1:nlevsoi) ! residual for the volumetric liquid water content (v/v) - real(r8) :: vert_trans_sink(bounds%begc:bounds%endc,1:nlevsoi) ! vertically distributed transpiration sink (mm H2O/s) (+ = to atm) real(r8) :: dwat_temp !----------------------------------------------------------------------- @@ -1429,8 +1156,8 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & smp_l => soilstate_inst%smp_l_col , & ! Input: [real(r8) (:,:) ] soil matrix potential [mm] hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice water (kg/m2) - h2osoi_liq => waterstate_inst%h2osoi_liq_col & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) - + h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) + qflx_rootsoi_col => waterflux_inst%qflx_rootsoi_col & ) ! end associate statement ! Get time step @@ -1438,16 +1165,6 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & nstep = get_nstep() dtime = get_step_size() - call Compute_EffecRootFrac_And_VertTranSink(bounds, num_hydrologyc, & - filter_hydrologyc, vert_trans_sink(bounds%begc:bounds%endc, 1:), & - waterflux_inst, soilstate_inst) - - if ( use_hydrstress ) then - call Compute_VertTranSink_PHS(bounds, num_hydrologyc, & - filter_hydrologyc, vert_trans_sink(bounds%begc:bounds%endc, 1:), & - waterflux_inst, soilstate_inst, canopystate_inst, energyflux_inst) - end if - ! main spatial loop do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) @@ -1507,7 +1224,7 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & ! RHS of system of equations call compute_RHS_moisture_form(c, nlayers, & - vert_trans_sink(c,1:nlayers), & + qflx_rootsoi_col(c,1:nlayers), & vwc_liq(c,1:nlayers), & qin(c,1:nlayers), & qout(c,1:nlayers), & @@ -1600,7 +1317,7 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & endif ! compute the net flux - fluxNet0(j) = qin_test - qout_test - vert_trans_sink(c,j) + fluxNet0(j) = qin_test - qout_test - qflx_rootsoi_col(c,j) ! flux calculation is inexpensive else @@ -1611,7 +1328,7 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & endif ! switch between the expensive and inexpensive fluxcalculations ! compute the net flux at the start of the sub-step - fluxNet1(j) = qin(c,j) - qout(c,j) - vert_trans_sink(c,j) + fluxNet1(j) = qin(c,j) - qout(c,j) - qflx_rootsoi_col(c,j) end do ! looping through layers diff --git a/src/biogeophys/SoilWaterPlantSinkMod.F90 b/src/biogeophys/SoilWaterPlantSinkMod.F90 new file mode 100644 index 0000000000..90624ae70c --- /dev/null +++ b/src/biogeophys/SoilWaterPlantSinkMod.F90 @@ -0,0 +1,444 @@ +module SoilWaterPlantSinkMod + + use clm_varctl , only : use_hydrstress + use decompMod , only : bounds_type + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use abortutils , only : endrun + use clm_varctl , only : iulog + use landunit_varcon , only : istsoil,istcrop + use column_varcon , only : icol_road_perv + implicit none + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +contains + + subroutine Compute_EffecRootFrac_And_VertTranSink(bounds, num_hydrologyc, & + filter_hydrologyc, soilstate_inst, canopystate_inst, waterflux_inst, energyflux_inst) + + ! --------------------------------------------------------------------------------- + ! This is a wrapper for calculating the effective root fraction and soil + ! water sink due to plant transpiration. + ! Calculate Soil Water Sink to Roots over different types + ! of columns and for different process modules + ! The super-set of all columns that should have a root water sink + ! is filter_hydrologyc + ! There are three groups of columns: + ! 1) impervious roads, 2) non-natural vegetation and 3) natural vegetation + ! There are several methods available. + ! 1) the default version, 2) hydstress version and 3) fates boundary conditions + ! + ! There are only two quantities that are the result of this routine, and its + ! children: + ! waterflux_inst%qflx_rootsoi_col(c,j) + ! soilstate_inst%rootr_col(c,j) + ! + ! + ! --------------------------------------------------------------------------------- + + use SoilStateType , only : soilstate_type + use WaterFluxType , only : waterflux_type + use CanopyStateType , only : canopystate_type + use EnergyFluxType , only : energyflux_type + use ColumnType , only : col + use LandunitType , only : lun + + ! Arguments + type(bounds_type) , intent(in) :: bounds ! bounds + integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter + integer , intent(in) :: filter_hydrologyc(num_hydrologyc) ! column filter for soil points + type(soilstate_type) , intent(inout) :: soilstate_inst + type(waterflux_type) , intent(inout) :: waterflux_inst + type(canopystate_type) , intent(in) :: canopystate_inst + type(energyflux_type) , intent(in) :: energyflux_inst + + ! Local Variables + integer :: filterc(bounds%endc-bounds%begc+1) !column filter + integer :: num_filterc + integer :: num_filterc_tot + integer :: fc + integer :: c + integer :: l + + num_filterc_tot = 0 + + ! 1) pervious roads + num_filterc = 0 + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + if (col%itype(c) == icol_road_perv) then + num_filterc = num_filterc + 1 + filterc(num_filterc) = c + end if + end do + num_filterc_tot = num_filterc_tot+num_filterc + if(use_hydrstress) then + call Compute_EffecRootFrac_And_VertTranSink_HydStress_Roads(bounds, & + num_filterc,filterc, soilstate_inst, waterflux_inst) + else + call Compute_EffecRootFrac_And_VertTranSink_Default(bounds, & + num_filterc,filterc, soilstate_inst, waterflux_inst) + end if + + + ! Note: 2 and 3 really don't need to be split. But I am leaving + ! it split in case someone wants to calculate uptake in a special + ! way for a specific LU or coverage type (RGK 04/2017). Feel + ! free to consolidate if there are no plans to do such a thing. + + + ! 2) not ( pervious road or natural vegetation) , everything else + num_filterc = 0 + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + l = col%landunit(c) + if ( (col%itype(c) /= icol_road_perv) .and. (lun%itype(l) /= istsoil) ) then + num_filterc = num_filterc + 1 + filterc(num_filterc) = c + end if + end do + num_filterc_tot = num_filterc_tot+num_filterc + if(use_hydrstress) then + call Compute_EffecRootFrac_And_VertTranSink_HydStress(bounds, & + num_filterc, filterc, waterflux_inst, soilstate_inst, & + canopystate_inst, energyflux_inst) + else + call Compute_EffecRootFrac_And_VertTranSink_Default(bounds, & + num_filterc,filterc, soilstate_inst, waterflux_inst) + end if + + + ! 3) Natural vegetation + num_filterc = 0 + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + l = col%landunit(c) + if ( (lun%itype(l) == istsoil) ) then + num_filterc = num_filterc + 1 + filterc(num_filterc) = c + end if + end do + num_filterc_tot = num_filterc_tot+num_filterc + if (use_hydrstress) then + call Compute_EffecRootFrac_And_VertTranSink_HydStress(bounds, & + num_filterc, filterc, waterflux_inst, soilstate_inst, & + canopystate_inst,energyflux_inst) + else + call Compute_EffecRootFrac_And_VertTranSink_Default(bounds, & + num_filterc,filterc, soilstate_inst, waterflux_inst) + end if + + if (num_hydrologyc /= num_filterc_tot) then + write(iulog,*) 'The total number of columns flagged to root water uptake' + write(iulog,*) 'did not match the total number calculated' + write(iulog,*) 'This is likely a problem with the interpretation of column/lu filters.' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + + return + end subroutine Compute_EffecRootFrac_And_VertTranSink + + ! ==================================================================================== + + subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress_Roads(bounds, & + num_filterc,filterc, soilstate_inst, waterflux_inst) + + use SoilStateType , only : soilstate_type + use WaterFluxType , only : waterflux_type + use clm_varpar , only : nlevsoi + use clm_varpar , only : max_patch_per_col + use PatchType , only : patch + use ColumnType , only : col + + ! Arguments + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_filterc + integer , intent(in) :: filterc(:) + type(soilstate_type) , intent(inout) :: soilstate_inst + type(waterflux_type) , intent(inout) :: waterflux_inst + + ! Locals + integer :: j + integer :: c + integer :: fc + integer :: pi + integer :: p + real(r8) :: temp(bounds%begc:bounds%endc) ! accumulator for rootr weighting + + + associate(& + qflx_rootsoi_col => waterflux_inst%qflx_rootsoi_col , & ! Output: [real(r8) (:,:) ] + ! vegetation/soil water exchange (mm H2O/s) (+ = to atm) + qflx_tran_veg_patch => waterflux_inst%qflx_tran_veg_patch , & ! Input: [real(r8) (:) ] + ! vegetation transpiration (mm H2O/s) (+ = to atm) + qflx_tran_veg_col => waterflux_inst%qflx_tran_veg_col , & ! Input: [real(r8) (:) ] + ! vegetation transpiration (mm H2O/s) (+ = to atm) + rootr_patch => soilstate_inst%rootr_patch , & ! Input: [real(r8) (:,:) ] + ! effective fraction of roots in each soil layer + rootr_col => soilstate_inst%rootr_col & ! Output: [real(r8) (:,:) ] + !effective fraction of roots in each soil layer + ) + + ! First step is to calculate the column-level effective rooting + ! fraction in each soil layer. This is done outside the usual + ! PATCH-to-column averaging routines because it is not a simple + ! weighted average of the PATCH level rootr arrays. Instead, the + ! weighting depends on both the per-unit-area transpiration + ! of the PATCH and the PATCHEs area relative to all PATCHES. + + temp(bounds%begc : bounds%endc) = 0._r8 + + + do j = 1, nlevsoi + do fc = 1, num_filterc + c = filterc(fc) + rootr_col(c,j) = 0._r8 + end do + end do + + do pi = 1,max_patch_per_col + do j = 1,nlevsoi + do fc = 1, num_filterc + c = filterc(fc) + if (pi <= col%npatches(c)) then + p = col%patchi(c) + pi - 1 + if (patch%active(p)) then + rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & + qflx_tran_veg_patch(p) * patch%wtcol(p) + end if + end if + end do + end do + do fc = 1, num_filterc + c = filterc(fc) + if (pi <= col%npatches(c)) then + p = col%patchi(c) + pi - 1 + if (patch%active(p)) then + temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) + end if + end if + end do + end do + + + do j = 1, nlevsoi + do fc = 1, num_filterc + c = filterc(fc) + if (temp(c) /= 0._r8) then + rootr_col(c,j) = rootr_col(c,j)/temp(c) + end if + qflx_rootsoi_col(c,j) = rootr_col(c,j)*qflx_tran_veg_col(c) + end do + end do + end associate + return + end subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress_Roads + + ! ================================================================================== + + subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress( bounds, & + num_filterc, filterc, waterflux_inst, soilstate_inst, & + canopystate_inst, energyflux_inst) + + + ! + !USES: + use decompMod , only : bounds_type + use clm_varpar , only : nlevsoi + use clm_varpar , only : max_patch_per_col + use SoilStateType , only : soilstate_type + use WaterFluxType , only : waterflux_type + use CanopyStateType , only : canopystate_type + use PatchType , only : patch + use ColumnType , only : col + use clm_varctl , only : iulog + use PhotosynthesisMod, only : plc, params_inst + use column_varcon , only : icol_road_perv + use shr_infnan_mod , only : isnan => shr_infnan_isnan + use EnergyFluxType , only : energyflux_type + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds ! bounds + integer , intent(in) :: num_filterc ! number of column soil points in column filter + integer , intent(in) :: filterc(:) ! column filter for soil points + type(waterflux_type) , intent(inout) :: waterflux_inst + type(soilstate_type) , intent(inout) :: soilstate_inst + type(canopystate_type) , intent(in) :: canopystate_inst + type(energyflux_type), intent(in) :: energyflux_inst + ! + ! !LOCAL VARIABLES: + integer :: p,c,fc,j ! do loop indices + integer :: pi ! patch index + real(r8) :: temp(bounds%begc:bounds%endc) ! accumulator for rootr weighting + real(r8) :: grav2 ! soil layer gravitational potential relative to surface (mm H2O) + integer , parameter :: soil=1,root=4 ! index values + !----------------------------------------------------------------------- + + associate(& + k_soil_root => soilstate_inst%k_soil_root_patch , & ! Input: [real(r8) (:,:) ] + ! soil-root interface conductance (mm/s) + qflx_phs_neg_col => waterflux_inst%qflx_phs_neg_col , & ! Input: [real(r8) (:) ] n + ! net neg hydraulic redistribution flux(mm H2O/s) + qflx_tran_veg_col => waterflux_inst%qflx_tran_veg_col , & ! Input: [real(r8) (:) ] + ! vegetation transpiration (mm H2O/s) (+ = to atm) + qflx_tran_veg_patch => waterflux_inst%qflx_tran_veg_patch , & ! Input: [real(r8) (:) ] + ! vegetation transpiration (mm H2O/s) (+ = to atm) + qflx_rootsoi_col => waterflux_inst%qflx_rootsoi_col , & ! Output: [real(r8) (:) ] + ! col root and soil water + ! exchange [mm H2O/s] [+ into root] + rootr_col => soilstate_inst%rootr_col , & ! Input: [real(r8) (:,:) ] + ! effective fraction of roots in each soil layer + rootr_patch => soilstate_inst%rootr_patch , & ! Input: [real(r8) (:,:) ] + ! effective fraction of roots in each soil layer + smp => soilstate_inst%smp_l_col , & ! Input: [real(r8) (:,:) ] soil matrix pot. [mm] + frac_veg_nosno => canopystate_inst%frac_veg_nosno_patch , & ! Input: [integer (:) ] + ! fraction of vegetation not + ! covered by snow (0 OR 1) [-] + z => col%z , & ! Input: [real(r8) (:,:) ] layer node depth (m) + vegwp => canopystate_inst%vegwp_patch & ! Input: [real(r8) (:,:) ] vegetation water + ! matric potential (mm) + ) + + do fc = 1, num_filterc + c = filterc(fc) + qflx_phs_neg_col(c) = 0._r8 + + do j = 1, nlevsoi + grav2 = z(c,j) * 1000._r8 + temp(c) = 0._r8 + do pi = 1,max_patch_per_col + if (pi <= col%npatches(c)) then + p = col%patchi(c) + pi - 1 + if (patch%active(p).and.frac_veg_nosno(p)>0) then + if (patch%wtcol(p) > 0._r8) then + temp(c) = temp(c) + k_soil_root(p,j) & + * (smp(c,j) - vegwp(p,4) - grav2)* patch%wtcol(p) + endif + end if + end if + end do + qflx_rootsoi_col(c,j)= temp(c) + + if (temp(c) < 0._r8) qflx_phs_neg_col(c) = qflx_phs_neg_col(c) + temp(c) + end do + + ! Back out the effective root density + if( sum(qflx_rootsoi_col(c,:))>0.0_r8 ) then + do j = 1, nlevsoi + rootr_col(c,j) = qflx_rootsoi_col(c,j)/sum( qflx_rootsoi_col(c,:)) + end do + else + rootr_col(c,:) = 0.0_r8 + end if + end do + + end associate + + return + end subroutine Compute_EffecRootFrac_And_VertTranSink_HydStress + + ! ================================================================================== + + subroutine Compute_EffecRootFrac_And_VertTranSink_Default(bounds, num_filterc, & + filterc, soilstate_inst, waterflux_inst) + + ! + ! Generic routine to apply transpiration as a sink condition that + ! is vertically distributed over the soil column. Should be + ! applicable to any Richards solver that is not coupled to plant + ! hydraulics. + ! + !USES: + use decompMod , only : bounds_type + use shr_kind_mod , only : r8 => shr_kind_r8 + use clm_varpar , only : nlevsoi, max_patch_per_col + use SoilStateType , only : soilstate_type + use WaterFluxType , only : waterflux_type + use PatchType , only : patch + use ColumnType , only : col + use clm_varctl , only : use_hydrstress + use column_varcon , only : icol_road_perv + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds ! bounds + integer , intent(in) :: num_filterc ! number of column soil points in column filter + integer , intent(in) :: filterc(num_filterc) ! column filter for soil points + type(waterflux_type) , intent(inout) :: waterflux_inst + type(soilstate_type) , intent(inout) :: soilstate_inst + ! + ! !LOCAL VARIABLES: + integer :: p,c,fc,j ! do loop indices + integer :: pi ! patch index + real(r8) :: temp(bounds%begc:bounds%endc) ! accumulator for rootr weighting + associate(& + qflx_rootsoi_col => waterflux_inst%qflx_rootsoi_col , & ! Output: [real(r8) (:,:) ] + ! vegetation/soil water exchange (m H2O/s) (+ = to atm) + qflx_tran_veg_patch => waterflux_inst%qflx_tran_veg_patch , & ! Input: [real(r8) (:) ] + ! vegetation transpiration (mm H2O/s) (+ = to atm) + qflx_tran_veg_col => waterflux_inst%qflx_tran_veg_col , & ! Input: [real(r8) (:) ] + ! vegetation transpiration (mm H2O/s) (+ = to atm) + rootr_patch => soilstate_inst%rootr_patch , & ! Input: [real(r8) (:,:) ] + ! effective fraction of roots in each soil layer + rootr_col => soilstate_inst%rootr_col & ! Output: [real(r8) (:,:) ] + ! effective fraction of roots in each soil layer + ) + + ! First step is to calculate the column-level effective rooting + ! fraction in each soil layer. This is done outside the usual + ! PATCH-to-column averaging routines because it is not a simple + ! weighted average of the PATCH level rootr arrays. Instead, the + ! weighting depends on both the per-unit-area transpiration + ! of the PATCH and the PATCHEs area relative to all PATCHES. + + temp(bounds%begc : bounds%endc) = 0._r8 + + do j = 1, nlevsoi + do fc = 1, num_filterc + c = filterc(fc) + rootr_col(c,j) = 0._r8 + end do + end do + + do pi = 1,max_patch_per_col + do j = 1,nlevsoi + do fc = 1, num_filterc + c = filterc(fc) + if (pi <= col%npatches(c)) then + p = col%patchi(c) + pi - 1 + if (patch%active(p)) then + rootr_col(c,j) = rootr_col(c,j) + rootr_patch(p,j) * & + qflx_tran_veg_patch(p) * patch%wtcol(p) + end if + end if + end do + end do + do fc = 1, num_filterc + c = filterc(fc) + if (pi <= col%npatches(c)) then + p = col%patchi(c) + pi - 1 + if (patch%active(p)) then + temp(c) = temp(c) + qflx_tran_veg_patch(p) * patch%wtcol(p) + end if + end if + end do + end do + + do j = 1, nlevsoi + do fc = 1, num_filterc + c = filterc(fc) + if (temp(c) /= 0._r8) then + rootr_col(c,j) = rootr_col(c,j)/temp(c) + end if + qflx_rootsoi_col(c,j) = rootr_col(c,j)*qflx_tran_veg_col(c) + + end do + end do + end associate + return + end subroutine Compute_EffecRootFrac_And_VertTranSink_Default + +end module SoilWaterPlantSinkMod + diff --git a/src/biogeophys/SolarAbsorbedType.F90 b/src/biogeophys/SolarAbsorbedType.F90 index 3fb1ac0eb7..cff8cf9956 100644 --- a/src/biogeophys/SolarAbsorbedType.F90 +++ b/src/biogeophys/SolarAbsorbedType.F90 @@ -186,12 +186,12 @@ subroutine InitHistory(this, bounds) this%fsa_r_patch(begp:endp) = spval call hist_addfld1d (fname='FSA_R', units='W/m^2', & avgflag='A', long_name='Rural absorbed solar radiation', & - ptr_patch=this%fsa_r_patch, set_spec=spval) + ptr_patch=this%fsa_r_patch, set_spec=spval, default='inactive') this%fsa_u_patch(begp:endp) = spval call hist_addfld1d (fname='FSA_U', units='W/m^2', & avgflag='A', long_name='Urban absorbed solar radiation', & - ptr_patch=this%fsa_u_patch, c2l_scale_type='urbanf', set_nourb=spval) + ptr_patch=this%fsa_u_patch, c2l_scale_type='urbanf', set_nourb=spval, default='inactive') this%fsr_patch(begp:endp) = spval call hist_addfld1d (fname='FSR', units='W/m^2', & diff --git a/src/biogeophys/SurfaceAlbedoMod.F90 b/src/biogeophys/SurfaceAlbedoMod.F90 index b815d948ae..0bbec164e6 100644 --- a/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/src/biogeophys/SurfaceAlbedoMod.F90 @@ -205,7 +205,7 @@ subroutine SurfaceAlbedo(bounds,nc, & use shr_orb_mod use clm_time_manager , only : get_nstep use abortutils , only : endrun - use clm_varctl , only : subgridflag, use_snicar_frc, use_ed + use clm_varctl , only : subgridflag, use_snicar_frc, use_fates use CLMFatesInterfaceMod, only : hlm_fates_interface_type ! !ARGUMENTS: @@ -918,7 +918,7 @@ subroutine SurfaceAlbedo(bounds,nc, & ! Calculate surface albedos and fluxes ! Only perform on vegetated pfts where coszen > 0 - if (use_ed) then + if (use_fates) then call clm_fates%wrap_canopy_radiation(bounds, nc, & num_vegsol, filter_vegsol, & @@ -970,7 +970,7 @@ subroutine SoilAlbedo (bounds, & ! !USES: use clm_varpar , only : numrad use clm_varcon , only : tfrz - use landunit_varcon , only : istice, istice_mec, istdlak + use landunit_varcon , only : istice_mec, istdlak use LakeCon , only : lakepuddling ! ! !ARGUMENTS: @@ -1032,7 +1032,7 @@ subroutine SoilAlbedo (bounds, & !albsoi = albsod albsod(c,ib) = min(albsat(soilcol,ib)+inc, albdry(soilcol,ib)) albsoi(c,ib) = albsod(c,ib) - else if (lun%itype(l) == istice .or. lun%itype(l) == istice_mec) then ! land ice + else if (lun%itype(l) == istice_mec) then ! land ice ! changed from local variable to clm_type: !albsod = albice(ib) !albsoi = albsod @@ -1218,7 +1218,11 @@ subroutine TwoStream (bounds, & gdir(p) = phi1 + phi2*cosz twostext(p) = gdir(p)/cosz avmu(p) = ( 1._r8 - phi1/phi2 * log((phi1+phi2)/phi1) ) / phi2 - temp0(p) = gdir(p) + phi2*cosz + ! Restrict this calculation of temp0. We have seen cases where small temp0 + ! can cause unrealistic single scattering albedo (asu) associated with the + ! log calculation in temp2 below, thereby eventually causing a negative soil albedo + ! See bugzilla bug 2431: http://bugs.cgd.ucar.edu/show_bug.cgi?id=2431 + temp0(p) = max(gdir(p) + phi2*cosz,1.e-6_r8) temp1 = phi1*cosz temp2(p) = ( 1._r8 - temp1/temp0(p) * log((temp1+temp0(p))/temp1) ) end do diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index 65e40901d8..add2d67488 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -7,7 +7,7 @@ module SurfaceRadiationMod ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg - use clm_varctl , only : use_snicar_frc, use_ed + use clm_varctl , only : use_snicar_frc, use_fates use decompMod , only : bounds_type use clm_varcon , only : namec use atm2lndType , only : atm2lnd_type @@ -266,22 +266,23 @@ subroutine InitHistory(this, bounds) this%fsr_sno_vd_patch(begp:endp) = spval call hist_addfld1d (fname='SNOFSRVD', units='W/m^2', & avgflag='A', long_name='direct vis reflected solar radiation from snow', & - ptr_patch=this%fsr_sno_vd_patch, default='inactive') + ptr_patch=this%fsr_sno_vd_patch) this%fsr_sno_nd_patch(begp:endp) = spval call hist_addfld1d (fname='SNOFSRND', units='W/m^2', & avgflag='A', long_name='direct nir reflected solar radiation from snow', & - ptr_patch=this%fsr_sno_nd_patch, default='inactive') + ptr_patch=this%fsr_sno_nd_patch) this%fsr_sno_vi_patch(begp:endp) = spval call hist_addfld1d (fname='SNOFSRVI', units='W/m^2', & avgflag='A', long_name='diffuse vis reflected solar radiation from snow', & - ptr_patch=this%fsr_sno_vi_patch, default='inactive') + ptr_patch=this%fsr_sno_vi_patch) this%fsr_sno_ni_patch(begp:endp) = spval call hist_addfld1d (fname='SNOFSRNI', units='W/m^2', & avgflag='A', long_name='diffuse nir reflected solar radiation from snow', & - ptr_patch=this%fsr_sno_ni_patch, default='inactive') + ptr_patch=this%fsr_sno_ni_patch) + end subroutine InitHistory @@ -318,7 +319,7 @@ subroutine CanopySunShadeFracs(filter_nourbanp, num_nourbanp, & ! 6) shaded leaf area for canopy layer ! 7) sunlit fraction of canopy ! - ! This routine has a counterpart when the ed model is turned on. + ! This routine has a counterpart when the fates model is turned on. ! CLMEDInterf_CanopySunShadeFracs() ! If changes are applied to this routine, please take a moment to review that ! subroutine as well and consider if any new information related to these types of @@ -580,8 +581,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & fsds_sno_vd => surfrad_inst%fsds_sno_vd_patch , & ! Output: [real(r8) (:) ] incident visible, direct radiation on snow (for history files) (patch) [W/m2] fsds_sno_nd => surfrad_inst%fsds_sno_nd_patch , & ! Output: [real(r8) (:) ] incident near-IR, direct radiation on snow (for history files) (patch) [W/m2] fsds_sno_vi => surfrad_inst%fsds_sno_vi_patch , & ! Output: [real(r8) (:) ] incident visible, diffuse radiation on snow (for history files) (patch) [W/m2] - fsds_sno_ni => surfrad_inst%fsds_sno_ni_patch , & ! Output: [real(r8) (:) ] incident near-IR, diffuse radiation on snow (for history files) (patch) [W/m2] - frac_sno_eff => waterstate_inst%frac_sno_eff_col & !Input: + fsds_sno_ni => surfrad_inst%fsds_sno_ni_patch , & ! Output: [real(r8) (:) ] incident near-IR, diffuse radiation on snow (for history files) (patch) [W/m2] + frac_sno_eff => waterstate_inst%frac_sno_eff_col & !Input: ) @@ -615,7 +616,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! zero-out fsun for the urban patches ! the non-urban patches were set prior to this call - ! and split into ed and non-ed specific functions + ! and split into fates and non-fates specific functions do fp = 1,num_urbanp p = filter_urbanp(fp) fsun(p) = 0._r8 diff --git a/src/biogeophys/SurfaceResistanceMod.F90 b/src/biogeophys/SurfaceResistanceMod.F90 index 2abc7e2a5a..55e41a1106 100644 --- a/src/biogeophys/SurfaceResistanceMod.F90 +++ b/src/biogeophys/SurfaceResistanceMod.F90 @@ -220,7 +220,7 @@ subroutine calc_beta_leepielke1992(bounds, num_nolakec, filter_nolakec, & use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use decompMod , only : bounds_type use clm_varcon , only : denh2o, denice - use landunit_varcon , only : istice, istice_mec, istwet, istsoil, istcrop + use landunit_varcon , only : istice_mec, istwet, istsoil, istcrop use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_imperv, icol_road_perv use ColumnType , only : col @@ -253,8 +253,7 @@ subroutine calc_beta_leepielke1992(bounds, num_nolakec, filter_nolakec, & do fc = 1,num_nolakec c = filter_nolakec(fc) l = col%landunit(c) - if (lun%itype(l)/=istwet .AND. lun%itype(l)/=istice & - .AND. lun%itype(l)/=istice_mec) then + if (lun%itype(l)/=istwet .AND. lun%itype(l)/=istice_mec) then if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then wx = (h2osoi_liq(c,1)/denh2o+h2osoi_ice(c,1)/denice)/col%dz(c,1) fac = min(1._r8, wx/watsat(c,1)) @@ -318,7 +317,7 @@ subroutine calc_soil_resistance_sl14(bounds, num_nolakec, filter_nolakec, & use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use decompMod , only : bounds_type use clm_varcon , only : denh2o, denice - use landunit_varcon , only : istice, istice_mec, istwet, istsoil, istcrop + use landunit_varcon , only : istice_mec, istwet, istsoil, istcrop use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_imperv, icol_road_perv use ColumnType , only : col @@ -357,8 +356,7 @@ subroutine calc_soil_resistance_sl14(bounds, num_nolakec, filter_nolakec, & do fc = 1,num_nolakec c = filter_nolakec(fc) l = col%landunit(c) - if (lun%itype(l)/=istwet .AND. lun%itype(l)/=istice & - .AND. lun%itype(l)/=istice_mec) then + if (lun%itype(l)/=istwet .AND. lun%itype(l)/=istice_mec) then if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then vwc_liq = max(h2osoi_liq(c,1),1.0e-6_r8)/(dz(c,1)*denh2o) ! eff_porosity not calculated til SoilHydrology diff --git a/src/biogeophys/TemperatureType.F90 b/src/biogeophys/TemperatureType.F90 index 75e3a0e658..a797159829 100644 --- a/src/biogeophys/TemperatureType.F90 +++ b/src/biogeophys/TemperatureType.F90 @@ -92,10 +92,10 @@ module TemperatureType ! Heat content real(r8), pointer :: beta_col (:) ! coefficient of convective velocity [-] - real(r8), pointer :: hc_soi_col (:) ! col soil heat content (MJ/m2) - real(r8), pointer :: hc_soisno_col (:) ! col soil plus snow heat content (MJ/m2) real(r8), pointer :: heat1_grc (:) ! grc initial gridcell total heat content real(r8), pointer :: heat2_grc (:) ! grc post land cover change total heat content + real(r8), pointer :: liquid_water_temp1_grc (:) ! grc initial weighted average liquid water temperature (K) + real(r8), pointer :: liquid_water_temp2_grc (:) ! grc post land cover change weighted average liquid water temperature (K) ! Flags integer , pointer :: imelt_col (:,:) ! flag for melting (=1), freezing (=2), Not=0 (-nlevsno+1:nlevgrnd) @@ -250,10 +250,10 @@ subroutine InitAllocate(this, bounds) ! Heat content allocate(this%beta_col (begc:endc)) ; this%beta_col (:) = nan - allocate(this%hc_soi_col (begc:endc)) ; this%hc_soi_col (:) = nan - allocate(this%hc_soisno_col (begc:endc)) ; this%hc_soisno_col (:) = nan allocate(this%heat1_grc (begg:endg)) ; this%heat1_grc (:) = nan allocate(this%heat2_grc (begg:endg)) ; this%heat2_grc (:) = nan + allocate(this%liquid_water_temp1_grc (begg:endg)) ; this%liquid_water_temp1_grc (:) = nan + allocate(this%liquid_water_temp2_grc (begg:endg)) ; this%liquid_water_temp2_grc (:) = nan ! flags allocate(this%imelt_col (begc:endc,-nlevsno+1:nlevgrnd)) ; this%imelt_col (:,:) = huge(1) @@ -309,7 +309,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_grnd_u_col(begc:endc) = spval call hist_addfld1d (fname='TG_U', units='K', & avgflag='A', long_name='Urban ground temperature', & - ptr_col=this%t_grnd_u_col, set_nourb=spval, c2l_scale_type='urbans') + ptr_col=this%t_grnd_u_col, set_nourb=spval, c2l_scale_type='urbans', default='inactive') this%t_lake_col(begc:endc,:) = spval call hist_addfld2d (fname='TLAKE', units='K', type2d='levlak', & @@ -339,7 +339,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='TSA_R', units='K', & avgflag='A', long_name='Rural 2m air temperature', & - ptr_patch=this%t_ref2m_r_patch, set_spec=spval) + ptr_patch=this%t_ref2m_r_patch, set_spec=spval, default='inactive') this%t_ref2m_min_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMNAV', units='K', & @@ -354,27 +354,27 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_ref2m_min_r_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMNAV_R', units='K', & avgflag='A', long_name='Rural daily minimum of average 2-m temperature', & - ptr_patch=this%t_ref2m_min_r_patch, set_spec=spval) + ptr_patch=this%t_ref2m_min_r_patch, set_spec=spval, default='inactive') this%t_ref2m_max_r_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMXAV_R', units='K', & avgflag='A', long_name='Rural daily maximum of average 2-m temperature', & - ptr_patch=this%t_ref2m_max_r_patch, set_spec=spval) + ptr_patch=this%t_ref2m_max_r_patch, set_spec=spval, default='inactive') this%t_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='TSA_U', units='K', & avgflag='A', long_name='Urban 2m air temperature', & - ptr_patch=this%t_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%t_ref2m_u_patch, set_nourb=spval, default='inactive') this%t_ref2m_min_u_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMNAV_U', units='K', & avgflag='A', long_name='Urban daily minimum of average 2-m temperature', & - ptr_patch=this%t_ref2m_min_u_patch, set_nourb=spval) + ptr_patch=this%t_ref2m_min_u_patch, set_nourb=spval, default='inactive') this%t_ref2m_max_u_patch(begp:endp) = spval call hist_addfld1d (fname='TREFMXAV_U', units='K', & avgflag='A', long_name='Urban daily maximum of average 2-m temperature', & - ptr_patch=this%t_ref2m_max_u_patch, set_nourb=spval) + ptr_patch=this%t_ref2m_max_u_patch, set_nourb=spval, default='inactive') this%t_veg_patch(begp:endp) = spval call hist_addfld1d (fname='TV', units='K', & @@ -394,7 +394,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_grnd_r_col(begc:endc) = spval call hist_addfld1d (fname='TG_R', units='K', & avgflag='A', long_name='Rural ground temperature', & - ptr_col=this%t_grnd_r_col, set_spec=spval) + ptr_col=this%t_grnd_r_col, set_spec=spval, default='inactive') this%t_soisno_col(begc:endc,:) = spval call hist_addfld2d (fname='TSOI', units='K', type2d='levgrnd', & @@ -418,7 +418,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_a10_patch(begp:endp) = spval call hist_addfld1d (fname='T10', units='K', & avgflag='A', long_name='10-day running mean of 2-m temperature', & - ptr_patch=this%t_a10_patch, default=active) + ptr_patch=this%t_a10_patch, default='inactive') if (use_cn .and. use_crop )then this%t_a5min_patch(begp:endp) = spval @@ -448,44 +448,46 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp ) this%t_roof_inner_lun(begl:endl) = spval call hist_addfld1d(fname='TROOF_INNER', units='K', & avgflag='A', long_name='roof inside surface temperature', & - ptr_lunit=this%t_roof_inner_lun, set_nourb=spval, l2g_scale_type='unity') + ptr_lunit=this%t_roof_inner_lun, set_nourb=spval, l2g_scale_type='unity', & + default='inactive') this%t_sunw_inner_lun(begl:endl) = spval call hist_addfld1d(fname='TSUNW_INNER', units='K', & avgflag='A', long_name='sunwall inside surface temperature', & - ptr_lunit=this%t_sunw_inner_lun, set_nourb=spval, l2g_scale_type='unity') + ptr_lunit=this%t_sunw_inner_lun, set_nourb=spval, l2g_scale_type='unity', & + default='inactive') this%t_shdw_inner_lun(begl:endl) = spval call hist_addfld1d(fname='TSHDW_INNER', units='K', & avgflag='A', long_name='shadewall inside surface temperature', & - ptr_lunit=this%t_shdw_inner_lun, set_nourb=spval, l2g_scale_type='unity') + ptr_lunit=this%t_shdw_inner_lun, set_nourb=spval, l2g_scale_type='unity', & + default='inactive') this%t_floor_lun(begl:endl) = spval call hist_addfld1d(fname='TFLOOR', units='K', & avgflag='A', long_name='floor temperature', & - ptr_lunit=this%t_floor_lun, set_nourb=spval, l2g_scale_type='unity') + ptr_lunit=this%t_floor_lun, set_nourb=spval, l2g_scale_type='unity', & + default='inactive') end if - this%hc_soi_col(begc:endc) = spval - call hist_addfld1d (fname='HCSOI', units='MJ/m2', & - avgflag='A', long_name='soil heat content', & - ptr_col=this%hc_soi_col, set_lake=spval, set_urb=spval, l2g_scale_type='veg') - - this%hc_soisno_col(begc:endc) = spval - call hist_addfld1d (fname='HC', units='MJ/m2', & - avgflag='A', long_name='heat content of soil/snow/lake', & - ptr_col=this%hc_soisno_col, set_urb=spval) - this%heat1_grc(begg:endg) = spval - call hist_addfld1d (fname='GC_HEAT1', units='J/m^2', & + call hist_addfld1d (fname='HEAT_CONTENT1', units='J/m^2', & avgflag='A', long_name='initial gridcell total heat content', & ptr_lnd=this%heat1_grc) + call hist_addfld1d (fname='HEAT_CONTENT1_VEG', units='J/m^2', & + avgflag='A', long_name='initial gridcell total heat content - vegetated landunits only', & + ptr_lnd=this%heat1_grc, l2g_scale_type='veg', default='inactive') this%heat2_grc(begg:endg) = spval - call hist_addfld1d (fname='GC_HEAT2', units='J/m^2', & + call hist_addfld1d (fname='HEAT_CONTENT2', units='J/m^2', & avgflag='A', long_name='post land cover change total heat content', & ptr_lnd=this%heat2_grc, default='inactive') + this%liquid_water_temp1_grc(begg:endg) = spval + call hist_addfld1d (fname='LIQUID_WATER_TEMP1', units='K', & + avgflag='A', long_name='initial gridcell weighted average liquid water temperature', & + ptr_lnd=this%liquid_water_temp1_grc, default='inactive') + this%snot_top_col(begc:endc) = spval call hist_addfld1d (fname='SNOTTOPL', units='K', & avgflag='A', long_name='snow temperature (top layer)', & @@ -598,7 +600,7 @@ subroutine InitCold(this, bounds, & use shr_kind_mod , only : r8 => shr_kind_r8 use shr_const_mod , only : SHR_CONST_TKFRZ use clm_varcon , only : denice, denh2o, sb - use landunit_varcon, only : istice, istwet, istsoil, istdlak, istice_mec + use landunit_varcon, only : istwet, istsoil, istdlak, istice_mec use column_varcon , only : icol_road_imperv, icol_roof, icol_sunwall use column_varcon , only : icol_shadewall, icol_road_perv use clm_varctl , only : iulog, use_vancouver, use_mexicocity @@ -647,7 +649,7 @@ subroutine InitCold(this, bounds, & ! Below snow temperatures - nonlake points (lake points are set below) if (.not. lun%lakpoi(l)) then - if (lun%itype(l)==istice .or. lun%itype(l)==istice_mec) then + if (lun%itype(l)==istice_mec) then this%t_soisno_col(c,1:nlevgrnd) = 250._r8 else if (lun%itype(l) == istwet) then @@ -1379,6 +1381,9 @@ subroutine UpdateAccVars (this, bounds) endif end do + ! Accumulate and extract T10 + !(acumulates TSA as 10-day running mean) + call update_accum_field ('T10', this%t_ref2m_patch, nstep) call extract_accum_field ('T10', this%t_a10_patch, nstep) @@ -1404,14 +1409,17 @@ subroutine UpdateAccVars (this, bounds) ! Accumulate and extract GDD0 do p = begp,endp - g = patch%gridcell(p) - if (month==1 .and. day==1 .and. secs==dtime) then - rbufslp(p) = accumResetVal ! reset gdd - else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & - ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then - rbufslp(p) = max(0._r8, min(26._r8, this%t_ref2m_patch(p)-SHR_CONST_TKFRZ)) * dtime/SHR_CONST_CDAY - else - rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + ! Avoid unnecessary calculations over inactive points + if (patch%active(p)) then + g = patch%gridcell(p) + if (month==1 .and. day==1 .and. secs==dtime) then + rbufslp(p) = accumResetVal ! reset gdd + else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & + ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then + rbufslp(p) = max(0._r8, min(26._r8, this%t_ref2m_patch(p)-SHR_CONST_TKFRZ)) * dtime/SHR_CONST_CDAY + else + rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + end if end if end do call update_accum_field ('GDD0', rbufslp, nstep) @@ -1420,15 +1428,18 @@ subroutine UpdateAccVars (this, bounds) ! Accumulate and extract GDD8 do p = begp,endp - g = patch%gridcell(p) - if (month==1 .and. day==1 .and. secs==dtime) then - rbufslp(p) = accumResetVal ! reset gdd - else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & - ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then - rbufslp(p) = max(0._r8, min(30._r8, & - this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + 8._r8))) * dtime/SHR_CONST_CDAY - else - rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + ! Avoid unnecessary calculations over inactive points + if (patch%active(p)) then + g = patch%gridcell(p) + if (month==1 .and. day==1 .and. secs==dtime) then + rbufslp(p) = accumResetVal ! reset gdd + else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & + ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then + rbufslp(p) = max(0._r8, min(30._r8, & + this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + 8._r8))) * dtime/SHR_CONST_CDAY + else + rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + end if end if end do call update_accum_field ('GDD8', rbufslp, nstep) @@ -1437,15 +1448,18 @@ subroutine UpdateAccVars (this, bounds) ! Accumulate and extract GDD10 do p = begp,endp - g = patch%gridcell(p) - if (month==1 .and. day==1 .and. secs==dtime) then - rbufslp(p) = accumResetVal ! reset gdd - else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & - ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then - rbufslp(p) = max(0._r8, min(30._r8, & - this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + 10._r8))) * dtime/SHR_CONST_CDAY - else - rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + ! Avoid unnecessary calculations over inactive points + if (patch%active(p)) then + g = patch%gridcell(p) + if (month==1 .and. day==1 .and. secs==dtime) then + rbufslp(p) = accumResetVal ! reset gdd + else if (( month > 3 .and. month < 10 .and. grc%latdeg(g) >= 0._r8) .or. & + ((month > 9 .or. month < 4) .and. grc%latdeg(g) < 0._r8) ) then + rbufslp(p) = max(0._r8, min(30._r8, & + this%t_ref2m_patch(p)-(SHR_CONST_TKFRZ + 10._r8))) * dtime/SHR_CONST_CDAY + else + rbufslp(p) = 0._r8 ! keeps gdd unchanged at other times (eg, through Dec in NH) + end if end if end do call update_accum_field ('GDD10', rbufslp, nstep) @@ -1453,9 +1467,6 @@ subroutine UpdateAccVars (this, bounds) end if - ! Accumulate and extract T10 - !(acumulates TSA as 10-day running mean) - deallocate(rbufslp) end subroutine UpdateAccVars diff --git a/src/biogeophys/TotalWaterAndHeatMod.F90 b/src/biogeophys/TotalWaterAndHeatMod.F90 new file mode 100644 index 0000000000..7b9153a029 --- /dev/null +++ b/src/biogeophys/TotalWaterAndHeatMod.F90 @@ -0,0 +1,909 @@ +module TotalWaterAndHeatMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Routines for computing total column water and heat contents + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use decompMod , only : bounds_type + use clm_varcon , only : cpice, cpliq, denh2o, tfrz, hfus, aquifer_water_baseline + use clm_varpar , only : nlevgrnd, nlevsoi, nlevurb + use ColumnType , only : col + use LandunitType , only : lun + use subgridAveMod , only : p2c + use SoilHydrologyType , only : soilhydrology_type + use WaterstateType , only : waterstate_type + use UrbanParamsType , only : urbanparams_type + use SoilStateType , only : soilstate_type + use TemperatureType , only : temperature_type + use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall + use column_varcon , only : icol_road_perv, icol_road_imperv + use landunit_varcon , only : istdlak, istsoil,istcrop,istwet,istice_mec + ! + ! !PUBLIC TYPES: + implicit none + save + ! + ! !PUBLIC MEMBER FUNCTIONS: + + ! For water (ComputeWaterMass* / ComputeLiqIceMass*): We have separate routines for lake + ! vs. non-lake because parts of the code call just one or the other. + ! + ! For heat (ComputeHeat*): We use separate routines for lake vs. non-lake to keep these + ! routines parallel with the water routines. + public :: ComputeWaterMassNonLake ! Compute total water mass of non-lake columns + public :: ComputeWaterMassLake ! Compute total water mass of lake columns + public :: ComputeLiqIceMassNonLake ! Compute total water mass of non-lake columns, separated into liquid and ice + public :: ComputeLiqIceMassLake ! Compute total water mass of lake columns, separated into liquid and ice + public :: ComputeHeatNonLake ! Compute heat content of non-lake columns + public :: ComputeHeatLake ! Compute heat content of lake columns + public :: AdjustDeltaHeatForDeltaLiq ! Adjusts the change in gridcell heat content due to land cover change to account for the implicit heat flux associated with delta_liq + public :: LiquidWaterHeat ! Get the total heat content of some mass of liquid water at a given temperature + + ! + ! !PUBLIC MEMBER DATA: + + ! While some parts of the code work just fine with any heat_base_temp, other parts + ! currently wouldn't work right if we changed this value. This is all related to the + ! fact that we don't currently track temperature explicitly for all components of the + ! system. Specifically: + ! + ! (1) For liquid water pools that don't have an explicit temperature, we assume a + ! temperature of heat_base_temp. This is not a terrible assumption for + ! heat_base_temp = tfrz, but would be a terrible assumption for (e.g.) + ! heat_base_temp = 0. + ! + ! (2) In AdjustDeltaHeatForDeltaLiq, we currently don't account for the energy + ! associated with delta_ice (as we do for delta_liq). This amounts to implicitly + ! assuming that this ice runoff is at heat_base_temp (this is tied in with the fact + ! that we don't explicitly track the temperature of runoff). This makes sense for + ! heat_base_temp = tfrz, but wouldn't make sense for other values of heat_base_temp. + real(r8), parameter, public :: heat_base_temp = tfrz ! Base temperature for heat sums [K] + + ! ------------------------------------------------------------------------ + ! The following are public just to support unit testing; they shouldn't be used by other code + ! ------------------------------------------------------------------------ + + ! Minimum and maximum temperatures for the water temperature used by AdjustDeltaHeatForDeltaLiq + real(r8), parameter :: DeltaLiqMinTemp = tfrz ! [K] + real(r8), parameter :: DeltaLiqMaxTemp = tfrz + 35._r8 ! [K] + + ! + ! !PRIVATE MEMBER FUNCTIONS: + private :: AccumulateLiquidWaterHeat ! For use by ComputeHeat* routines: accumulate quantities that we need to count for liquid water, for a single column + private :: TempToHeat ! For use by ComputeHeat* routines: convert temperature to heat content + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +contains + + !----------------------------------------------------------------------- + subroutine ComputeWaterMassNonLake(bounds, num_nolakec, filter_nolakec, & + soilhydrology_inst, waterstate_inst, water_mass) + ! + ! !DESCRIPTION: + ! Compute total water mass for all non-lake columns + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_nolakec ! number of column non-lake points in column filter + integer , intent(in) :: filter_nolakec(:) ! column filter for non-lake points + type(soilhydrology_type) , intent(in) :: soilhydrology_inst + type(waterstate_type) , intent(in) :: waterstate_inst + real(r8) , intent(inout) :: water_mass( bounds%begc: ) ! computed water mass (kg m-2) + ! + ! !LOCAL VARIABLES: + real(r8) :: liquid_mass(bounds%begc:bounds%endc) ! kg m-2 + real(r8) :: ice_mass(bounds%begc:bounds%endc) ! kg m-2 + integer :: fc, c + + character(len=*), parameter :: subname = 'ComputeWaterMassNonLake' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(water_mass) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + call ComputeLiqIceMassNonLake( & + bounds = bounds, & + num_nolakec = num_nolakec, & + filter_nolakec = filter_nolakec, & + soilhydrology_inst = soilhydrology_inst, & + waterstate_inst = waterstate_inst, & + liquid_mass = liquid_mass(bounds%begc:bounds%endc), & + ice_mass = ice_mass(bounds%begc:bounds%endc)) + + do fc = 1, num_nolakec + c = filter_nolakec(fc) + water_mass(c) = liquid_mass(c) + ice_mass(c) + end do + + end subroutine ComputeWaterMassNonLake + + !----------------------------------------------------------------------- + subroutine ComputeWaterMassLake(bounds, num_lakec, filter_lakec, & + waterstate_inst, water_mass) + ! + ! !DESCRIPTION: + ! Compute total water mass for all lake columns + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_lakec ! number of column lake points in column filter + integer , intent(in) :: filter_lakec(:) ! column filter for lake points + type(waterstate_type) , intent(in) :: waterstate_inst + real(r8) , intent(inout) :: water_mass( bounds%begc: ) ! computed water mass (kg m-2) + ! + ! !LOCAL VARIABLES: + real(r8) :: liquid_mass(bounds%begc:bounds%endc) ! kg m-2 + real(r8) :: ice_mass(bounds%begc:bounds%endc) ! kg m-2 + integer :: fc, c + + character(len=*), parameter :: subname = 'ComputeWaterMassLake' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(water_mass) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + call ComputeLiqIceMassLake( & + bounds = bounds, & + num_lakec = num_lakec, & + filter_lakec = filter_lakec, & + waterstate_inst = waterstate_inst, & + liquid_mass = liquid_mass(bounds%begc:bounds%endc), & + ice_mass = ice_mass(bounds%begc:bounds%endc)) + + do fc = 1, num_lakec + c = filter_lakec(fc) + water_mass(c) = liquid_mass(c) + ice_mass(c) + end do + + end subroutine ComputeWaterMassLake + + + !----------------------------------------------------------------------- + subroutine ComputeLiqIceMassNonLake(bounds, num_nolakec, filter_nolakec, & + soilhydrology_inst, waterstate_inst, liquid_mass, ice_mass) + ! + ! !DESCRIPTION: + ! Compute total water mass for all non-lake columns, separated into liquid and ice + ! + ! Note: Changes to this routine should generally be accompanied by similar changes + ! to ComputeHeatNonLake + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_nolakec ! number of column non-lake points in column filter + integer , intent(in) :: filter_nolakec(:) ! column filter for non-lake points + type(soilhydrology_type) , intent(in) :: soilhydrology_inst + type(waterstate_type) , intent(in) :: waterstate_inst + real(r8) , intent(inout) :: liquid_mass( bounds%begc: ) ! computed liquid water mass (kg m-2) + real(r8) , intent(inout) :: ice_mass( bounds%begc: ) ! computed ice mass (kg m-2) + ! + ! !LOCAL VARIABLES: + integer :: c, j, fc ! indices + logical :: has_h2o ! whether this point potentially has water to add + real(r8) :: h2ocan_col(bounds%begc:bounds%endc) ! canopy water (mm H2O) + real(r8) :: snocan_col(bounds%begc:bounds%endc) ! canopy snow water (mm H2O) + real(r8) :: liqcan ! canopy liquid water (mm H2O) + + character(len=*), parameter :: subname = 'ComputeLiqIceMassNonLake' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(liquid_mass) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(ice_mass) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + associate( & + snl => col%snl , & ! Input: [integer (:) ] negative number of snow layers + + h2osfc => waterstate_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) + h2osno => waterstate_inst%h2osno_col , & ! Input: [real(r8) (:) ] snow water (mm H2O) + h2ocan_patch => waterstate_inst%h2ocan_patch , & ! Input: [real(r8) (:) ] canopy water (mm H2O) + snocan_patch => waterstate_inst%snocan_patch , & ! Input: [real(r8) (:) ] canopy snow water (mm H2O) + h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) + h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) + total_plant_stored_h2o => waterstate_inst%total_plant_stored_h2o_col, & + ! Input: [real(r8) (:,:) ] plant internal stored water (mm H2O) + wa => soilhydrology_inst%wa_col & ! Input: [real(r8) (:) ] water in the unconfined aquifer (mm) + ) + + do fc = 1, num_nolakec + c = filter_nolakec(fc) + liquid_mass(c) = 0._r8 + ice_mass(c) = 0._r8 + end do + + call p2c(bounds, num_nolakec, filter_nolakec, & + h2ocan_patch(bounds%begp:bounds%endp), & + h2ocan_col(bounds%begc:bounds%endc)) + + call p2c(bounds, num_nolakec, filter_nolakec, & + snocan_patch(bounds%begp:bounds%endp), & + snocan_col(bounds%begc:bounds%endc)) + + do fc = 1, num_nolakec + c = filter_nolakec(fc) + + ! waterstate_inst%snocan_patch and waterstate_inst%liqcan_patch are only set if + ! we're using snow-on-veg; otherwise they are 0. However, we can rely on + ! h2ocan_patch being set in all cases, so we can always determine the liquid mass + ! as (h2ocan - snocan). + ! Note the difference between liqcan and total_plant_stored_h2o. The prior + ! is that which exists on the vegetation canopy surface, the latter is + ! that which exists within the plant xylems and tissues. In cases + ! where FATES hydraulics is not turned on, this total_plant_stored_h2o is + ! non-changing, and is set to 0 for a trivial solution. + + liqcan = h2ocan_col(c) - snocan_col(c) + liquid_mass(c) = liquid_mass(c) + liqcan + total_plant_stored_h2o(c) + ice_mass(c) = ice_mass(c) + snocan_col(c) + + if (snl(c) < 0) then + ! Loop over snow layers + do j = snl(c)+1,0 + liquid_mass(c) = liquid_mass(c) + h2osoi_liq(c,j) + ice_mass(c) = ice_mass(c) + h2osoi_ice(c,j) + end do + else if (h2osno(c) /= 0._r8) then + ! No explicit snow layers, but there may still be some ice in h2osno (there is + ! no liquid water in this case) + ice_mass(c) = ice_mass(c) + h2osno(c) + end if + + if (col%hydrologically_active(c)) then + ! It's important to exclude non-hydrologically-active points, because some of + ! them have wa set, but seemingly incorrectly (set to 4000). + + ! NOTE(wjs, 2017-03-23) We subtract aquifer_water_baseline because water in the + ! unconfined aquifer is in some senses a virtual water pool. For CLM45 physics, + ! it isn't clear to me if this subtraction is the "right" thing to do (it can + ! lead to a net negative value, though that's probably okay). But we definitely + ! want to do it for CLM5 physics: there, wa stays fixed at 5000 for + ! hydrologically-active columns, yet this apparently doesn't interact with the + ! system, so we don't want to count that water mass in the total column water. + liquid_mass(c) = liquid_mass(c) + (wa(c) - aquifer_water_baseline) + end if + + if (col%itype(c) == icol_roof .or. col%itype(c) == icol_sunwall & + .or. col%itype(c) == icol_shadewall .or. col%itype(c) == icol_road_imperv) then + ! Nothing more to add in this case + else + liquid_mass(c) = liquid_mass(c) + h2osfc(c) + end if + end do + + ! Soil water content + do j = 1, nlevgrnd + do fc = 1, num_nolakec + c = filter_nolakec(fc) + if (col%itype(c) == icol_sunwall .or. col%itype(c) == icol_shadewall) then + has_h2o = .false. + else if (col%itype(c) == icol_roof) then + if (j <= nlevurb) then + has_h2o = .true. + else + has_h2o = .false. + end if + else + has_h2o = .true. + end if + + if (has_h2o) then + liquid_mass(c) = liquid_mass(c) + h2osoi_liq(c,j) + ice_mass(c) = ice_mass(c) + h2osoi_ice(c,j) + end if + end do + end do + + end associate + + end subroutine ComputeLiqIceMassNonLake + + !----------------------------------------------------------------------- + subroutine ComputeLiqIceMassLake(bounds, num_lakec, filter_lakec, & + waterstate_inst, liquid_mass, ice_mass) + ! + ! !DESCRIPTION: + ! Compute total water mass for all lake columns, separated into liquid and ice + ! + ! Note: Changes to this routine should generally be accompanied by similar changes + ! to ComputeHeatLake + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_lakec ! number of column lake points in column filter + integer , intent(in) :: filter_lakec(:) ! column filter for lake points + type(waterstate_type) , intent(in) :: waterstate_inst + real(r8) , intent(inout) :: liquid_mass( bounds%begc: ) ! computed liquid water mass (kg m-2) + real(r8) , intent(inout) :: ice_mass( bounds%begc: ) ! computed ice mass (kg m-2) + ! + ! !LOCAL VARIABLES: + integer :: c, j, fc ! indices + + character(len=*), parameter :: subname = 'ComputeLiqIceMassLake' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(liquid_mass) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(ice_mass) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + associate( & + snl => col%snl , & ! Input: [integer (:) ] negative number of snow layers + + h2osno => waterstate_inst%h2osno_col , & ! Input: [real(r8) (:) ] snow water (mm H2O) + h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice lens (kg/m2) + h2osoi_liq => waterstate_inst%h2osoi_liq_col & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) + ) + + do fc = 1, num_lakec + c = filter_lakec(fc) + liquid_mass(c) = 0._r8 + ice_mass(c) = 0._r8 + end do + + ! Snow water content + do fc = 1, num_lakec + c = filter_lakec(fc) + if (snl(c) < 0) then + ! Loop over snow layers + do j = snl(c)+1,0 + liquid_mass(c) = liquid_mass(c) + h2osoi_liq(c,j) + ice_mass(c) = ice_mass(c) + h2osoi_ice(c,j) + end do + else if (h2osno(c) /= 0._r8) then + ! No explicit snow layers, but there may still be some ice in h2osno (there is + ! no liquid water in this case) + ice_mass(c) = ice_mass(c) + h2osno(c) + end if + end do + + ! Soil water content of the soil under the lake + do j = 1, nlevgrnd + do fc = 1, num_lakec + c = filter_lakec(fc) + liquid_mass(c) = liquid_mass(c) + h2osoi_liq(c,j) + ice_mass(c) = ice_mass(c) + h2osoi_ice(c,j) + end do + end do + + end associate + + end subroutine ComputeLiqIceMassLake + + !----------------------------------------------------------------------- + subroutine ComputeHeatNonLake(bounds, num_nolakec, filter_nolakec, & + urbanparams_inst, soilstate_inst, & + temperature_inst, waterstate_inst, soilhydrology_inst, & + heat, heat_liquid, cv_liquid) + ! + ! !DESCRIPTION: + ! Compute total heat content for all non-lake columns. + ! + ! Optionally, also return the total heat content just of liquid water for each column + ! (excluding latent heat), and/or the total heat capacity just of liquid water for + ! each column. Together, these can be used by the caller to compute the weighted + ! average liquid water temperature (with weightings done by the water mass). + ! + ! Note: Changes to this routine - for anything involving liquid or ice - should + ! generally be accompanied by similar changes to ComputeLiqIceMassNonLake + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_nolakec + integer , intent(in) :: filter_nolakec(:) + type(urbanparams_type) , intent(in) :: urbanparams_inst + type(soilstate_type) , intent(in) :: soilstate_inst + type(temperature_type) , intent(in) :: temperature_inst + type(waterstate_type) , intent(in) :: waterstate_inst + type(soilhydrology_type) , intent(in) :: soilhydrology_inst + + real(r8) , intent(inout) :: heat( bounds%begc: ) ! sum of heat content for all columns [J/m^2] + real(r8) , intent(inout) :: heat_liquid( bounds%begc: ) ! sum of heat content for all columns: liquid water, excluding latent heat [J/m^2] + real(r8) , intent(inout) :: cv_liquid( bounds%begc: ) ! sum of liquid heat capacity for all columns [J/(m^2 K)] + ! + ! !LOCAL VARIABLES: + integer :: fc + integer :: l,c,j + + logical :: has_h2o ! whether this point potentially has water to add + + real(r8) :: h2ocan_col(bounds%begc:bounds%endc) ! canopy water (mm H2O) + real(r8) :: snocan_col(bounds%begc:bounds%endc) ! canopy snow water (mm H2O) + real(r8) :: liqcan ! canopy liquid water (mm H2O) + + real(r8) :: heat_dry_mass(bounds%begc:bounds%endc) ! sum of heat content: dry mass [J/m^2] + real(r8) :: heat_ice(bounds%begc:bounds%endc) ! sum of heat content: ice [J/m^2] + real(r8) :: latent_heat_liquid(bounds%begc:bounds%endc) ! sum of latent heat content of liquid water [J/m^2] + + character(len=*), parameter :: subname = 'ComputeHeatNonLake' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(heat) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(heat_liquid) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(cv_liquid) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + associate( & + snl => col%snl, & ! number of snow layers + dz => col%dz, & ! layer depth (m) + nlev_improad => urbanparams_inst%nlev_improad, & ! number of impervious road layers + cv_wall => urbanparams_inst%cv_wall, & ! heat capacity of urban wall (J/m^3/K) + cv_roof => urbanparams_inst%cv_roof, & ! heat capacity of urban roof (J/m^3/K) + cv_improad => urbanparams_inst%cv_improad, & ! heat capacity of urban impervious road (J/m^3/K) + watsat => soilstate_inst%watsat_col, & ! volumetric soil water at saturation (porosity) + csol => soilstate_inst%csol_col, & ! heat capacity, soil solids (J/m**3/Kelvin) + t_soisno => temperature_inst%t_soisno_col, & ! soil temperature (Kelvin) + t_h2osfc => temperature_inst%t_h2osfc_col, & ! surface water temperature (Kelvin) + h2osoi_liq => waterstate_inst%h2osoi_liq_col, & ! liquid water (kg/m2) + h2osoi_ice => waterstate_inst%h2osoi_ice_col, & ! frozen water (kg/m2) + h2osno => waterstate_inst%h2osno_col, & ! snow water (mm H2O) + h2osfc => waterstate_inst%h2osfc_col, & ! surface water (mm H2O) + h2ocan_patch => waterstate_inst%h2ocan_patch, & ! canopy water (mm H2O) + snocan_patch => waterstate_inst%snocan_patch, & ! canopy snow water (mm H2O) + total_plant_stored_h2o_col => waterstate_inst%total_plant_stored_h2o_col, & ! Input: [real(r8) (:) ] water mass in plant tissues (kg m-2) + wa => soilhydrology_inst%wa_col & ! water in the unconfined aquifer (mm) + ) + + do fc = 1, num_nolakec + c = filter_nolakec(fc) + + heat_liquid(c) = 0._r8 + cv_liquid(c) = 0._r8 + heat_dry_mass(c) = 0._r8 + heat_ice(c) = 0._r8 + latent_heat_liquid(c) = 0._r8 + end do + + call p2c(bounds, & + parr = h2ocan_patch(bounds%begp:bounds%endp), & + carr = h2ocan_col(bounds%begc:bounds%endc), & + p2c_scale_type = 'unity') + + call p2c(bounds, & + parr = snocan_patch(bounds%begp:bounds%endp), & + carr = snocan_col(bounds%begc:bounds%endc), & + p2c_scale_type = 'unity') + + do fc = 1, num_nolakec + c = filter_nolakec(fc) + + !--- canopy water --- + ! + ! TODO(wjs, 2017-03-11) Canopy water currently doesn't have an explicit + ! temperature; thus, we only add its latent heat of fusion. Eventually, we should + ! probably track its temperature explicitly - or at least give it an implicit + ! temperature for the sake of these energy calculations (I think that's needed for + ! full conservation). + ! + ! However, we still call the standard AccumulateLiquidWaterHeat routine, so that we + ! average in a heat_base_temp value in heat_liquid. I think this will generally + ! lead to less of a sensible heat flux adjustment needed by the dynbal energy + ! conservation code. (But I went back and forth on whether to do this, so could + ! be convinced otherwise.) + + ! snocan and liqcan are only set if we're using snow-on-veg; otherwise they are 0. + ! However, we can rely on h2ocan being set in all cases, so we can always + ! determine the liquid mass as (h2ocan - snocan). + + ! Note (rgk 04-2017): added total_plant_stored_h2o_col(c), which is the + ! water inside the plant, which is zero for all non-dynamic models. FATES hydraulics + ! is the only one with dynamic storage atm. + ! Commentary (rgk 04-2017): water has moved from the soil to the plant tissues, + ! and the two pools have different temperatures associated with them. However, + ! we are not accounting for or conserving the flux of energy between the two + ! pools. The energy in the plant water should "bring with it" the internal + ! energy of the soil-to-root water flux. + + liqcan = h2ocan_col(c) - snocan_col(c) + total_plant_stored_h2o_col(c) + call AccumulateLiquidWaterHeat( & + temp = heat_base_temp, & + h2o = liqcan, & + cv_liquid = cv_liquid(c), & + heat_liquid = heat_liquid(c), & + latent_heat_liquid = latent_heat_liquid(c)) + + !--- snow --- + if ( snl(c) < 0 ) then + ! Loop over snow layers + do j = snl(c)+1,0 + call AccumulateLiquidWaterHeat( & + temp = t_soisno(c,j), & + h2o = h2osoi_liq(c,j), & + cv_liquid = cv_liquid(c), & + heat_liquid = heat_liquid(c), & + latent_heat_liquid = latent_heat_liquid(c)) + heat_ice(c) = heat_ice(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (h2osoi_ice(c,j)*cpice)) + end do + else if (h2osno(c) /= 0._r8) then + ! No explicit snow layers, but there may still be some ice in h2osno (there is + ! no liquid water in this case) + j = 1 + heat_ice(c) = heat_ice(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (h2osno(c)*cpice)) + end if + + if (col%hydrologically_active(c)) then + ! NOTE(wjs, 2017-03-23) Water in the unconfined aquifer currently doesn't have + ! an explicit temperature; thus, we only add its latent heat of + ! fusion. However, we still call the standard AccumulateLiquidWaterHeat routine, so + ! that we average in a heat_base_temp value in heat_liquid. I think this will + ! generally lead to less of a sensible heat flux adjustment needed by the + ! dynbal energy conservation code. (But I went back and forth on whether to do + ! this, so could be convinced otherwise.) In the default CLM5 configuration, + ! this should all be irrelevant, because (wa(c) - aquifer_water_baseline) + ! should be fixed at 0 for all hydrologically-active points. + + call AccumulateLiquidWaterHeat( & + temp = heat_base_temp, & + h2o = (wa(c) - aquifer_water_baseline), & + cv_liquid = cv_liquid(c), & + heat_liquid = heat_liquid(c), & + latent_heat_liquid = latent_heat_liquid(c)) + end if + + if (col%itype(c) == icol_roof .or. col%itype(c) == icol_sunwall & + .or. col%itype(c) == icol_shadewall .or. col%itype(c) == icol_road_imperv) then + ! Nothing more to add in this case + else + !--- surface water --- + call AccumulateLiquidWaterHeat( & + temp = t_h2osfc(c), & + h2o = h2osfc(c), & + cv_liquid = cv_liquid(c), & + heat_liquid = heat_liquid(c), & + latent_heat_liquid = latent_heat_liquid(c)) + end if + + end do + + + !--- below ground (soil & soil water) and related urban columns + do j = 1, nlevgrnd + do fc = 1, num_nolakec + c = filter_nolakec(fc) + l = col%landunit(c) + + if (col%itype(c)==icol_sunwall .or. col%itype(c)==icol_shadewall) then + has_h2o = .false. + if (j <= nlevurb) then + heat_dry_mass(c) = heat_dry_mass(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (cv_wall(l,j) * dz(c,j))) + end if + + else if (col%itype(c) == icol_roof) then + if (j <= nlevurb) then + has_h2o = .true. + heat_dry_mass(c) = heat_dry_mass(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (cv_roof(l,j) * dz(c,j))) + else + has_h2o = .false. + end if + + else + has_h2o = .true. + + if (col%itype(c) == icol_road_imperv .and. j <= nlev_improad(l)) then + heat_dry_mass(c) = heat_dry_mass(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (cv_improad(l,j) * dz(c,j))) + else if (lun%itype(l) /= istwet .and. lun%itype(l) /= istice_mec) then + ! Note that this also includes impervious roads below nlev_improad (where + ! we have soil) + heat_dry_mass(c) = heat_dry_mass(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (csol(c,j)*(1-watsat(c,j))*dz(c,j))) + end if + end if + + if (has_h2o) then + call AccumulateLiquidWaterHeat( & + temp = t_soisno(c,j), & + h2o = h2osoi_liq(c,j), & + cv_liquid = cv_liquid(c), & + heat_liquid = heat_liquid(c), & + latent_heat_liquid = latent_heat_liquid(c)) + heat_ice(c) = heat_ice(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (h2osoi_ice(c,j)*cpice)) + end if + end do + end do + + do fc = 1, num_nolakec + c = filter_nolakec(fc) + heat(c) = heat_dry_mass(c) + heat_ice(c) + heat_liquid(c) + latent_heat_liquid(c) + end do + + end associate + + end subroutine ComputeHeatNonLake + + !----------------------------------------------------------------------- + subroutine ComputeHeatLake(bounds, num_lakec, filter_lakec, & + soilstate_inst, temperature_inst, waterstate_inst, & + heat, heat_liquid, cv_liquid) + ! + ! !DESCRIPTION: + ! Compute total heat content for all lake columns + ! + ! Optionally, also return the total heat content just of liquid water for each column + ! (excluding latent heat), and/or the total heat capacity just of liquid water for + ! each column. Together, these can be used by the caller to compute the weighted + ! average liquid water temperature (with weightings done by the water mass). + ! + ! Note: Changes to this routine - for anything involving liquid or ice - should + ! generally be accompanied by similar changes to ComputeLiqIceMassLake + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_lakec + integer , intent(in) :: filter_lakec(:) + type(soilstate_type) , intent(in) :: soilstate_inst + type(temperature_type) , intent(in) :: temperature_inst + type(waterstate_type) , intent(in) :: waterstate_inst + + real(r8) , intent(inout) :: heat( bounds%begc: ) ! sum of heat content for all columns [J/m^2] + real(r8) , intent(inout) :: heat_liquid( bounds%begc: ) ! sum of heat content for all columns: liquid water, excluding latent heat [J/m^2] + real(r8) , intent(inout) :: cv_liquid( bounds%begc: ) ! sum of liquid heat capacity for all columns [J/(m^2 K)] + ! + ! !LOCAL VARIABLES: + integer :: fc + integer :: c,j + + real(r8) :: heat_dry_mass(bounds%begc:bounds%endc) ! sum of heat content: dry mass [J/m^2] + real(r8) :: heat_ice(bounds%begc:bounds%endc) ! sum of heat content: ice [J/m^2] + real(r8) :: latent_heat_liquid(bounds%begc:bounds%endc) ! sum of latent heat content of liquid water [J/m^2] + + character(len=*), parameter :: subname = 'ComputeHeatLake' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(heat) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(heat_liquid) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(cv_liquid) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + associate( & + snl => col%snl, & ! number of snow layers + dz => col%dz, & ! layer depth (m) + watsat => soilstate_inst%watsat_col, & ! volumetric soil water at saturation (porosity) + csol => soilstate_inst%csol_col, & ! heat capacity, soil solids (J/m**3/Kelvin) + t_soisno => temperature_inst%t_soisno_col, & ! soil temperature (Kelvin) + h2osoi_liq => waterstate_inst%h2osoi_liq_col, & ! liquid water (kg/m2) + h2osoi_ice => waterstate_inst%h2osoi_ice_col, & ! frozen water (kg/m2) + h2osno => waterstate_inst%h2osno_col & ! snow water (mm H2O) + ) + + do fc = 1, num_lakec + c = filter_lakec(fc) + + heat_liquid(c) = 0._r8 + cv_liquid(c) = 0._r8 + heat_dry_mass(c) = 0._r8 + heat_ice(c) = 0._r8 + latent_heat_liquid(c) = 0._r8 + end do + + ! Snow heat content + do fc = 1, num_lakec + c = filter_lakec(fc) + if ( snl(c) < 0 ) then + ! Loop over snow layers + do j = snl(c)+1,0 + call AccumulateLiquidWaterHeat( & + temp = t_soisno(c,j), & + h2o = h2osoi_liq(c,j), & + cv_liquid = cv_liquid(c), & + heat_liquid = heat_liquid(c), & + latent_heat_liquid = latent_heat_liquid(c)) + heat_ice(c) = heat_ice(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (h2osoi_ice(c,j)*cpice)) + end do + else if (h2osno(c) /= 0._r8) then + ! TODO(wjs, 2017-03-16) (Copying this note from old code... I'm not positive + ! it's still true.) The heat capacity (not latent heat) of snow without snow + ! layers is currently ignored in LakeTemperature, so it should be ignored here. + ! Eventually we should consider this. + end if + end do + + ! Soil water content of the soil under the lake + do j = 1,nlevgrnd + do fc = 1, num_lakec + c = filter_lakec(fc) + + heat_dry_mass(c) = heat_dry_mass(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (csol(c,j)*(1-watsat(c,j))*dz(c,j))) + call AccumulateLiquidWaterHeat( & + temp = t_soisno(c,j), & + h2o = h2osoi_liq(c,j), & + cv_liquid = cv_liquid(c), & + heat_liquid = heat_liquid(c), & + latent_heat_liquid = latent_heat_liquid(c)) + heat_ice(c) = heat_ice(c) + & + TempToHeat(temp = t_soisno(c,j), cv = (h2osoi_ice(c,j)*cpice)) + end do + end do + + ! TODO(wjs, 2017-03-11) Include heat content of water in lakes, once we include + ! lake water as an explicit water state (https://github.com/NCAR/CLM/issues/2) + + do fc = 1, num_lakec + c = filter_lakec(fc) + heat(c) = heat_dry_mass(c) + heat_ice(c) + heat_liquid(c) + latent_heat_liquid(c) + end do + + end associate + + end subroutine ComputeHeatLake + + !----------------------------------------------------------------------- + subroutine AdjustDeltaHeatForDeltaLiq(bounds, delta_liq, & + liquid_water_temp1, liquid_water_temp2, & + delta_heat) + ! + ! !DESCRIPTION: + ! Adjusts delta_heat (the change in gridcell heat content due to land cover change + ! that needs to be accounted for via a heat flux) to account for the implicit heat + ! flux associated with delta_liq. + ! + ! Note that, throughout CLM, we don't explicitly track the temperature or heat content + ! of runoff. Furthermore, we currently cannot compute the exact heat content of + ! delta_liq (the dynamic landcover adjustment), because we aren't summing the liquid + ! water heat content on a pool-by-pool (and layer-by-layer) basis, but rather on a + ! bulk basis across each column. Thus, the formulation in this routine is currently + ! using a rough approximation of the temperature of delta_liq - assuming it is at the + ! average temperature of the liquid water in the grid cell. This can be a poor + ! assumption in some cases (e.g., if the grid cell is 90% glacier, 5% natural veg and + ! 5% crop, and the only transitions are between natural veg and crop - then the + ! glacier's liquid water temperature factors into the average liquid water + ! temperature, even though it doesn't contribute at all to delta_liq). + ! + ! Also note that we don't account for delta_ice here. This implicitly assumes that + ! ice runoff is at heat_base_temp (which is reasonable as long as heat_base_temp = + ! tfrz). + ! + ! Eventually, if we begin to explicitly account for the temperature / heat content of + ! liquid and ice runoff in CLM, then this routine should be reworked to use the true + ! heat contents of both liquid and ice runoff. + ! + ! Sign convention: delta_liq and delta_heat are positive if the post-landcover change + ! value is greater than the pre-landcover change value. + ! + ! !USES: + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + real(r8), intent(in) :: delta_liq( bounds%begg: ) ! change in gridcell h2o liq content [kg/m^2] + real(r8), intent(in) :: liquid_water_temp1( bounds%begg: ) ! average liquid water temperature before land cover change [K] + real(r8), intent(in) :: liquid_water_temp2( bounds%begg: ) ! average liquid water temperature after land cover change [K] + real(r8), intent(inout) :: delta_heat( bounds%begg: ) ! change in gridcell heat content [J/m^2] + ! + ! !LOCAL VARIABLES: + integer :: g + real(r8) :: water_temperature ! [K] + real(r8) :: total_liquid_heat ! [J/m^2] + real(r8) :: heat_liquid ! [J/m^2] + real(r8) :: latent_heat_liquid ! [J/m^2] + real(r8) :: cv ! heat capacity [J/(m^2 K)] + + character(len=*), parameter :: subname = 'AdjustDeltaHeatForDeltaLiq' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(delta_liq) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(liquid_water_temp1) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(liquid_water_temp2) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(delta_heat) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + + do g = bounds%begg, bounds%endg + if (delta_liq(g) /= 0._r8) then + if (delta_liq(g) < 0._r8) then + ! There was more water in the initial state than in the final state. We'll + ! generate a positive runoff. We assume that the runoff has a temperature equal + ! to the average temperature of liquid water in the initial state. + water_temperature = liquid_water_temp1(g) + else + ! There is more water in the final state than in the initial state. We'll + ! generate a negative runoff. We assume that we're sucking water out of the + ! ocean at a temperature equal to the average temperature of liquid water in + ! the final state. + water_temperature = liquid_water_temp2(g) + end if + + ! Since we're not trying to completely conserve energy here, it's better to + ! ensure that the estimated water temperature is in some reasonable bounds. + ! This protects against getting bad temperatures as a result of something like + ! catastrophic cancellation, or the weirdness that can arise from having + ! negative water volumes included in the averages. + water_temperature = max(water_temperature, DeltaLiqMinTemp) + water_temperature = min(water_temperature, DeltaLiqMaxTemp) + + total_liquid_heat = LiquidWaterHeat( & + temp = water_temperature, & + h2o = delta_liq(g)) + + ! For delta_liq < 0 (liq2 < liq1): We'll generate a positive runoff; we want to + ! effectively include some positive heat from that positive runoff in the heat2 + ! state, which means adding a positive term to delta_heat. Since the above heat + ! quantities will be negative, we need to subtract them. The reverse is true + ! for delta_liq > 0; again, we need to subtract the heat quantities. + delta_heat(g) = delta_heat(g) - total_liquid_heat + + end if + end do + + end subroutine AdjustDeltaHeatForDeltaLiq + + !----------------------------------------------------------------------- + function LiquidWaterHeat(temp, h2o) result(heat) + ! + ! !DESCRIPTION: + ! Get the total heat content (including latent heat) of some mass of liquid water at + ! a given temperature, using a base temperature of heat_base_temp. + ! + ! !USES: + ! + ! !ARGUMENTS: + real(r8) :: heat ! function result + real(r8), intent(in) :: temp ! temperature [K] + real(r8), intent(in) :: h2o ! water mass [kg/m^2] + ! + ! !LOCAL VARIABLES: + real(r8) :: heat_liquid ! heat content of liquid water, excluding latent heat [J/m^2] + real(r8) :: latent_heat_liquid ! latent heat content of liquid water [J/m^2] + + character(len=*), parameter :: subname = 'LiquidWaterHeat' + !----------------------------------------------------------------------- + + heat_liquid = 0._r8 + latent_heat_liquid = 0._r8 + call AccumulateLiquidWaterHeat(temp = temp, h2o = h2o, & + heat_liquid = heat_liquid, latent_heat_liquid = latent_heat_liquid) + + heat = heat_liquid + latent_heat_liquid + + end function LiquidWaterHeat + + + !----------------------------------------------------------------------- + subroutine AccumulateLiquidWaterHeat(temp, h2o, & + heat_liquid, latent_heat_liquid, cv_liquid) + ! + ! !DESCRIPTION: + ! In the course of accumulating heat contents: Accumulate quantities that we need to + ! count for liquid water, for a single column + ! + ! !ARGUMENTS: + real(r8), intent(in) :: temp ! temperature [K] + real(r8), intent(in) :: h2o ! water mass [kg/m^2] + + real(r8), intent(inout) :: heat_liquid ! accumulated total heat content of liquid water for this column, excluding latent heat [J/m^2] + real(r8), intent(inout) :: latent_heat_liquid ! accumulated total latent heat content of liquid water for this column [J/m^2] + real(r8), intent(inout), optional :: cv_liquid ! accumulated total liquid heat capacity for this column [J/(m^2 K)] + ! + ! !LOCAL VARIABLES: + real(r8) :: cv ! heat capacity [J/(m^2 K)] + + character(len=*), parameter :: subname = 'AccumulateLiquidWaterHeat' + !----------------------------------------------------------------------- + + cv = h2o*cpliq + if (present(cv_liquid)) then + cv_liquid = cv_liquid + cv + end if + heat_liquid = heat_liquid + TempToHeat(temp = temp, cv = cv) + latent_heat_liquid = latent_heat_liquid + h2o*hfus + end subroutine AccumulateLiquidWaterHeat + + !----------------------------------------------------------------------- + pure function TempToHeat(temp, cv) result(heat) + ! + ! !DESCRIPTION: + ! Convert temperature to heat content + ! + ! !ARGUMENTS: + real(r8) :: heat ! function result: heat in J/m^2 + real(r8), intent(in) :: temp ! temperature [K] + real(r8), intent(in) :: cv ! heat capacity [J/(m^2 K)] + !----------------------------------------------------------------------- + + heat = cv*(temp - heat_base_temp) + + end function TempToHeat + +end module TotalWaterAndHeatMod diff --git a/src/biogeophys/UrbanAlbedoMod.F90 b/src/biogeophys/UrbanAlbedoMod.F90 index 2e63cf83bc..06552ae1d0 100644 --- a/src/biogeophys/UrbanAlbedoMod.F90 +++ b/src/biogeophys/UrbanAlbedoMod.F90 @@ -156,6 +156,8 @@ subroutine UrbanAlbedo (bounds, num_urbanl, filter_urbanl, & albi => surfalb_inst%albi_patch , & ! Output: [real(r8) (:,:) ] urban pft surface albedo (diffuse) begl => bounds%begl , & + vf_sr => urbanparams_inst%vf_sr , & ! Input: [real(r8) (:) ] view factor of sky for road + vf_sw => urbanparams_inst%vf_sw , & ! Input: [real(r8) (:) ] view factor of sky for one wall endl => bounds%endl & ) @@ -183,8 +185,22 @@ subroutine UrbanAlbedo (bounds, num_urbanl, filter_urbanl, & do fp = 1,num_urbanp p = filter_urbanp(fp) l = patch%landunit(p) - albd(p,ib) = 1._r8 - albi(p,ib) = 1._r8 + ! Setting albedos to wall and road view factors ensures that urban + ! albedo will scale up to 1.0 + c = patch%column(p) + if (col%itype(c) == icol_sunwall) then + albd(p,ib) = vf_sw(l) + albi(p,ib) = vf_sw(l) + else if (col%itype(c) == icol_shadewall) then + albd(p,ib) = vf_sw(l) + albi(p,ib) = vf_sw(l) + else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then + albd(p,ib) = vf_sr(l) + albi(p,ib) = vf_sr(l) + else if (col%itype(c) == icol_roof) then + albd(p,ib) = 1._r8 + albi(p,ib) = 1._r8 + endif fabd(p,ib) = 0._r8 fabd_sun(p,ib) = 0._r8 fabd_sha(p,ib) = 0._r8 @@ -230,14 +246,16 @@ subroutine UrbanAlbedo (bounds, num_urbanl, filter_urbanl, & sabs_perroad_dif(l,ib) = 0._r8 sref_roof_dir(l,ib) = 1._r8 sref_roof_dif(l,ib) = 1._r8 - sref_sunwall_dir(l,ib) = 1._r8 - sref_sunwall_dif(l,ib) = 1._r8 - sref_shadewall_dir(l,ib) = 1._r8 - sref_shadewall_dif(l,ib) = 1._r8 - sref_improad_dir(l,ib) = 1._r8 - sref_improad_dif(l,ib) = 1._r8 - sref_perroad_dir(l,ib) = 1._r8 - sref_perroad_dif(l,ib) = 1._r8 + ! Setting sref to wall and road view factors ensures that urban + ! albedo will scale up to 1.0 + sref_sunwall_dir(l,ib) = vf_sw(l) + sref_sunwall_dif(l,ib) = vf_sw(l) + sref_shadewall_dir(l,ib) = vf_sw(l) + sref_shadewall_dif(l,ib) = vf_sw(l) + sref_improad_dir(l,ib) = vf_sr(l) + sref_improad_dif(l,ib) = vf_sr(l) + sref_perroad_dir(l,ib) = vf_sr(l) + sref_perroad_dif(l,ib) = vf_sr(l) end do end do diff --git a/src/biogeophys/UrbanParamsType.F90 b/src/biogeophys/UrbanParamsType.F90 index 2f987f88b6..4b4187c3af 100644 --- a/src/biogeophys/UrbanParamsType.F90 +++ b/src/biogeophys/UrbanParamsType.F90 @@ -377,7 +377,7 @@ subroutine UrbanInput(begg, endg, mode) use fileutils , only : getavu, relavu, getfil, opnfil use spmdMod , only : masterproc use domainMod , only : ldomain - use ncdio_pio , only : file_desc_t, ncd_defvar, ncd_io, ncd_inqvdlen, ncd_inqfdims + use ncdio_pio , only : file_desc_t, ncd_io, ncd_inqvdlen, ncd_inqfdims use ncdio_pio , only : ncd_pio_openfile, ncd_pio_closefile, ncd_inqdid, ncd_inqdlen ! ! !ARGUMENTS: diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 905c200dc1..8cf5eaf2f9 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -36,12 +36,13 @@ module WaterstateType real(r8), pointer :: h2osno_old_col (:) ! col snow mass for previous time step (kg/m2) (new) real(r8), pointer :: h2osoi_liq_col (:,:) ! col liquid water (kg/m2) (new) (-nlevsno+1:nlevgrnd) real(r8), pointer :: h2osoi_ice_col (:,:) ! col ice lens (kg/m2) (new) (-nlevsno+1:nlevgrnd) + real(r8), pointer :: h2osoi_liq_tot_col (:) ! vertically summed col liquid water (kg/m2) (new) (-nlevsno+1:nlevgrnd) + real(r8), pointer :: h2osoi_ice_tot_col (:) ! vertically summed col ice lens (kg/m2) (new) (-nlevsno+1:nlevgrnd) real(r8), pointer :: h2osoi_liqice_10cm_col (:) ! col liquid water + ice lens in top 10cm of soil (kg/m2) real(r8), pointer :: h2osoi_vol_col (:,:) ! col volumetric soil water (0<=h2osoi_vol<=watsat) [m3/m3] (nlevgrnd) real(r8), pointer :: air_vol_col (:,:) ! col air filled porosity real(r8), pointer :: h2osoi_liqvol_col (:,:) ! col volumetric liquid water content (v/v) real(r8), pointer :: h2ocan_patch (:) ! patch canopy water (mm H2O) - real(r8), pointer :: h2ocan_col (:) ! col canopy water (mm H2O) real(r8), pointer :: h2osfc_col (:) ! col surface water (mm H2O) real(r8), pointer :: snocan_patch (:) ! patch canopy snow water (mm H2O) real(r8), pointer :: liqcan_patch (:) ! patch canopy liquid water (mm H2O) @@ -53,6 +54,12 @@ module WaterstateType real(r8), pointer :: ice2_grc (:) ! grc post land cover change total ice content real(r8), pointer :: tws_grc (:) ! grc total water storage (mm H2O) + real(r8), pointer :: total_plant_stored_h2o_col(:) ! col water that is bound in plants, including roots, sapwood, leaves, etc + ! in most cases, the vegetation scheme does not have a dynamic + ! water storage in plants, and thus 0.0 is a suitable for the trivial case. + ! When FATES is coupled in with plant hydraulics turned on, this storage + ! term is set to non-zero. (kg/m2 H2O) + real(r8), pointer :: snw_rds_col (:,:) ! col snow grain radius (col,lyr) [m^-6, microns] real(r8), pointer :: snw_rds_top_col (:) ! col snow grain radius (top layer) [m^-6, microns] real(r8), pointer :: h2osno_top_col (:) ! col top-layer mass of snow [kg] @@ -85,9 +92,7 @@ module WaterstateType ! Balance Checks - real(r8), pointer :: begwb_patch (:) ! water mass begining of the time step real(r8), pointer :: begwb_col (:) ! water mass begining of the time step - real(r8), pointer :: endwb_patch (:) ! water mass end of the time step real(r8), pointer :: endwb_col (:) ! water mass end of the time step real(r8), pointer :: errh2o_patch (:) ! water conservation error (mm H2O) real(r8), pointer :: errh2o_col (:) ! water conservation error (mm H2O) @@ -183,8 +188,9 @@ subroutine InitAllocate(this, bounds) allocate(this%h2osoi_liqvol_col (begc:endc,-nlevsno+1:nlevgrnd)) ; this%h2osoi_liqvol_col (:,:) = nan allocate(this%h2osoi_ice_col (begc:endc,-nlevsno+1:nlevgrnd)) ; this%h2osoi_ice_col (:,:) = nan allocate(this%h2osoi_liq_col (begc:endc,-nlevsno+1:nlevgrnd)) ; this%h2osoi_liq_col (:,:) = nan + allocate(this%h2osoi_ice_tot_col (begc:endc)) ; this%h2osoi_ice_tot_col (:) = nan + allocate(this%h2osoi_liq_tot_col (begc:endc)) ; this%h2osoi_liq_tot_col (:) = nan allocate(this%h2ocan_patch (begp:endp)) ; this%h2ocan_patch (:) = nan - allocate(this%h2ocan_col (begc:endc)) ; this%h2ocan_col (:) = nan allocate(this%snocan_patch (begp:endp)) ; this%snocan_patch (:) = nan allocate(this%liqcan_patch (begp:endp)) ; this%liqcan_patch (:) = nan allocate(this%snounload_patch (begp:endp)) ; this%snounload_patch (:) = nan @@ -196,6 +202,8 @@ subroutine InitAllocate(this, bounds) allocate(this%ice2_grc (begg:endg)) ; this%ice2_grc (:) = nan allocate(this%tws_grc (begg:endg)) ; this%tws_grc (:) = nan + allocate(this%total_plant_stored_h2o_col(begc:endc)) ; this%total_plant_stored_h2o_col(:) = nan + allocate(this%snw_rds_col (begc:endc,-nlevsno+1:0)) ; this%snw_rds_col (:,:) = nan allocate(this%snw_rds_top_col (begc:endc)) ; this%snw_rds_top_col (:) = nan allocate(this%h2osno_top_col (begc:endc)) ; this%h2osno_top_col (:) = nan @@ -225,9 +233,7 @@ subroutine InitAllocate(this, bounds) allocate(this%fcansno_patch (begp:endp)) ; this%fcansno_patch (:) = nan allocate(this%fdry_patch (begp:endp)) ; this%fdry_patch (:) = nan - allocate(this%begwb_patch (begp:endp)) ; this%begwb_patch (:) = nan allocate(this%begwb_col (begc:endc)) ; this%begwb_col (:) = nan - allocate(this%endwb_patch (begp:endp)) ; this%endwb_patch (:) = nan allocate(this%endwb_col (begc:endc)) ; this%endwb_col (:) = nan allocate(this%errh2o_patch (begp:endp)) ; this%errh2o_patch (:) = nan allocate(this%errh2o_col (begc:endc)) ; this%errh2o_col (:) = nan @@ -242,9 +248,9 @@ subroutine InitHistory(this, bounds) ! ! !USES: use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) - use clm_varctl , only : create_glacier_mec_landunit, use_cn, use_lch4 + use clm_varctl , only : use_cn, use_lch4 use clm_varctl , only : hist_wrtch4diag - use clm_varpar , only : nlevsno + use clm_varpar , only : nlevsno, nlevsoi use histFileMod , only : hist_addfld1d, hist_addfld2d, no_snow_normal, no_snow_zero ! ! !ARGUMENTS: @@ -276,26 +282,41 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='Snow ice content', & ptr_col=data2dptr, no_snow_behavior=no_snow_normal, default='inactive') - this%h2osoi_vol_col(begc:endc,:) = spval - call hist_addfld2d (fname='H2OSOI', units='mm3/mm3', type2d='levgrnd', & + data2dptr => this%h2osoi_vol_col(begc:endc,1:nlevsoi) + call hist_addfld2d (fname='H2OSOI', units='mm3/mm3', type2d='levsoi', & avgflag='A', long_name='volumetric soil water (vegetated landunits only)', & ptr_col=this%h2osoi_vol_col, l2g_scale_type='veg') - this%h2osoi_liq_col(begc:endc,:) = spval - call hist_addfld2d (fname='SOILLIQ', units='kg/m2', type2d='levgrnd', & +! this%h2osoi_liq_col(begc:endc,:) = spval +! call hist_addfld2d (fname='SOILLIQ', units='kg/m2', type2d='levgrnd', & +! avgflag='A', long_name='soil liquid water (vegetated landunits only)', & +! ptr_col=this%h2osoi_liq_col, l2g_scale_type='veg') + + data2dptr => this%h2osoi_liq_col(begc:endc,1:nlevsoi) + call hist_addfld2d (fname='SOILLIQ', units='kg/m2', type2d='levsoi', & avgflag='A', long_name='soil liquid water (vegetated landunits only)', & - ptr_col=this%h2osoi_liq_col, l2g_scale_type='veg') + ptr_col=data2dptr, l2g_scale_type='veg') - this%h2osoi_ice_col(begc:endc,:) = spval - call hist_addfld2d (fname='SOILICE', units='kg/m2', type2d='levgrnd', & + data2dptr => this%h2osoi_ice_col(begc:endc,1:nlevsoi) + call hist_addfld2d (fname='SOILICE', units='kg/m2', type2d='levsoi', & avgflag='A', long_name='soil ice (vegetated landunits only)', & - ptr_col=this%h2osoi_ice_col, l2g_scale_type='veg') + ptr_col=data2dptr, l2g_scale_type='veg') this%h2osoi_liqice_10cm_col(begc:endc) = spval call hist_addfld1d (fname='SOILWATER_10CM', units='kg/m2', & avgflag='A', long_name='soil liquid water + ice in top 10cm of soil (veg landunits only)', & ptr_col=this%h2osoi_liqice_10cm_col, set_urb=spval, set_lake=spval, l2g_scale_type='veg') + this%h2osoi_liq_tot_col(begc:endc) = spval + call hist_addfld1d (fname='TOTSOILLIQ', units='kg/m2', & + avgflag='A', long_name='vertically summed soil liquid water (veg landunits only)', & + ptr_col=this%h2osoi_liq_tot_col, set_urb=spval, set_lake=spval, l2g_scale_type='veg') + + this%h2osoi_ice_tot_col(begc:endc) = spval + call hist_addfld1d (fname='TOTSOILICE', units='kg/m2', & + avgflag='A', long_name='vertically summed soil cie (veg landunits only)', & + ptr_col=this%h2osoi_ice_tot_col, set_urb=spval, set_lake=spval, l2g_scale_type='veg') + this%h2ocan_patch(begp:endp) = spval call hist_addfld1d (fname='H2OCAN', units='mm', & avgflag='A', long_name='intercepted water', & @@ -326,22 +347,22 @@ subroutine InitHistory(this, bounds) default='inactive') this%liq1_grc(begg:endg) = spval - call hist_addfld1d (fname='GC_LIQ1', units='mm', & + call hist_addfld1d (fname='LIQUID_CONTENT1', units='mm', & avgflag='A', long_name='initial gridcell total liq content', & ptr_lnd=this%liq1_grc) this%liq2_grc(begg:endg) = spval - call hist_addfld1d (fname='GC_LIQ2', units='mm', & + call hist_addfld1d (fname='LIQUID_CONTENT2', units='mm', & avgflag='A', long_name='post landuse change gridcell total liq content', & ptr_lnd=this%liq2_grc, default='inactive') this%ice1_grc(begg:endg) = spval - call hist_addfld1d (fname='GC_ICE1', units='mm', & + call hist_addfld1d (fname='ICE_CONTENT1', units='mm', & avgflag='A', long_name='initial gridcell total ice content', & ptr_lnd=this%ice1_grc) this%ice2_grc(begg:endg) = spval - call hist_addfld1d (fname='GC_ICE2', units='mm', & + call hist_addfld1d (fname='ICE_CONTENT2', units='mm', & avgflag='A', long_name='post land cover change total ice content', & ptr_lnd=this%ice2_grc, default='inactive') @@ -355,6 +376,14 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='total water storage', & ptr_lnd=this%tws_grc) + ! (rgk 02-02-2017) There is intentionally no entry here for stored plant water + ! I think that since the value is zero in all cases except + ! for FATES plant hydraulics, it will be confusing for users + ! when they see their plants have no water in output files. + ! So it is not useful diagnostic information. The information + ! can be provided through FATES specific history diagnostics + ! if need be. + ! Humidity this%q_ref2m_patch(begp:endp) = spval @@ -370,12 +399,12 @@ subroutine InitHistory(this, bounds) this%rh_ref2m_r_patch(begp:endp) = spval call hist_addfld1d (fname='RH2M_R', units='%', & avgflag='A', long_name='Rural 2m specific humidity', & - ptr_patch=this%rh_ref2m_r_patch, set_spec=spval) + ptr_patch=this%rh_ref2m_r_patch, set_spec=spval, default='inactive') this%rh_ref2m_u_patch(begp:endp) = spval call hist_addfld1d (fname='RH2M_U', units='%', & avgflag='A', long_name='Urban 2m relative humidity', & - ptr_patch=this%rh_ref2m_u_patch, set_nourb=spval) + ptr_patch=this%rh_ref2m_u_patch, set_nourb=spval, default='inactive') this%rh_af_patch(begp:endp) = spval call hist_addfld1d (fname='RHAF', units='fraction', & @@ -444,7 +473,7 @@ subroutine InitHistory(this, bounds) this%snow_depth_col(begc:endc) = spval call hist_addfld1d (fname='SNOW_DEPTH', units='m', & avgflag='A', long_name='snow height of snow covered area', & - ptr_col=this%snow_depth_col, c2l_scale_type='urbanf')!, default='inactive') + ptr_col=this%snow_depth_col, c2l_scale_type='urbanf') call hist_addfld1d (fname='SNOW_DEPTH_ICE', units='m', & avgflag='A', long_name='snow height of snow covered area (ice landunits only)', & @@ -477,18 +506,16 @@ subroutine InitHistory(this, bounds) ptr_col=this%int_snow_col, l2g_scale_type='ice', & default='inactive') - if (create_glacier_mec_landunit) then - this%snow_persistence_col(begc:endc) = spval - call hist_addfld1d (fname='SNOW_PERSISTENCE', units='seconds', & - avgflag='I', long_name='Length of time of continuous snow cover (nat. veg. landunits only)', & - ptr_col=this%snow_persistence_col, l2g_scale_type='natveg') - end if + this%snow_persistence_col(begc:endc) = spval + call hist_addfld1d (fname='SNOW_PERSISTENCE', units='seconds', & + avgflag='I', long_name='Length of time of continuous snow cover (nat. veg. landunits only)', & + ptr_col=this%snow_persistence_col, l2g_scale_type='natveg') if (use_cn) then this%wf_col(begc:endc) = spval call hist_addfld1d (fname='WF', units='proportion', & avgflag='A', long_name='soil water as frac. of whc for top 0.05 m', & - ptr_col=this%wf_col) + ptr_col=this%wf_col, default='inactive') end if this%h2osno_top_col(begc:endc) = spval @@ -561,7 +588,7 @@ subroutine InitCold(this, bounds, & use shr_kind_mod , only : r8 => shr_kind_r8 use shr_const_mod , only : SHR_CONST_TKFRZ use clm_varpar , only : nlevsoi, nlevgrnd, nlevsno, nlevlak, nlevurb - use landunit_varcon , only : istice, istwet, istsoil, istdlak, istcrop, istice_mec + use landunit_varcon , only : istwet, istsoil, istdlak, istcrop, istice_mec use column_varcon , only : icol_shadewall, icol_road_perv use column_varcon , only : icol_road_imperv, icol_roof, icol_sunwall use clm_varcon , only : denice, denh2o, spval, sb, bdsno @@ -625,11 +652,15 @@ subroutine InitCold(this, bounds, & end if end do + ! Water Stored in plants is almost always a static entity, with the exception + ! of when FATES-hydraulics is used. As such, this is trivially set to 0.0 (rgk 03-2017) + this%total_plant_stored_h2o_col(bounds%begc:bounds%endc) = 0.0_r8 + + associate(snl => col%snl) this%h2osfc_col(bounds%begc:bounds%endc) = 0._r8 this%h2ocan_patch(bounds%begp:bounds%endp) = 0._r8 - this%h2ocan_col(bounds%begc:bounds%endc) = 0._r8 this%snocan_patch(bounds%begp:bounds%endp) = 0._r8 this%liqcan_patch(bounds%begp:bounds%endp) = 0._r8 this%snounload_patch(bounds%begp:bounds%endp) = 0._r8 @@ -742,7 +773,7 @@ subroutine InitCold(this, bounds, & this%h2osoi_vol_col(c,j) = 1.0_r8 endif end do - else if (lun%itype(l) == istice .or. lun%itype(l) == istice_mec) then + else if (lun%itype(l) == istice_mec) then nlevs = nlevgrnd do j = 1, nlevs this%h2osoi_vol_col(c,j) = 1.0_r8 @@ -767,6 +798,7 @@ subroutine InitCold(this, bounds, & end if end do + !-------------------------------------------- ! Set Lake water !-------------------------------------------- @@ -824,7 +856,7 @@ subroutine Restart(this, bounds, ncid, flag, & ! ! !USES: use spmdMod , only : masterproc - use clm_varcon , only : denice, denh2o, pondmx, watmin, spval + use clm_varcon , only : denice, denh2o, pondmx, watmin, spval, nameg use landunit_varcon , only : istcrop, istdlak, istsoil use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use clm_time_manager , only : is_first_step @@ -903,6 +935,13 @@ subroutine Restart(this, bounds, ncid, flag, & long_name='Canopy snow unloading', units='kg/m2', & interpinic_flag='interp', readvar=readvar, data=this%snounload_patch) + ! TWS is needed when methane is on and the TWS_inversion is used to get exact + ! restart. + call restartvar(ncid=ncid, flag=flag, varname='TWS', xtype=ncd_double, & + dim1name=nameg, & + long_name='Total Water Storage', units='mm', & + interpinic_flag='interp', readvar=readvar, data=this%tws_grc) + if(use_luna)then call restartvar(ncid=ncid, flag=flag, varname='rh10', xtype=ncd_double, & dim1name='pft', long_name='10-day mean boundary layer relatie humidity', units='unitless', & diff --git a/src/biogeophys/WaterfluxType.F90 b/src/biogeophys/WaterfluxType.F90 index fd8f0a8ddf..fe84753ea4 100644 --- a/src/biogeophys/WaterfluxType.F90 +++ b/src/biogeophys/WaterfluxType.F90 @@ -43,10 +43,12 @@ module WaterfluxType real(r8), pointer :: qflx_evap_grnd_col (:) ! col ground surface evaporation rate (mm H2O/s) [+] real(r8), pointer :: qflx_phs_neg_col (:) ! col sum of negative hydraulic redistribution fluxes (mm H2O/s) [+] - ! In the snow capping parametrization excess mass above h2osno_max is removed. A breakdown of mass into liquid - ! and solid fluxes is done, these are represented by qflx_snwcp_liq_col and qflx_snwcp_ice_col. + ! In the snow capping parametrization excess mass above h2osno_max is removed. A breakdown of mass into liquid + ! and solid fluxes is done, these are represented by qflx_snwcp_liq_col and qflx_snwcp_ice_col. real(r8), pointer :: qflx_snwcp_liq_col (:) ! col excess liquid h2o due to snow capping (outgoing) (mm H2O /s) real(r8), pointer :: qflx_snwcp_ice_col (:) ! col excess solid h2o due to snow capping (outgoing) (mm H2O /s) + real(r8), pointer :: qflx_snwcp_discarded_liq_col(:) ! col excess liquid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) + real(r8), pointer :: qflx_snwcp_discarded_ice_col(:) ! col excess solid h2o due to snow capping, which we simply discard in order to reset the snow pack (mm H2O /s) real(r8), pointer :: qflx_tran_veg_patch (:) ! patch vegetation transpiration (mm H2O/s) (+ = to atm) real(r8), pointer :: qflx_tran_veg_col (:) ! col vegetation transpiration (mm H2O/s) (+ = to atm) @@ -61,12 +63,12 @@ module WaterfluxType real(r8), pointer :: qflx_snotempunload_patch (:) ! patch canopy snow temp unloading (mm H2O /s) real(r8), pointer :: qflx_snotempunload_col (:) ! col canopy snow temp unloading (mm H2O /s) - real(r8), pointer :: qflx_ev_snow_patch (:) ! patch evaporation heat flux from snow (W/m**2) [+ to atm] - real(r8), pointer :: qflx_ev_snow_col (:) ! col evaporation heat flux from snow (W/m**2) [+ to atm] - real(r8), pointer :: qflx_ev_soil_patch (:) ! patch evaporation heat flux from soil (W/m**2) [+ to atm] - real(r8), pointer :: qflx_ev_soil_col (:) ! col evaporation heat flux from soil (W/m**2) [+ to atm] - real(r8), pointer :: qflx_ev_h2osfc_patch (:) ! patch evaporation heat flux from soil (W/m**2) [+ to atm] - real(r8), pointer :: qflx_ev_h2osfc_col (:) ! col evaporation heat flux from soil (W/m**2) [+ to atm] + real(r8), pointer :: qflx_ev_snow_patch (:) ! patch evaporation heat flux from snow (mm H2O/s) [+ to atm] + real(r8), pointer :: qflx_ev_snow_col (:) ! col evaporation heat flux from snow (mm H2O/s) [+ to atm] + real(r8), pointer :: qflx_ev_soil_patch (:) ! patch evaporation heat flux from soil (mm H2O/s) [+ to atm] + real(r8), pointer :: qflx_ev_soil_col (:) ! col evaporation heat flux from soil (mm H2O/s) [+ to atm] + real(r8), pointer :: qflx_ev_h2osfc_patch (:) ! patch evaporation heat flux from soil (mm H2O/s) [+ to atm] + real(r8), pointer :: qflx_ev_h2osfc_col (:) ! col evaporation heat flux from soil (mm H2O/s) [+ to atm] real(r8), pointer :: qflx_adv_col (:,:) ! col advective flux across different soil layer interfaces [mm H2O/s] [+ downward] real(r8), pointer :: qflx_rootsoi_col (:,:) ! col root and soil water exchange [mm H2O/s] [+ into root] @@ -187,6 +189,8 @@ subroutine InitAllocate(this, bounds) allocate(this%qflx_sub_snow_col (begc:endc)) ; this%qflx_sub_snow_col (:) = 0.0_r8 allocate(this%qflx_snwcp_liq_col (begc:endc)) ; this%qflx_snwcp_liq_col (:) = nan allocate(this%qflx_snwcp_ice_col (begc:endc)) ; this%qflx_snwcp_ice_col (:) = nan + allocate(this%qflx_snwcp_discarded_liq_col(begc:endc)) ; this%qflx_snwcp_discarded_liq_col(:) = nan + allocate(this%qflx_snwcp_discarded_ice_col(begc:endc)) ; this%qflx_snwcp_discarded_ice_col(:) = nan allocate(this%qflx_tran_veg_col (begc:endc)) ; this%qflx_tran_veg_col (:) = nan allocate(this%qflx_evap_veg_col (begc:endc)) ; this%qflx_evap_veg_col (:) = nan allocate(this%qflx_evap_can_col (begc:endc)) ; this%qflx_evap_can_col (:) = nan @@ -261,7 +265,7 @@ end subroutine InitAllocate subroutine InitHistory(this, bounds) ! ! !USES: - use clm_varctl , only : create_glacier_mec_landunit, use_cn + use clm_varctl , only : use_cn use histFileMod , only : hist_addfld1d, hist_addfld2d, no_snow_normal ! ! !ARGUMENTS: @@ -297,7 +301,8 @@ subroutine InitHistory(this, bounds) this%qflx_qrgwl_col(begc:endc) = spval call hist_addfld1d (fname='QRGWL', units='mm/s', & - avgflag='A', long_name='surface runoff at glaciers (liquid only), wetlands, lakes', & + avgflag='A', & + long_name='surface runoff at glaciers (liquid only), wetlands, lakes; also includes melted ice runoff from QSNWCPICE', & ptr_col=this%qflx_qrgwl_col, c2l_scale_type='urbanf') this%qflx_drain_col(begc:endc) = spval @@ -329,24 +334,32 @@ subroutine InitHistory(this, bounds) this%qflx_runoff_col(begc:endc) = spval call hist_addfld1d (fname='QRUNOFF', units='mm/s', & avgflag='A', & - long_name='total liquid runoff (does not include QSNWCPICE) not including correction for land use change', & + long_name='total liquid runoff not including correction for land use change', & ptr_col=this%qflx_runoff_col, c2l_scale_type='urbanf') + call hist_addfld1d (fname='QRUNOFF_ICE', units='mm/s', avgflag='A', & + long_name='total liquid runoff not incl corret for LULCC (ice landunits only)', & + ptr_col=this%qflx_runoff_col, c2l_scale_type='urbanf', l2g_scale_type='ice') + this%qflx_runoff_u_col(begc:endc) = spval call hist_addfld1d (fname='QRUNOFF_U', units='mm/s', & avgflag='A', long_name='Urban total runoff', & - ptr_col=this%qflx_runoff_u_col, set_nourb=spval, c2l_scale_type='urbanf') + ptr_col=this%qflx_runoff_u_col, set_nourb=spval, c2l_scale_type='urbanf', default='inactive') this%qflx_runoff_r_col(begc:endc) = spval call hist_addfld1d (fname='QRUNOFF_R', units='mm/s', & avgflag='A', long_name='Rural total runoff', & - ptr_col=this%qflx_runoff_r_col, set_spec=spval) + ptr_col=this%qflx_runoff_r_col, set_spec=spval, default='inactive') this%qflx_snow_drain_col(begc:endc) = spval call hist_addfld1d (fname='QFLX_SNOW_DRAIN', units='mm/s', & avgflag='A', long_name='drainage from snow pack', & ptr_col=this%qflx_snow_drain_col, c2l_scale_type='urbanf') + call hist_addfld1d (fname='QFLX_SNOW_DRAIN_ICE', units='mm/s', & + avgflag='A', long_name='drainage from snow pack melt (ice landunits only)', & + ptr_col=this%qflx_snow_drain_col, c2l_scale_type='urbanf', l2g_scale_type='ice') + this%qflx_snomelt_col(begc:endc) = spval call hist_addfld1d (fname='QSNOMELT', units='mm/s', & avgflag='A', long_name='snow melt rate', & @@ -354,8 +367,7 @@ subroutine InitHistory(this, bounds) call hist_addfld1d (fname='QSNOMELT_ICE', units='mm/s', & avgflag='A', long_name='snow melt (ice landunits only)', & - ptr_col=this%qflx_snomelt_col, c2l_scale_type='urbanf', l2g_scale_type='ice', & - default='inactive') + ptr_col=this%qflx_snomelt_col, c2l_scale_type='urbanf', l2g_scale_type='ice') this%qflx_snomelt_lyr_col(begc:endc,-nlevsno+1:0) = spval data2dptr => this%qflx_snomelt_lyr_col(begc:endc,-nlevsno+1:0) @@ -375,8 +387,7 @@ subroutine InitHistory(this, bounds) call hist_addfld1d (fname='QSNOFRZ_ICE', units='mm/s', & avgflag='A', long_name='column-integrated snow freezing rate (ice landunits only)', & - ptr_col=this%qflx_snofrz_col, c2l_scale_type='urbanf', l2g_scale_type='ice', & - default='inactive') + ptr_col=this%qflx_snofrz_col, c2l_scale_type='urbanf', l2g_scale_type='ice') this%qflx_snofrz_lyr_col(begc:endc,-nlevsno+1:0) = spval data2dptr => this%qflx_snofrz_lyr_col(begc:endc,-nlevsno+1:0) @@ -411,8 +422,11 @@ subroutine InitHistory(this, bounds) call hist_addfld1d (fname='QSOIL_ICE', units='mm/s', & avgflag='A', long_name='Ground evaporation (ice landunits only)', & - ptr_patch=this%qflx_evap_soi_patch, c2l_scale_type='urbanf', l2g_scale_type='ice', & - default='inactive') + ptr_patch=this%qflx_evap_soi_patch, c2l_scale_type='urbanf', l2g_scale_type='ice') + + call hist_addfld2d (fname='QROOTSINK', units='mm/s', type2d='levsoi', & + avgflag='A', long_name='water flux from soil to root in each soil-layer', & + ptr_col=this%qflx_rootsoi_col, set_spec=spval, l2g_scale_type='veg', default='inactive') this%qflx_evap_can_patch(begp:endp) = spval call hist_addfld1d (fname='QVEGE', units='mm/s', & @@ -424,18 +438,23 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='canopy transpiration', & ptr_patch=this%qflx_tran_veg_patch, set_lake=0._r8, c2l_scale_type='urbanf') + this%qflx_ev_snow_patch(begp:endp) = spval + call hist_addfld1d (fname='QSNOEVAP', units='mm/s', & + avgflag='A', long_name='evaporation from snow', & + ptr_patch=this%qflx_tran_veg_patch, set_lake=0._r8, c2l_scale_type='urbanf') + this%qflx_snowindunload_patch(begp:endp) = spval - call hist_addfld1d (fname='QSNOWINDUNLOAD', units='mm/s', & + call hist_addfld1d (fname='QSNO_WINDUNLOAD', units='mm/s', & avgflag='A', long_name='canopy snow wind unloading', & ptr_patch=this%qflx_snowindunload_patch, set_lake=0._r8, c2l_scale_type='urbanf') this%qflx_snotempunload_patch(begp:endp) = spval - call hist_addfld1d (fname='QSNOTEMPUNLOAD', units='mm/s', & + call hist_addfld1d (fname='QSNO_TEMPUNLOAD', units='mm/s', & avgflag='A', long_name='canopy snow temp unloading', & ptr_patch=this%qflx_snotempunload_patch, set_lake=0._r8, c2l_scale_type='urbanf') this%qflx_snwcp_liq_col(begc:endc) = spval - call hist_addfld1d (fname='QSNWCPLIQ', units='mm H2O/s', & + call hist_addfld1d (fname='QSNOCPLIQ', units='mm H2O/s', & avgflag='A', long_name='excess liquid h2o due to snow capping not including correction for land use change', & ptr_col=this%qflx_snwcp_liq_col, c2l_scale_type='urbanf') @@ -444,61 +463,45 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='excess solid h2o due to snow capping not including correction for land use change', & ptr_col=this%qflx_snwcp_ice_col, c2l_scale_type='urbanf') - if (use_cn) then - this%qflx_rain_grnd_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_RAIN_GRND', units='mm H2O/s', & - avgflag='A', long_name='rain on ground after interception', & - ptr_patch=this%qflx_rain_grnd_patch, default='inactive', c2l_scale_type='urbanf') - end if - - if (use_cn) then - this%qflx_snow_grnd_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_SNOW_GRND', units='mm H2O/s', & - avgflag='A', long_name='snow on ground after interception', & - ptr_patch=this%qflx_snow_grnd_patch, default='inactive', c2l_scale_type='urbanf') - end if - - if (use_cn) then - this%qflx_evap_grnd_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_EVAP_GRND', units='mm H2O/s', & - avgflag='A', long_name='ground surface evaporation', & - ptr_patch=this%qflx_evap_grnd_patch, default='inactive', c2l_scale_type='urbanf') - end if - - if (use_cn) then - this%qflx_evap_veg_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_EVAP_VEG', units='mm H2O/s', & - avgflag='A', long_name='vegetation evaporation', & - ptr_patch=this%qflx_evap_veg_patch, default='inactive', c2l_scale_type='urbanf') - end if - - if (use_cn) then - this%qflx_evap_tot_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_EVAP_TOT', units='mm H2O/s', & - avgflag='A', long_name='qflx_evap_soi + qflx_evap_can + qflx_tran_veg', & - ptr_patch=this%qflx_evap_tot_patch, default='inactive', c2l_scale_type='urbanf') - end if - - if (use_cn) then - this%qflx_dew_grnd_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_DEW_GRND', units='mm H2O/s', & - avgflag='A', long_name='ground surface dew formation', & - ptr_patch=this%qflx_dew_grnd_patch, default='inactive', c2l_scale_type='urbanf') - end if - - if (use_cn) then - this%qflx_sub_snow_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_SUB_SNOW', units='mm H2O/s', & - avgflag='A', long_name='sublimation rate from snow pack', & - ptr_patch=this%qflx_sub_snow_patch, default='inactive', c2l_scale_type='urbanf') - end if - - if (use_cn) then - this%qflx_dew_snow_patch(begp:endp) = spval - call hist_addfld1d (fname='QFLX_DEW_SNOW', units='mm H2O/s', & - avgflag='A', long_name='surface dew added to snow pacK', & - ptr_patch=this%qflx_dew_snow_patch, default='inactive', c2l_scale_type='urbanf') - end if + this%qflx_rain_grnd_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_RAIN_GRND', units='mm H2O/s', & + avgflag='A', long_name='rain on ground after interception', & + ptr_patch=this%qflx_rain_grnd_patch, default='inactive', c2l_scale_type='urbanf') + + this%qflx_snow_grnd_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_SNOW_GRND', units='mm H2O/s', & + avgflag='A', long_name='snow on ground after interception', & + ptr_patch=this%qflx_snow_grnd_patch, default='inactive', c2l_scale_type='urbanf') + + this%qflx_evap_grnd_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_EVAP_GRND', units='mm H2O/s', & + avgflag='A', long_name='ground surface evaporation', & + ptr_patch=this%qflx_evap_grnd_patch, default='inactive', c2l_scale_type='urbanf') + + this%qflx_evap_veg_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_EVAP_VEG', units='mm H2O/s', & + avgflag='A', long_name='vegetation evaporation', & + ptr_patch=this%qflx_evap_veg_patch, default='inactive', c2l_scale_type='urbanf') + + this%qflx_evap_tot_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_EVAP_TOT', units='mm H2O/s', & + avgflag='A', long_name='qflx_evap_soi + qflx_evap_can + qflx_tran_veg', & + ptr_patch=this%qflx_evap_tot_patch, c2l_scale_type='urbanf') + + this%qflx_dew_grnd_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_DEW_GRND', units='mm H2O/s', & + avgflag='A', long_name='ground surface dew formation', & + ptr_patch=this%qflx_dew_grnd_patch, c2l_scale_type='urbanf') + + this%qflx_sub_snow_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_SUB_SNOW', units='mm H2O/s', & + avgflag='A', long_name='sublimation rate from snow pack', & + ptr_patch=this%qflx_sub_snow_patch, c2l_scale_type='urbanf') + + this%qflx_dew_snow_patch(begp:endp) = spval + call hist_addfld1d (fname='QFLX_DEW_SNOW', units='mm H2O/s', & + avgflag='A', long_name='surface dew added to snow pacK', & + ptr_patch=this%qflx_dew_snow_patch, c2l_scale_type='urbanf') this%qflx_h2osfc_surf_col(begc:endc) = spval call hist_addfld1d (fname='QH2OSFC', units='mm/s', & diff --git a/src/biogeophys/test/CMakeLists.txt b/src/biogeophys/test/CMakeLists.txt index 94bc536d1e..75b77d5391 100644 --- a/src/biogeophys/test/CMakeLists.txt +++ b/src/biogeophys/test/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(Daylength_test) add_subdirectory(Irrigation_test) add_subdirectory(HumanStress_test) -add_subdirectory(SnowHydrology_test) \ No newline at end of file +add_subdirectory(SnowHydrology_test) +add_subdirectory(TotalWaterAndHeat_test) diff --git a/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt b/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt index 8274c49ee7..cfd1e3a4bb 100644 --- a/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt +++ b/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt @@ -1,6 +1,7 @@ set (pfunit_sources test_SnowHydrology_initSnowLayers.pf - test_SnowHydrology_newSnowBulkDensity.pf) + test_SnowHydrology_newSnowBulkDensity.pf + test_SnowHydrology_SnowCappingExcess.pf) create_pFUnit_test(SnowHydrology test_SnowHydrology_exe "${pfunit_sources}" "") diff --git a/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_SnowCappingExcess.pf b/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_SnowCappingExcess.pf new file mode 100644 index 0000000000..7c67a69c9a --- /dev/null +++ b/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_SnowCappingExcess.pf @@ -0,0 +1,230 @@ +module test_SnowHydrology_SnowCappingExcess + + ! Tests of SnowHydrologyMod: SnowCappingExcess + + use pfunit_mod + use SnowHydrologyMod + use TopoMod, only : topo_type + use shr_kind_mod , only : r8 => shr_kind_r8 + use unittestSubgridMod + use unittestSimpleSubgridSetupsMod + use unittestFilterBuilderMod + use unittestTimeManagerMod + use unittestArrayMod, only : col_array + use clm_varcon, only : h2osno_max + use clm_varpar, only : nlevsno + use landunit_varcon, only : istsoil, istice_mec + + implicit none + + @TestCase + type, extends(TestCase) :: TestSCE + contains + procedure :: setUp + procedure :: tearDown + end type TestSCE + + real(r8), parameter :: tol = 1.e-13_r8 + + ! Make sure the h2osno_max value is substantially larger than the reset_snow_h2osno + ! value, so that tests make sense. + real(r8), parameter :: my_h2osno_max = reset_snow_h2osno + 1000._r8 + +contains + + subroutine setUp(this) + class(TestSCE), intent(inout) :: this + h2osno_max = my_h2osno_max + call SnowHydrologySetControlForTesting( & + set_reset_snow = .false., & + set_reset_snow_glc = .false., & + set_reset_snow_glc_ela = 1.e9_r8) + call unittest_timemgr_setup() + end subroutine setUp + + subroutine tearDown(this) + class(TestSCE), intent(inout) :: this + call unittest_subgrid_teardown() + call unittest_timemgr_teardown() + end subroutine tearDown + + @Test + subroutine SnowCappingExcess_OneExceeds(this) + ! Test with one column that exceeds the max, two that don't + class(TestSCE), intent(inout) :: this + real(r8) :: h2osno(3) + real(r8), parameter :: my_excess = 1._r8 + real(r8) :: h2osno_excess(3) + logical :: apply_runoff(3) + integer :: num_snowc + integer, allocatable :: filter_snowc(:) + + call setup_landunit_ncols(ltype=istsoil, ctypes=[1,1,1], cweights=[0.5_r8, 0.25_r8, 0.25_r8]) + call filter_from_range(bounds%begc, bounds%endc, num_snowc, filter_snowc) + ! Column 2 exceeds the max, other columns don't + h2osno = [h2osno_max - 1._r8, h2osno_max + my_excess, h2osno_max - 1._r8] + + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno=h2osno, topo=col_array(0._r8), & + h2osno_excess=h2osno_excess, apply_runoff=apply_runoff) + + @assertEqual([0._r8, my_excess, 0._r8], h2osno_excess, tolerance=tol) + @assertTrue(apply_runoff(2)) + end subroutine SnowCappingExcess_OneExceeds + + @Test + subroutine SnowCappingExcess_ResetNonGlacier(this) + ! With reset_snow = .true., should reset non-glacier points + class(TestSCE), intent(inout) :: this + real(r8) :: h2osno(3) + real(r8), parameter :: my_excess = 1._r8 + real(r8) :: h2osno_excess(3) + logical :: apply_runoff(3) + integer :: num_snowc + integer, allocatable :: filter_snowc(:) + + call SnowHydrologySetControlForTesting(set_reset_snow = .true.) + call setup_landunit_ncols(ltype=istsoil, ctypes=[1,1,1], cweights=[0.5_r8, 0.25_r8, 0.25_r8]) + call filter_from_range(bounds%begc, bounds%endc, num_snowc, filter_snowc) + ! Column 2 exceeds the max, other columns don't + h2osno = [reset_snow_h2osno - 1._r8, reset_snow_h2osno + my_excess, reset_snow_h2osno - 1._r8] + + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno=h2osno, topo=col_array(0._r8), & + h2osno_excess=h2osno_excess, apply_runoff=apply_runoff) + + @assertEqual([0._r8, my_excess, 0._r8], h2osno_excess, tolerance=tol) + @assertFalse(apply_runoff(2)) + end subroutine SnowCappingExcess_ResetNonGlacier + + @Test + subroutine SnowCappingExcess_DoNotResetGlacier(this) + ! With reset_snow = .true. but reset_snow_glc = .false., should not reset glacier + class(TestSCE), intent(inout) :: this + real(r8) :: h2osno(3) + real(r8), parameter :: my_excess = 1._r8 + real(r8) :: h2osno_excess(3) + logical :: apply_runoff(3) + integer :: num_snowc + integer, allocatable :: filter_snowc(:) + + call SnowHydrologySetControlForTesting(set_reset_snow = .true., & + set_reset_snow_glc = .false., set_reset_snow_glc_ela = 1000._r8) + call setup_landunit_ncols(ltype=istice_mec, ctypes=[1,1,1], cweights=[0.5_r8, 0.25_r8, 0.25_r8]) + call filter_from_range(bounds%begc, bounds%endc, num_snowc, filter_snowc) + ! Column 2 exceeds the max, other columns don't + h2osno = [reset_snow_h2osno - 1._r8, reset_snow_h2osno + my_excess, reset_snow_h2osno - 1._r8] + + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno=h2osno, topo=col_array(0._r8), & + h2osno_excess=h2osno_excess, apply_runoff=apply_runoff) + + @assertEqual([0._r8, 0._r8, 0._r8], h2osno_excess, tolerance=tol) + end subroutine SnowCappingExcess_DoNotResetGlacier + + @Test + subroutine SnowCappingExcess_ResetLowGlacier(this) + ! With reset_snow_glc = .true., should reset low glacier points + class(TestSCE), intent(inout) :: this + real(r8) :: h2osno(3) + real(r8), parameter :: my_excess = 1._r8 + real(r8), parameter :: ela = 1000._r8 + real(r8) :: h2osno_excess(3) + logical :: apply_runoff(3) + integer :: num_snowc + integer, allocatable :: filter_snowc(:) + + call SnowHydrologySetControlForTesting(set_reset_snow_glc = .true., & + set_reset_snow_glc_ela = ela) + call setup_landunit_ncols(ltype=istice_mec, ctypes=[1,1,1], cweights=[0.5_r8, 0.25_r8, 0.25_r8]) + call filter_from_range(bounds%begc, bounds%endc, num_snowc, filter_snowc) + ! Column 2 exceeds the max, other columns don't + h2osno = [reset_snow_h2osno - 1._r8, reset_snow_h2osno + my_excess, reset_snow_h2osno - 1._r8] + + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno=h2osno, topo=col_array(ela - 1._r8), & + h2osno_excess=h2osno_excess, apply_runoff=apply_runoff) + + @assertEqual([0._r8, my_excess, 0._r8], h2osno_excess, tolerance=tol) + @assertFalse(apply_runoff(2)) + end subroutine SnowCappingExcess_ResetLowGlacier + + @Test + subroutine SnowCappingExcess_DoNotResetHighGlacier(this) + ! With reset_snow_glc = .true., should not reset high glacier points + class(TestSCE), intent(inout) :: this + real(r8) :: h2osno(3) + real(r8), parameter :: my_excess = 1._r8 + real(r8), parameter :: ela = 1000._r8 + real(r8) :: h2osno_excess(3) + logical :: apply_runoff(3) + integer :: num_snowc + integer, allocatable :: filter_snowc(:) + + call SnowHydrologySetControlForTesting(set_reset_snow_glc = .true., & + set_reset_snow_glc_ela = ela) + call setup_landunit_ncols(ltype=istice_mec, ctypes=[1,1,1], cweights=[0.5_r8, 0.25_r8, 0.25_r8]) + call filter_from_range(bounds%begc, bounds%endc, num_snowc, filter_snowc) + ! Column 2 exceeds the max, other columns don't + h2osno = [reset_snow_h2osno - 1._r8, reset_snow_h2osno + my_excess, reset_snow_h2osno - 1._r8] + + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno=h2osno, topo=col_array(ela + 1._r8), & + h2osno_excess=h2osno_excess, apply_runoff=apply_runoff) + + @assertEqual([0._r8, 0._r8, 0._r8], h2osno_excess, tolerance=tol) + end subroutine SnowCappingExcess_DoNotResetHighGlacier + + @Test + subroutine SnowCappingExcess_DoNotResetNonGlacier(this) + ! With reset_snow_glc = .true. but reset_snow = .false., should not reset non-glacier + class(TestSCE), intent(inout) :: this + real(r8) :: h2osno(3) + real(r8), parameter :: my_excess = 1._r8 + real(r8) :: h2osno_excess(3) + logical :: apply_runoff(3) + integer :: num_snowc + integer, allocatable :: filter_snowc(:) + + call SnowHydrologySetControlForTesting(set_reset_snow = .false., & + set_reset_snow_glc = .true., set_reset_snow_glc_ela = 1000._r8) + call setup_landunit_ncols(ltype=istsoil, ctypes=[1,1,1], cweights=[0.5_r8, 0.25_r8, 0.25_r8]) + call filter_from_range(bounds%begc, bounds%endc, num_snowc, filter_snowc) + ! Column 2 exceeds the max, other columns don't + h2osno = [reset_snow_h2osno - 1._r8, reset_snow_h2osno + my_excess, reset_snow_h2osno - 1._r8] + + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno=h2osno, topo=col_array(0._r8), & + h2osno_excess=h2osno_excess, apply_runoff=apply_runoff) + + @assertEqual([0._r8, 0._r8, 0._r8], h2osno_excess, tolerance=tol) + end subroutine SnowCappingExcess_DoNotResetNonGlacier + + @Test + subroutine SnowCappingExcess_DoNotResetLater(this) + ! Make sure resetting doesn't happen after the given number of time steps + class(TestSCE), intent(inout) :: this + real(r8) :: h2osno(3) + real(r8), parameter :: my_excess = 1._r8 + real(r8) :: h2osno_excess(3) + logical :: apply_runoff(3) + integer :: num_snowc + integer :: nstep + integer, allocatable :: filter_snowc(:) + + call SnowHydrologySetControlForTesting(set_reset_snow = .true.) + call setup_landunit_ncols(ltype=istsoil, ctypes=[1,1,1], cweights=[0.5_r8, 0.25_r8, 0.25_r8]) + call filter_from_range(bounds%begc, bounds%endc, num_snowc, filter_snowc) + ! Column 2 exceeds the max, other columns don't + h2osno = [reset_snow_h2osno - 1._r8, reset_snow_h2osno + my_excess, reset_snow_h2osno - 1._r8] + nstep = nlevsno * reset_snow_timesteps_per_layer + 1 + call unittest_timemgr_set_nstep(nstep) + + call SnowCappingExcess(bounds, num_snowc, filter_snowc, & + h2osno=h2osno, topo=col_array(0._r8), & + h2osno_excess=h2osno_excess, apply_runoff=apply_runoff) + + @assertEqual([0._r8, 0._r8, 0._r8], h2osno_excess, tolerance=tol) + end subroutine SnowCappingExcess_DoNotResetLater + +end module test_SnowHydrology_SnowCappingExcess diff --git a/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_newSnowBulkDensity.pf b/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_newSnowBulkDensity.pf index ae7cc09c23..db8c7ba980 100644 --- a/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_newSnowBulkDensity.pf +++ b/src/biogeophys/test/SnowHydrology_test/test_SnowHydrology_newSnowBulkDensity.pf @@ -49,7 +49,8 @@ contains this%MINSNOWDENSITY = 50.0_r8 this%MAXSNOWDENSITY = 170.0_r8 this%MAXWINDEDSNOWDENSITY = 270.0_r8 - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., set_new_snow_density=1 ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=LoTmpDnsTruncatedAnderson1976 ) end subroutine setUp subroutine tearDown(this) @@ -68,7 +69,8 @@ contains class(TestSnowHydrology), intent(inout) :: this real(r8) :: minsnowdensity - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., set_new_snow_density=1 ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=LoTmpDnsTruncatedAnderson1976 ) this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = this%NEG15C - epsilon(this%NEG15C) call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) write(*,*) 'forc_t = ', this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) @@ -93,14 +95,15 @@ contains class(TestSnowHydrology), intent(inout) :: this real(r8) :: minsnowdensity - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., set_new_snow_density=2 ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=LoTmpDnsSlater2017 ) this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = this%NEG15C - epsilon(this%NEG15C) call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) @assertLessThanOrEqual( this%MINSNOWDENSITY, this%bifall(bounds%begc), message="at -15C SlaterDensity" ) minsnowdensity = this%bifall(bounds%begc) - ! Test that above 2C stays at the same value + ! Test that from -15 to -100, stays within bounds do while( this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) > (tfrz - 100.0_r8) ) this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) - 0.1_r8 call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) @@ -110,6 +113,37 @@ contains end subroutine newSnowBulkDensity_neg15_SlaterDensity + @Test + subroutine newSnowBulkDensity_lowT_SlaterDensity(this) + ! Test the input for very low temperatures: density should be no lower than at higher + ! temperatures + class(TestSnowHydrology), intent(inout) :: this + real(r8) :: density_at_neg_57_c(1) + + ! Setup + + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=LoTmpDnsSlater2017 ) + + ! Get density at -57 C. This is close to the highest density for the cold-temperature + ! regime. + this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = tfrz - 57._r8 + call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, density_at_neg_57_c) + + ! Exercise: Get density at very cold temperature: just above absolute zero + this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = 0.1_r8 + call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) + + ! Make sure that (1) density at -57 C is greater than minsnowdensity, and (2) density + ! at really cold T is greater than or equal to than density at -57 C (which is close + ! to the maximum snow density for the cold-temperature regime). + @assertLessThan(this%MINSNOWDENSITY, density_at_neg_57_c(1), message="density at -57C > min") + @assertLessThanOrEqual(density_at_neg_57_c(1), this%bifall(bounds%begc), message="density at very cold > density at -57C") + + end subroutine newSnowBulkDensity_lowT_SlaterDensity + + + @Test subroutine checkWindDependentDensity(this) ! Test the range of the wind denpendent density @@ -117,11 +151,13 @@ contains real(r8) :: base_density, last_density, diff this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = (this%NEG15C + this%TWOC)*0.5 - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., set_new_snow_density=1 ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=LoTmpDnsTruncatedAnderson1976 ) this%atm2lnd_inst%forc_wind_grc(bounds%begg) = 0.0_r8 call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) base_density = this%bifall(bounds%begc) - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.true., set_new_snow_density=1 ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.true., & + set_new_snow_density=LoTmpDnsTruncatedAnderson1976 ) call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) @assertEqual( base_density, this%bifall(bounds%begc), tolerance=1.0e-12_r8, message="Expect no change with zero wind" ) write(*,*) 'without wind-depend = ', base_density, ' with wind@0=', this%bifall(bounds%begc) @@ -163,7 +199,8 @@ contains integer :: density_type do density_type = 1, 2 - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., set_new_snow_density=density_type ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=density_type ) write(*,*) 'snow density type = ', density_type this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = this%TWOC + epsilon(this%TWOC) call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) @@ -188,7 +225,8 @@ contains integer :: density_type do density_type = 1, 2 - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., set_new_snow_density=density_type ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=density_type ) write(*,*) 'snow density type = ', density_type this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc) = this%TWOC + epsilon(this%TWOC) call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) @@ -208,7 +246,8 @@ contains lastsnowdensity = this%bifall(bounds%begc) ! Check that both density types give same answers if ( density_type == 1 ) then - call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., set_new_snow_density=2 ) + call SnowHydrologySetControlForTesting( set_winddep_snowdensity=.false., & + set_new_snow_density=LoTmpDnsSlater2017 ) call NewSnowBulkDensity(bounds, this%numf, this%filter, this%atm2lnd_inst, this%bifall) @assertEqual( this%bifall(bounds%begc), lastsnowdensity, message="Density methods same for mid temps" ) end if diff --git a/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt b/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt new file mode 100644 index 0000000000..67f2a4812e --- /dev/null +++ b/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt @@ -0,0 +1,12 @@ +set (pfunit_sources + test_total_water_and_heat.pf) + +# extra sources used for this test, which are not .pf files +# (currently none) +set (extra_sources + ) + +create_pFUnit_test(total_water_and_heat test_total_water_and_heat_exe + "${pfunit_sources}" "${extra_sources}") + +target_link_libraries(test_total_water_and_heat_exe clm csm_share esmf_wrf_timemgr) \ No newline at end of file diff --git a/src/biogeophys/test/TotalWaterAndHeat_test/test_total_water_and_heat.pf b/src/biogeophys/test/TotalWaterAndHeat_test/test_total_water_and_heat.pf new file mode 100644 index 0000000000..d135cb40bc --- /dev/null +++ b/src/biogeophys/test/TotalWaterAndHeat_test/test_total_water_and_heat.pf @@ -0,0 +1,189 @@ +module test_total_water_and_heat + + ! Tests of TotalWaterAndHeatMod + + use pfunit_mod + use TotalWaterAndHeatMod + use shr_kind_mod , only : r8 => shr_kind_r8 + use unittestSubgridMod + use unittestSimpleSubgridSetupsMod + use clm_varcon, only : tfrz, cpliq, hfus + + implicit none + + @TestCase + type, extends(TestCase) :: TestTWAH + contains + procedure :: setUp + procedure :: tearDown + end type TestTWAH + + real(r8), parameter :: tol = 1.e-13_r8 + real(r8), parameter :: irrelevant_temp = tfrz + 9999._r8 + +contains + + subroutine setUp(this) + class(TestTWAH), intent(inout) :: this + end subroutine setUp + + subroutine tearDown(this) + class(TestTWAH), intent(inout) :: this + + if (unittest_subgrid_needs_teardown) then + call unittest_subgrid_teardown() + end if + end subroutine tearDown + + ! ------------------------------------------------------------------------ + ! Tests of LiquidWaterHeat + ! ------------------------------------------------------------------------ + + @Test + subroutine LiquidWaterHeatBasic(this) + class(TestTWAH), intent(inout) :: this + real(r8), parameter :: h2o = 3._r8 + real(r8), parameter :: temp_above_base = 4._r8 + real(r8), parameter :: temp = heat_base_temp + temp_above_base + real(r8) :: heat + real(r8) :: expected_heat, expected_latent_heat, expected_total + + heat = LiquidWaterHeat(temp = temp, h2o = h2o) + expected_latent_heat = h2o * hfus + expected_heat = h2o * cpliq * temp_above_base + expected_total = expected_latent_heat + expected_heat + + @assertEqual(expected_total, heat, tolerance=tol) + end subroutine LiquidWaterHeatBasic + + ! ------------------------------------------------------------------------ + ! Tests of AdjustDeltaHeatForDeltaLiq + ! ------------------------------------------------------------------------ + + @Test + subroutine AdjustDeltaHeatNoDeltaLiq(this) + class(TestTWAH), intent(inout) :: this + real(r8) :: delta_heat(1) + real(r8), parameter :: delta_liq = 0._r8 + real(r8), parameter :: delta_heat_init = 17._r8 + + call setup_single_veg_patch(pft_type = 1) + + delta_heat(1) = delta_heat_init + + call AdjustDeltaHeatForDeltaLiq(bounds, [delta_liq], & + [irrelevant_temp], [irrelevant_temp], & + delta_heat) + + @assertEqual(delta_heat(1), delta_heat_init) + end subroutine AdjustDeltaHeatNoDeltaLiq + + @Test + subroutine AdjustDeltaHeatNegativeDeltaLiq(this) + class(TestTWAH), intent(inout) :: this + real(r8) :: delta_heat(1) + real(r8) :: heat_diff + real(r8) :: expected_total_heat + real(r8), parameter :: liquid_water_temp1 = tfrz + 3._r8 + real(r8), parameter :: delta_heat_init = 17._r8 + real(r8), parameter :: delta_liq = -2._r8 + + call setup_single_veg_patch(pft_type = 1) + + delta_heat(1) = delta_heat_init + + call AdjustDeltaHeatForDeltaLiq(bounds, [delta_liq], & + [liquid_water_temp1], [irrelevant_temp], & + delta_heat) + heat_diff = delta_heat(1) - delta_heat_init + + expected_total_heat = LiquidWaterHeat( & + temp = liquid_water_temp1, & + h2o = -delta_liq) + + @assertLessThan(0._r8, heat_diff) + @assertEqual(expected_total_heat, heat_diff, tolerance=tol) + + end subroutine AdjustDeltaHeatNegativeDeltaLiq + + @Test + subroutine AdjustDeltaHeatPositiveDeltaLiq(this) + class(TestTWAH), intent(inout) :: this + real(r8) :: delta_heat(1) + real(r8) :: heat_diff + real(r8) :: expected_total_heat + real(r8), parameter :: liquid_water_temp2 = tfrz + 3._r8 + real(r8), parameter :: delta_heat_init = 17._r8 + real(r8), parameter :: delta_liq = 2._r8 + + call setup_single_veg_patch(pft_type = 1) + + delta_heat(1) = delta_heat_init + + call AdjustDeltaHeatForDeltaLiq(bounds, [delta_liq], & + [irrelevant_temp], [liquid_water_temp2], & + delta_heat) + heat_diff = delta_heat(1) - delta_heat_init + + expected_total_heat = LiquidWaterHeat( & + temp = liquid_water_temp2, & + h2o = -delta_liq) + + @assertGreaterThan(0._r8, heat_diff) + @assertEqual(expected_total_heat, heat_diff, tolerance=tol) + + end subroutine AdjustDeltaHeatPositiveDeltaLiq + + @Test + subroutine AdjustDeltaHeatVeryColdTemperature(this) + class(TestTWAH), intent(inout) :: this + real(r8) :: delta_heat(1) + real(r8) :: heat_diff + real(r8) :: expected_total_heat + real(r8), parameter :: liquid_water_temp2 = DeltaLiqMinTemp - 1._r8 + real(r8), parameter :: delta_heat_init = 17._r8 + real(r8), parameter :: delta_liq = 2._r8 + + call setup_single_veg_patch(pft_type = 1) + + delta_heat(1) = delta_heat_init + + call AdjustDeltaHeatForDeltaLiq(bounds, [delta_liq], & + [irrelevant_temp], [liquid_water_temp2], & + delta_heat) + heat_diff = delta_heat(1) - delta_heat_init + + expected_total_heat = LiquidWaterHeat( & + temp = DeltaLiqMinTemp, & + h2o = -delta_liq) + + @assertEqual(expected_total_heat, heat_diff, tolerance=tol) + end subroutine AdjustDeltaHeatVeryColdTemperature + + @Test + subroutine AdjustDeltaHeatVeryHotTemperature(this) + class(TestTWAH), intent(inout) :: this + real(r8) :: delta_heat(1) + real(r8) :: heat_diff + real(r8) :: expected_total_heat + real(r8), parameter :: liquid_water_temp2 = DeltaLiqMaxTemp + 1._r8 + real(r8), parameter :: delta_heat_init = 17._r8 + real(r8), parameter :: delta_liq = 2._r8 + + call setup_single_veg_patch(pft_type = 1) + + delta_heat(1) = delta_heat_init + + call AdjustDeltaHeatForDeltaLiq(bounds, [delta_liq], & + [irrelevant_temp], [liquid_water_temp2], & + delta_heat) + heat_diff = delta_heat(1) - delta_heat_init + + expected_total_heat = LiquidWaterHeat( & + temp = DeltaLiqMaxTemp, & + h2o = -delta_liq) + + @assertEqual(expected_total_heat, heat_diff, tolerance=tol) + end subroutine AdjustDeltaHeatVeryHotTemperature + +end module test_total_water_and_heat diff --git a/src/cpl/clm_cpl_indices.F90 b/src/cpl/clm_cpl_indices.F90 index e8f366856f..525b709cc6 100644 --- a/src/cpl/clm_cpl_indices.F90 +++ b/src/cpl/clm_cpl_indices.F90 @@ -104,6 +104,9 @@ module clm_cpl_indices integer, public ::index_x2l_Faxa_dstdry3 ! flux: Size 3 dust -- dry deposition integer, public ::index_x2l_Faxa_dstdry4 ! flux: Size 4 dust -- dry deposition + integer, public ::index_x2l_Faxa_nhx ! flux nhx from atm + integer, public ::index_x2l_Faxa_noy ! flux noy from atm + integer, public ::index_x2l_Flrr_flood ! rtm->lnd rof flood flux integer, public ::index_x2l_Flrr_volr ! rtm->lnd rof volr total volume integer, public ::index_x2l_Flrr_volrmch ! rtm->lnd rof volr main channel volume @@ -136,7 +139,7 @@ subroutine clm_cpl_indices_set( ) use seq_drydep_mod , only: drydep_fields_token, lnd_drydep use shr_megan_mod , only: shr_megan_fields_token, shr_megan_mechcomps_n use shr_fire_emis_mod,only: shr_fire_emis_fields_token, shr_fire_emis_ztop_token, shr_fire_emis_mechcomps_n - use clm_varctl , only: use_voc + use clm_varctl , only: ndep_from_cpl use glc_elevclass_mod, only: glc_get_num_elevation_classes, glc_elevclass_as_string ! ! !ARGUMENTS: @@ -210,9 +213,7 @@ subroutine clm_cpl_indices_set( ) index_l2x_Fall_methane = mct_avect_indexra(l2x,'Fall_methane',perrWith='quiet') ! MEGAN fluxes - ! use_voc is a temporary logic to enable turning off MEGAN fluxes when prognostic crop - ! is used - if (shr_megan_mechcomps_n>0 .and. use_voc) then + if (shr_megan_mechcomps_n>0) then index_l2x_Fall_flxvoc = mct_avect_indexra(l2x,trim(shr_megan_fields_token)) else index_l2x_Fall_flxvoc = 0 @@ -271,6 +272,13 @@ subroutine clm_cpl_indices_set( ) index_x2l_Faxa_dstwet3 = mct_avect_indexra(x2l,'Faxa_dstwet3') index_x2l_Faxa_dstwet4 = mct_avect_indexra(x2l,'Faxa_dstwet4') + index_x2l_Faxa_nhx = mct_avect_indexra(x2l,'Faxa_nhx', perrWith='quiet') + index_x2l_Faxa_noy = mct_avect_indexra(x2l,'Faxa_noy', perrWith='quiet') + + if (index_x2l_Faxa_nhx > 0 .and. index_x2l_Faxa_noy > 0) then + ndep_from_cpl = .true. + end if + index_x2l_Flrr_flood = mct_avect_indexra(x2l,'Flrr_flood') !------------------------------------------------------------- @@ -281,37 +289,37 @@ subroutine clm_cpl_indices_set( ) index_x2l_Sg_icemask_coupled_fluxes = mct_avect_indexra(x2l,'Sg_icemask_coupled_fluxes') glc_nec = glc_get_num_elevation_classes() - - ! If glc_nec > 0, then create coupling fields for all glc elevation classes - ! (1:glc_nec) plus bare land (index 0). Note that, if glc_nec = 0, then we don't even - ! need the bare land (0) index. - if (glc_nec > 0) then - allocate(index_l2x_Sl_tsrf(0:glc_nec)) - allocate(index_l2x_Sl_topo(0:glc_nec)) - allocate(index_l2x_Flgl_qice(0:glc_nec)) - allocate(index_x2l_Sg_ice_covered(0:glc_nec)) - allocate(index_x2l_Sg_topo(0:glc_nec)) - allocate(index_x2l_Flgg_hflx(0:glc_nec)) - - do num = 0,glc_nec - nec_str = glc_elevclass_as_string(num) - - name = 'Sg_ice_covered' // nec_str - index_x2l_Sg_ice_covered(num) = mct_avect_indexra(x2l,trim(name)) - name = 'Sg_topo' // nec_str - index_x2l_Sg_topo(num) = mct_avect_indexra(x2l,trim(name)) - name = 'Flgg_hflx' // nec_str - index_x2l_Flgg_hflx(num) = mct_avect_indexra(x2l,trim(name)) - - name = 'Sl_tsrf' // nec_str - index_l2x_Sl_tsrf(num) = mct_avect_indexra(l2x,trim(name)) - name = 'Sl_topo' // nec_str - index_l2x_Sl_topo(num) = mct_avect_indexra(l2x,trim(name)) - name = 'Flgl_qice' // nec_str - index_l2x_Flgl_qice(num) = mct_avect_indexra(l2x,trim(name)) - end do + if (glc_nec < 1) then + call shr_sys_abort('ERROR: In CLM4.5 and later, glc_nec must be at least 1.') end if + ! Create coupling fields for all glc elevation classes (1:glc_nec) plus bare land + ! (index 0). + allocate(index_l2x_Sl_tsrf(0:glc_nec)) + allocate(index_l2x_Sl_topo(0:glc_nec)) + allocate(index_l2x_Flgl_qice(0:glc_nec)) + allocate(index_x2l_Sg_ice_covered(0:glc_nec)) + allocate(index_x2l_Sg_topo(0:glc_nec)) + allocate(index_x2l_Flgg_hflx(0:glc_nec)) + + do num = 0,glc_nec + nec_str = glc_elevclass_as_string(num) + + name = 'Sg_ice_covered' // nec_str + index_x2l_Sg_ice_covered(num) = mct_avect_indexra(x2l,trim(name)) + name = 'Sg_topo' // nec_str + index_x2l_Sg_topo(num) = mct_avect_indexra(x2l,trim(name)) + name = 'Flgg_hflx' // nec_str + index_x2l_Flgg_hflx(num) = mct_avect_indexra(x2l,trim(name)) + + name = 'Sl_tsrf' // nec_str + index_l2x_Sl_tsrf(num) = mct_avect_indexra(l2x,trim(name)) + name = 'Sl_topo' // nec_str + index_l2x_Sl_topo(num) = mct_avect_indexra(l2x,trim(name)) + name = 'Flgl_qice' // nec_str + index_l2x_Flgl_qice(num) = mct_avect_indexra(l2x,trim(name)) + end do + call mct_aVect_clean(x2l) call mct_aVect_clean(l2x) diff --git a/src/cpl/lnd_comp_mct.F90 b/src/cpl/lnd_comp_mct.F90 index 53d07c444f..383cb26f4c 100644 --- a/src/cpl/lnd_comp_mct.F90 +++ b/src/cpl/lnd_comp_mct.F90 @@ -329,6 +329,7 @@ subroutine lnd_run_mct(EClock, cdata_l, x2l_l, l2x_l) logical :: dosend ! true => send data back to driver logical :: doalb ! .true. ==> do albedo calculation on this time step logical :: rof_prognostic ! .true. => running with a prognostic ROF model + logical :: glc_present ! .true. => running with a non-stub GLC model real(r8) :: nextsw_cday ! calday from clock of next radiation computation real(r8) :: caldayp1 ! clm calday plus dtime offset integer :: shrlogunit,shrloglev ! old values for share log unit and log level @@ -377,6 +378,14 @@ subroutine lnd_run_mct(EClock, cdata_l, x2l_l, l2x_l) nlend_sync = seq_timemgr_StopAlarmIsOn( EClock ) rstwr_sync = seq_timemgr_RestartAlarmIsOn( EClock ) + ! Determine if we're running with a prognostic ROF model, and if we're running with a + ! non-stub GLC model. These won't change throughout the run, but we can't count on + ! their being set in initialization, so need to get them in the run method. + + call seq_infodata_GetData( infodata, & + rof_prognostic=rof_prognostic, & + glc_present=glc_present) + ! Map MCT to land data type ! Perform downscaling if appropriate @@ -384,7 +393,11 @@ subroutine lnd_run_mct(EClock, cdata_l, x2l_l, l2x_l) ! Map to clm (only when state and/or fluxes need to be updated) call t_startf ('lc_lnd_import') - call lnd_import( bounds, x2l_l%rattr, atm2lnd_inst, glc2lnd_inst ) + call lnd_import( bounds, & + x2l = x2l_l%rattr, & + glc_present = glc_present, & + atm2lnd_inst = atm2lnd_inst, & + glc2lnd_inst = glc2lnd_inst) call t_stopf ('lc_lnd_import') ! Use infodata to set orbital values if updated mid-run @@ -392,12 +405,6 @@ subroutine lnd_run_mct(EClock, cdata_l, x2l_l, l2x_l) call seq_infodata_GetData( infodata, orb_eccen=eccen, orb_mvelpp=mvelpp, & orb_lambm0=lambm0, orb_obliqr=obliqr ) - ! Determine if we're running with a prognostic ROF model. This won't change - ! throughout the run, but we can't count on this being set in initialization, so need - ! to get it in the run method. - - call seq_infodata_GetData( infodata, rof_prognostic=rof_prognostic ) - ! Loop over time steps in coupling interval dosend = .false. diff --git a/src/cpl/lnd_import_export.F90 b/src/cpl/lnd_import_export.F90 index 1d8bc1c7ea..c255ec479f 100644 --- a/src/cpl/lnd_import_export.F90 +++ b/src/cpl/lnd_import_export.F90 @@ -15,26 +15,31 @@ module lnd_import_export contains !=============================================================================== - subroutine lnd_import( bounds, x2l, atm2lnd_inst, glc2lnd_inst) + subroutine lnd_import( bounds, x2l, glc_present, atm2lnd_inst, glc2lnd_inst) !--------------------------------------------------------------------------- ! !DESCRIPTION: ! Convert the input data from the coupler to the land model ! ! !USES: - use clm_varctl , only: co2_type, co2_ppmv, iulog, use_c13, create_glacier_mec_landunit + use seq_flds_mod , only: seq_flds_x2l_fields + use clm_varctl , only: co2_type, co2_ppmv, iulog, use_c13 + use clm_varctl , only: ndep_from_cpl use clm_varcon , only: rair, o2_molar_const, c13ratio use shr_const_mod , only: SHR_CONST_TKFRZ + use shr_string_mod , only: shr_string_listGetName use domainMod , only: ldomain + use shr_infnan_mod , only : isnan => shr_infnan_isnan ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! bounds real(r8) , intent(in) :: x2l(:,:) ! driver import state to land model + logical , intent(in) :: glc_present ! .true. => running with a non-stub GLC model type(atm2lnd_type) , intent(inout) :: atm2lnd_inst ! clm internal input data type type(glc2lnd_type) , intent(inout) :: glc2lnd_inst ! clm internal input data type ! ! !LOCAL VARIABLES: - integer :: g,i,nstep,ier ! indices, number of steps, and error code + integer :: g,i,k,nstep,ier ! indices, number of steps, and error code real(r8) :: forc_rainc ! rainxy Atm flux mm/s real(r8) :: e ! vapor pressure (Pa) real(r8) :: qsat ! saturation specific humidity (kg/kg) @@ -53,8 +58,8 @@ subroutine lnd_import( bounds, x2l, atm2lnd_inst, glc2lnd_inst) real(r8) :: a0,a1,a2,a3,a4,a5,a6 ! coefficients for esat over water real(r8) :: b0,b1,b2,b3,b4,b5,b6 ! coefficients for esat over ice real(r8) :: tdc, t ! Kelvins to Celcius function and its input - integer :: num ! counter - character(len=32), parameter :: sub = 'lnd_import_mct' + character(len=32) :: fname ! name of field that is NaN + character(len=32), parameter :: sub = 'lnd_import' ! Constants to compute vapor pressure parameter (a0=6.107799961_r8 , a1=4.436518521e-01_r8, & @@ -188,7 +193,7 @@ subroutine lnd_import( bounds, x2l, atm2lnd_inst, glc2lnd_inst) end if qsat = 0.622_r8*e / (forc_pbot - 0.378_r8*e) -!modify specific humidity if precip occurs + !modify specific humidity if precip occurs if(1==2) then if((forc_rainc+forc_rainl) > 0._r8) then forc_q = 0.95_r8*qsat @@ -199,6 +204,33 @@ subroutine lnd_import( bounds, x2l, atm2lnd_inst, glc2lnd_inst) atm2lnd_inst%forc_rh_grc(g) = 100.0_r8*(forc_q / qsat) + ! Check that solar, specific-humidity and LW downward aren't negative + if ( atm2lnd_inst%forc_lwrad_not_downscaled_grc(g) <= 0.0_r8 )then + call endrun( sub//' ERROR: Longwave down sent from the atmosphere model is negative or zero' ) + end if + if ( (atm2lnd_inst%forc_solad_grc(g,1) < 0.0_r8) .or. (atm2lnd_inst%forc_solad_grc(g,2) < 0.0_r8) & + .or. (atm2lnd_inst%forc_solai_grc(g,1) < 0.0_r8) .or. (atm2lnd_inst%forc_solai_grc(g,2) < 0.0_r8) ) then + call endrun( sub//' ERROR: One of the solar fields (indirect/diffuse, vis or near-IR)'// & + ' from the atmosphere model is negative or zero' ) + end if + if ( atm2lnd_inst%forc_q_not_downscaled_grc(g) < 0.0_r8 )then + call endrun( sub//' ERROR: Bottom layer specific humidty sent from the atmosphere model is less than zero' ) + end if + + ! Check if any input from the coupler is NaN + if ( any(isnan(x2l(:,i))) )then + write(iulog,*) '# of NaNs = ', count(isnan(x2l(:,i))) + write(iulog,*) 'Which are NaNs = ', isnan(x2l(:,i)) + do k = 1, size(x2l(:,i)) + if ( isnan(x2l(k,i)) )then + call shr_string_listGetName( seq_flds_x2l_fields, k, fname ) + write(iulog,*) trim(fname) + end if + end do + write(iulog,*) 'gridcell index = ', g + call endrun( sub//' ERROR: One or more of the input from the atmosphere model are NaN '// & + '(Not a Number from a bad floating point calculation)' ) + end if ! Make sure relative humidity is properly bounded ! atm2lnd_inst%forc_rh_grc(g) = min( 100.0_r8, atm2lnd_inst%forc_rh_grc(g) ) @@ -220,20 +252,28 @@ subroutine lnd_import( bounds, x2l, atm2lnd_inst, glc2lnd_inst) atm2lnd_inst%forc_pc13o2_grc(g) = co2_ppmv_val * c13ratio * 1.e-6_r8 * forc_pbot end if - ! glc coupling - - if (create_glacier_mec_landunit) then - do num = 0,glc_nec - glc2lnd_inst%frac_grc(g,num) = x2l(index_x2l_Sg_ice_covered(num),i) - glc2lnd_inst%topo_grc(g,num) = x2l(index_x2l_Sg_topo(num),i) - glc2lnd_inst%hflx_grc(g,num) = x2l(index_x2l_Flgg_hflx(num),i) - end do - glc2lnd_inst%icemask_grc(g) = x2l(index_x2l_Sg_icemask,i) - glc2lnd_inst%icemask_coupled_fluxes_grc(g) = x2l(index_x2l_Sg_icemask_coupled_fluxes,i) + if (ndep_from_cpl) then + ! The coupler is sending ndep in units if kgN/m2/s - and clm uses units of gN/m2/sec - so the + ! following conversion needs to happen + atm2lnd_inst%forc_ndep_grc(g) = (x2l(index_x2l_Faxa_nhx, i) + x2l(index_x2l_faxa_noy, i))*1000._r8 end if end do + call glc2lnd_inst%set_glc2lnd_fields( & + bounds = bounds, & + glc_present = glc_present, & + ! NOTE(wjs, 2017-12-13) the x2l argument doesn't have the typical bounds + ! subsetting (bounds%begg:bounds%endg). This mirrors the lack of these bounds in + ! the call to lnd_import from lnd_run_mct. This is okay as long as this code is + ! outside a clump loop. + x2l = x2l, & + index_x2l_Sg_ice_covered = index_x2l_Sg_ice_covered, & + index_x2l_Sg_topo = index_x2l_Sg_topo, & + index_x2l_Flgg_hflx = index_x2l_Flgg_hflx, & + index_x2l_Sg_icemask = index_x2l_Sg_icemask, & + index_x2l_Sg_icemask_coupled_fluxes = index_x2l_Sg_icemask_coupled_fluxes) + end subroutine lnd_import !=============================================================================== @@ -246,12 +286,15 @@ subroutine lnd_export( bounds, lnd2atm_inst, lnd2glc_inst, l2x) ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : iulog, create_glacier_mec_landunit + use seq_flds_mod , only : seq_flds_l2x_fields + use clm_varctl , only : iulog use clm_time_manager , only : get_nstep, get_step_size use seq_drydep_mod , only : n_drydep use shr_megan_mod , only : shr_megan_mechcomps_n use shr_fire_emis_mod , only : shr_fire_emis_mechcomps_n - use domainMod , only: ldomain + use domainMod , only : ldomain + use shr_string_mod , only : shr_string_listGetName + use shr_infnan_mod , only : isnan => shr_infnan_isnan ! ! !ARGUMENTS: implicit none @@ -261,11 +304,13 @@ subroutine lnd_export( bounds, lnd2atm_inst, lnd2glc_inst, l2x) real(r8) , intent(out) :: l2x(:,:)! land to coupler export state on land grid ! ! !LOCAL VARIABLES: - integer :: g,i ! indices + integer :: g,i,k ! indices integer :: ier ! error status integer :: nstep ! time step index integer :: dtime ! time step integer :: num ! counter + character(len=32) :: fname ! name of field that is NaN + character(len=32), parameter :: sub = 'lnd_export' !--------------------------------------------------------------------------- ! cesm sign convention is that fluxes are positive downward @@ -351,13 +396,27 @@ subroutine lnd_export( bounds, lnd2atm_inst, lnd2glc_inst, l2x) l2x(index_l2x_Flrl_irrig,i) = - lnd2atm_inst%qirrig_grc(g) ! glc coupling - - if (create_glacier_mec_landunit) then - do num = 0,glc_nec - l2x(index_l2x_Sl_tsrf(num),i) = lnd2glc_inst%tsrf_grc(g,num) - l2x(index_l2x_Sl_topo(num),i) = lnd2glc_inst%topo_grc(g,num) - l2x(index_l2x_Flgl_qice(num),i) = lnd2glc_inst%qice_grc(g,num) + ! We could avoid setting these fields if glc_present is .false., if that would + ! help with performance. (The downside would be that we wouldn't have these fields + ! available for diagnostic purposes or to force a later T compset with dlnd.) + do num = 0,glc_nec + l2x(index_l2x_Sl_tsrf(num),i) = lnd2glc_inst%tsrf_grc(g,num) + l2x(index_l2x_Sl_topo(num),i) = lnd2glc_inst%topo_grc(g,num) + l2x(index_l2x_Flgl_qice(num),i) = lnd2glc_inst%qice_grc(g,num) + end do + + ! Check if any output sent to the coupler is NaN + if ( any(isnan(l2x(:,i))) )then + write(iulog,*) '# of NaNs = ', count(isnan(l2x(:,i))) + write(iulog,*) 'Which are NaNs = ', isnan(l2x(:,i)) + do k = 1, size(l2x(:,i)) + if ( isnan(l2x(k,i)) )then + call shr_string_listGetName( seq_flds_l2x_fields, k, fname ) + write(iulog,*) trim(fname) + end if end do + write(iulog,*) 'gridcell index = ', g + call endrun( sub//' ERROR: One or more of the output from CLM to the coupler are NaN ' ) end if end do diff --git a/src/dyn_subgrid/dynColumnStateUpdaterMod.F90 b/src/dyn_subgrid/dynColumnStateUpdaterMod.F90 index a6d9a2554a..f5e3763cdc 100644 --- a/src/dyn_subgrid/dynColumnStateUpdaterMod.F90 +++ b/src/dyn_subgrid/dynColumnStateUpdaterMod.F90 @@ -17,6 +17,8 @@ module dynColumnStateUpdaterMod ! ! - call column_state_updater%update_column_state_* ! + ! All calls must be made from within a loop over clumps. + ! ! The following methods are available for state updates: ! ! - update_column_state_no_special_handling @@ -79,6 +81,13 @@ module dynColumnStateUpdaterMod ! columns. If there are fractional areas, then this adjustment is defined as (val_new * ! fractional_area_new - val_old * fractional_area_old). ! + ! NOTE(wjs, 2017-02-24) The implementation involves a few levels of calls to get to the + ! real work routine (update_column_state). This design made sense (in terms of removing + ! code duplication) when there were a number of "front-end" routines, with different + ! special handling. But now it seems we're moving towards having no special handling. + ! If we ditch all of the special handling, we could also ditch these extra levels. This + ! would make the code more straightforward, and would also improve performance. + ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg @@ -110,6 +119,15 @@ module dynColumnStateUpdaterMod ! determined at the time of the call to set_old_weights, so that we consider whether ! a column was active in the previous time step, rather than newly-active. integer , allocatable :: natveg_template_col(:) + + ! Whether there have been any changes in this time step. This is indexed by clump so + ! that it is thread-safe (so the different clumps don't stomp on each other). This + ! implies that the methods on this object need to be called from a loop over + ! clumps. (In the future, we plan to rework threading so that there is a separate + ! object for each clump. In this case the indexing by clump will go away here - + ! instead, there will be a single scalar 'any_changes' logical for each object.) + logical, allocatable :: any_changes(:) + contains ! Public routines procedure, public :: set_old_weights ! set weights before dyn subgrid updates @@ -151,7 +169,7 @@ module dynColumnStateUpdaterMod ! ======================================================================== !----------------------------------------------------------------------- - function constructor(bounds) + function constructor(bounds, nclumps) ! ! !DESCRIPTION: ! Initialize a column_state_updater_type object @@ -162,6 +180,7 @@ function constructor(bounds) ! !ARGUMENTS: type(column_state_updater_type) :: constructor ! function result type(bounds_type), intent(in) :: bounds ! processor bounds + integer , intent(in) :: nclumps ! number of clumps per proc ! ! !LOCAL VARIABLES: @@ -179,6 +198,9 @@ function constructor(bounds) allocate(constructor%natveg_template_col(bounds%begc:bounds%endc)) constructor%natveg_template_col(:) = TEMPLATE_NONE_FOUND + allocate(constructor%any_changes(nclumps)) + constructor%any_changes(:) = .false. + end function constructor ! ======================================================================== @@ -213,7 +235,7 @@ subroutine set_old_weights(this, bounds) end subroutine set_old_weights !----------------------------------------------------------------------- - subroutine set_new_weights(this, bounds) + subroutine set_new_weights(this, bounds, clump_index) ! ! !DESCRIPTION: ! Set subgrid weights after dyn subgrid updates @@ -223,6 +245,11 @@ subroutine set_new_weights(this, bounds) ! !ARGUMENTS: class(column_state_updater_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer , intent(in) :: clump_index + ! ! !LOCAL VARIABLES: integer :: c @@ -230,16 +257,20 @@ subroutine set_new_weights(this, bounds) character(len=*), parameter :: subname = 'set_new_weights' !----------------------------------------------------------------------- + this%any_changes(clump_index) = .false. do c = bounds%begc, bounds%endc this%cwtgcell_new(c) = col%wtgcell(c) this%area_gained_col(c) = this%cwtgcell_new(c) - this%cwtgcell_old(c) + if (this%area_gained_col(c) /= 0._r8) then + this%any_changes(clump_index) = .true. + end if end do end subroutine set_new_weights !----------------------------------------------------------------------- - subroutine update_column_state_no_special_handling(this, bounds, var, & - fractional_area_old, fractional_area_new, adjustment) + subroutine update_column_state_no_special_handling(this, bounds, clump_index, & + var, fractional_area_old, fractional_area_new, adjustment) ! ! !DESCRIPTION: ! Adjust the values of a column-level state variable due to changes in subgrid @@ -252,6 +283,11 @@ subroutine update_column_state_no_special_handling(this, bounds, var, & ! !ARGUMENTS: class(column_state_updater_type), intent(in) :: this type(bounds_type), intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer, intent(in) :: clump_index + real(r8), intent(inout) :: var( bounds%begc: ) ! column-level variable ! Fraction of each column over which the state variable applies. See module-level @@ -279,36 +315,47 @@ subroutine update_column_state_no_special_handling(this, bounds, var, & SHR_ASSERT_ALL((ubound(var) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) - vals_input(bounds%begc:bounds%endc) = var(bounds%begc:bounds%endc) - vals_input_valid(bounds%begc:bounds%endc) = .true. - has_prognostic_state(bounds%begc:bounds%endc) = .true. - non_conserved_mass(bounds%begg:bounds%endg) = 0._r8 + ! Even if there's no work to be done, need to zero out adjustment, since it's + ! intent(out), and caller may expect it to return in a reasonable state. + if (present(adjustment)) then + SHR_ASSERT_ALL((ubound(adjustment) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + adjustment(bounds%begc:bounds%endc) = 0._r8 + end if - ! explicit bounds not needed on any of these arguments - and specifying explicit - ! bounds defeats some later bounds checking (for fractional_area_old and - ! fractional_area_new) - call this%update_column_state_with_optional_fractions(& - bounds = bounds, & - vals_input = vals_input, & - vals_input_valid = vals_input_valid, & - has_prognostic_state = has_prognostic_state, & - var = var, & - non_conserved_mass = non_conserved_mass, & - fractional_area_old = fractional_area_old, & - fractional_area_new = fractional_area_new, & - adjustment = adjustment) + if (this%any_changes(clump_index)) then + + vals_input(bounds%begc:bounds%endc) = var(bounds%begc:bounds%endc) + vals_input_valid(bounds%begc:bounds%endc) = .true. + has_prognostic_state(bounds%begc:bounds%endc) = .true. + non_conserved_mass(bounds%begg:bounds%endg) = 0._r8 + + ! explicit bounds not needed on any of these arguments - and specifying explicit + ! bounds defeats some later bounds checking (for fractional_area_old and + ! fractional_area_new) + call this%update_column_state_with_optional_fractions(& + bounds = bounds, & + vals_input = vals_input, & + vals_input_valid = vals_input_valid, & + has_prognostic_state = has_prognostic_state, & + var = var, & + non_conserved_mass = non_conserved_mass, & + fractional_area_old = fractional_area_old, & + fractional_area_new = fractional_area_new, & + adjustment = adjustment) + + ! Since there is no special handling in this routine, the non_conserved_mass variable + ! should not have any accumulation. We allow for roundoff-level accumulation in case + ! non-conserved mass is determined in a way that is prone to roundoff-level errors. + err_msg = subname//': ERROR: failure to conserve mass when using no special handling' + SHR_ASSERT_ALL(abs(non_conserved_mass(bounds%begg:bounds%endg)) < conservation_tolerance, err_msg) - ! Since there is no special handling in this routine, the non_conserved_mass variable - ! should not have any accumulation. We allow for roundoff-level accumulation in case - ! non-conserved mass is determined in a way that is prone to roundoff-level errors. - err_msg = subname//': ERROR: failure to conserve mass when using no special handling' - SHR_ASSERT_ALL(abs(non_conserved_mass(bounds%begg:bounds%endg)) < conservation_tolerance, err_msg) + end if end subroutine update_column_state_no_special_handling !----------------------------------------------------------------------- - subroutine update_column_state_fill_special_using_natveg(this, bounds, var, & - non_conserved_mass_grc, fractional_area_old, fractional_area_new, adjustment) + subroutine update_column_state_fill_special_using_natveg(this, bounds, clump_index, & + var, non_conserved_mass_grc, fractional_area_old, fractional_area_new, adjustment) ! ! !DESCRIPTION: ! Adjust the values of a column-level state variable due to changes in subgrid @@ -328,6 +375,11 @@ subroutine update_column_state_fill_special_using_natveg(this, bounds, var, & ! !ARGUMENTS: class(column_state_updater_type), intent(in) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer, intent(in) :: clump_index + real(r8) , intent(inout) :: var( bounds%begc: ) ! column-level variable ! Mass lost (per unit of grid cell area) from each grid cell due to changing area of @@ -365,44 +417,56 @@ subroutine update_column_state_fill_special_using_natveg(this, bounds, var, & SHR_ASSERT_ALL((ubound(var) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) SHR_ASSERT_ALL((ubound(non_conserved_mass_grc) == (/bounds%begg/)), errMsg(sourcefile, __LINE__)) - do c = bounds%begc, bounds%endc - l = col%landunit(c) - if (lun%ifspecial(l)) then - has_prognostic_state(c) = .false. - - template_col = this%natveg_template_col(c) - if (template_col == TEMPLATE_NONE_FOUND) then - vals_input(c) = spval - vals_input_valid(c) = .false. + ! Even if there's no work to be done, need to zero out adjustment, since it's + ! intent(out), and caller may expect it to return in a reasonable state. + if (present(adjustment)) then + SHR_ASSERT_ALL((ubound(adjustment) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + adjustment(bounds%begc:bounds%endc) = 0._r8 + end if + + if (this%any_changes(clump_index)) then + + do c = bounds%begc, bounds%endc + l = col%landunit(c) + if (lun%ifspecial(l)) then + has_prognostic_state(c) = .false. + + template_col = this%natveg_template_col(c) + if (template_col == TEMPLATE_NONE_FOUND) then + vals_input(c) = spval + vals_input_valid(c) = .false. + else + vals_input(c) = var(template_col) + vals_input_valid(c) = .true. + end if else - vals_input(c) = var(template_col) + has_prognostic_state(c) = .true. + vals_input(c) = var(c) vals_input_valid(c) = .true. end if - else - has_prognostic_state(c) = .true. - vals_input(c) = var(c) - vals_input_valid(c) = .true. - end if - end do + end do + + ! explicit bounds not needed on any of these arguments - and specifying explicit + ! bounds defeats some later bounds checking (for fractional_area_old and + ! fractional_area_new) + call this%update_column_state_with_optional_fractions(& + bounds = bounds, & + vals_input = vals_input, & + vals_input_valid = vals_input_valid, & + has_prognostic_state = has_prognostic_state, & + var = var, & + non_conserved_mass = non_conserved_mass_grc, & + fractional_area_old = fractional_area_old, & + fractional_area_new = fractional_area_new, & + adjustment = adjustment) - ! explicit bounds not needed on any of these arguments - and specifying explicit - ! bounds defeats some later bounds checking (for fractional_area_old and - ! fractional_area_new) - call this%update_column_state_with_optional_fractions(& - bounds = bounds, & - vals_input = vals_input, & - vals_input_valid = vals_input_valid, & - has_prognostic_state = has_prognostic_state, & - var = var, & - non_conserved_mass = non_conserved_mass_grc, & - fractional_area_old = fractional_area_old, & - fractional_area_new = fractional_area_new, & - adjustment = adjustment) + end if end subroutine update_column_state_fill_special_using_natveg !----------------------------------------------------------------------- - subroutine update_column_state_fill_using_fixed_values(this, bounds, var, & + subroutine update_column_state_fill_using_fixed_values(this, bounds, clump_index, & + var, & landunit_values, non_conserved_mass_grc, & fractional_area_old, fractional_area_new, & adjustment) @@ -438,6 +502,11 @@ subroutine update_column_state_fill_using_fixed_values(this, bounds, var, & ! !ARGUMENTS: class(column_state_updater_type), intent(in) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer, intent(in) :: clump_index + real(r8) , intent(inout) :: var( bounds%begc: ) ! column-level variable real(r8) , intent(in) :: landunit_values(:) ! value to use as input for each landunit type @@ -481,40 +550,52 @@ subroutine update_column_state_fill_using_fixed_values(this, bounds, var, & SHR_ASSERT((size(landunit_values) == max_lunit), err_msg) SHR_ASSERT_ALL((ubound(non_conserved_mass_grc) == (/bounds%begg/)), errMsg(sourcefile, __LINE__)) - do c = bounds%begc, bounds%endc - l = col%landunit(c) - ltype = lun%itype(l) - my_fillval = landunit_values(ltype) - - if (my_fillval == FILLVAL_USE_EXISTING_VALUE) then - vals_input(c) = var(c) - vals_input_valid(c) = .true. - has_prognostic_state(c) = .true. - else - vals_input(c) = my_fillval - vals_input_valid(c) = .true. - has_prognostic_state(c) = .false. - end if - end do + ! Even if there's no work to be done, need to zero out adjustment, since it's + ! intent(out), and caller may expect it to return in a reasonable state. + if (present(adjustment)) then + SHR_ASSERT_ALL((ubound(adjustment) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + adjustment(bounds%begc:bounds%endc) = 0._r8 + end if - ! explicit bounds not needed on any of these arguments - and specifying explicit - ! bounds defeats some later bounds checking (for fractional_area_old and - ! fractional_area_new) - call this%update_column_state_with_optional_fractions( & - bounds = bounds, & - vals_input = vals_input, & - vals_input_valid = vals_input_valid, & - has_prognostic_state = has_prognostic_state, & - var = var, & - non_conserved_mass = non_conserved_mass_grc, & - fractional_area_old = fractional_area_old, & - fractional_area_new = fractional_area_new, & - adjustment = adjustment) + if (this%any_changes(clump_index)) then + + do c = bounds%begc, bounds%endc + l = col%landunit(c) + ltype = lun%itype(l) + my_fillval = landunit_values(ltype) + + if (my_fillval == FILLVAL_USE_EXISTING_VALUE) then + vals_input(c) = var(c) + vals_input_valid(c) = .true. + has_prognostic_state(c) = .true. + else + vals_input(c) = my_fillval + vals_input_valid(c) = .true. + has_prognostic_state(c) = .false. + end if + end do + + ! explicit bounds not needed on any of these arguments - and specifying explicit + ! bounds defeats some later bounds checking (for fractional_area_old and + ! fractional_area_new) + call this%update_column_state_with_optional_fractions( & + bounds = bounds, & + vals_input = vals_input, & + vals_input_valid = vals_input_valid, & + has_prognostic_state = has_prognostic_state, & + var = var, & + non_conserved_mass = non_conserved_mass_grc, & + fractional_area_old = fractional_area_old, & + fractional_area_new = fractional_area_new, & + adjustment = adjustment) + + end if end subroutine update_column_state_fill_using_fixed_values !----------------------------------------------------------------------- - subroutine update_column_state_fill_special_using_fixed_value(this, bounds, var, & + subroutine update_column_state_fill_special_using_fixed_value(this, bounds, clump_index, & + var, & special_value, non_conserved_mass_grc, & fractional_area_old, fractional_area_new, & adjustment) @@ -533,6 +614,11 @@ subroutine update_column_state_fill_special_using_fixed_value(this, bounds, var, ! !ARGUMENTS: class(column_state_updater_type), intent(in) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer, intent(in) :: clump_index + real(r8) , intent(inout) :: var( bounds%begc: ) ! column-level variable real(r8) , intent(in) :: special_value ! value to use as input for all special landunits @@ -575,6 +661,7 @@ subroutine update_column_state_fill_special_using_fixed_value(this, bounds, var, call this%update_column_state_fill_using_fixed_values( & bounds = bounds, & + clump_index = clump_index, & var = var, & landunit_values = landunit_values, & non_conserved_mass_grc = non_conserved_mass_grc, & @@ -640,7 +727,7 @@ subroutine update_column_state_with_optional_fractions(this, bounds, & real(r8), optional, intent(in) :: fractional_area_new( bounds%begc: ) ! Apparent state adjustment in each column - real(r8), optional, intent(out) :: adjustment( bounds%begc: ) + real(r8), optional, intent(inout) :: adjustment( bounds%begc: ) ! ! !LOCAL VARIABLES: real(r8) :: my_fractional_area_old(bounds%begc:bounds%endc) @@ -729,7 +816,7 @@ subroutine update_column_state(this, bounds, & real(r8), intent(inout) :: non_conserved_mass( bounds%begg: ) ! Apparent state adjustment in each column - real(r8), optional, intent(out) :: adjustment( bounds%begc: ) + real(r8), optional, intent(inout) :: adjustment( bounds%begc: ) ! ! !LOCAL VARIABLES: integer :: c, g @@ -832,9 +919,6 @@ subroutine update_column_state(this, bounds, & end do ! Distribute gain to growing columns - if (present(adjustment)) then - adjustment(bounds%begc:bounds%endc) = 0._r8 - end if do c = bounds%begc, bounds%endc g = col%gridcell(c) if (this%area_gained_col(c) > 0._r8) then diff --git a/src/dyn_subgrid/dynConsBiogeophysMod.F90 b/src/dyn_subgrid/dynConsBiogeophysMod.F90 index 9a594d11d6..540a3321ed 100644 --- a/src/dyn_subgrid/dynConsBiogeophysMod.F90 +++ b/src/dyn_subgrid/dynConsBiogeophysMod.F90 @@ -14,15 +14,21 @@ module dynConsBiogeophysMod use decompMod , only : bounds_type use UrbanParamsType , only : urbanparams_type use EnergyFluxType , only : energyflux_type - use LakeStateType , only : lakestate_type use SoilHydrologyType , only : soilhydrology_type use SoilStateType , only : soilstate_type use TemperatureType , only : temperature_type use WaterfluxType , only : waterflux_type use WaterstateType , only : waterstate_type - use LandunitType , only : lun + use TotalWaterAndHeatMod, only : ComputeLiqIceMassNonLake, ComputeLiqIceMassLake + use TotalWaterAndHeatMod, only : ComputeHeatNonLake, ComputeHeatLake + use TotalWaterAndHeatMod, only : AdjustDeltaHeatForDeltaLiq + use TotalWaterAndHeatMod, only : heat_base_temp + use subgridAveMod , only : p2c, c2g + use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch + use clm_varcon , only : tfrz, cpliq, hfus + use dynSubgridControlMod, only : get_for_testing_zero_dynbal_fluxes ! ! !PUBLIC MEMBER FUNCTIONS: implicit none @@ -32,7 +38,8 @@ module dynConsBiogeophysMod public :: dyn_hwcontent_final ! compute grid-level heat and water content, after land cover change; also compute dynbal fluxes ! ! !PRIVATE MEMBER FUNCTIONS - private :: dyn_hwcontent ! do the actual computation of grid-level heat and water content + private :: dyn_water_content ! compute gridcell total liquid and ice water contents + private :: dyn_heat_content ! compute gridcell total heat contents character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -42,7 +49,9 @@ module dynConsBiogeophysMod !--------------------------------------------------------------------------- subroutine dyn_hwcontent_init(bounds, & - urbanparams_inst, soilstate_inst, soilhydrology_inst, lakestate_inst, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & + urbanparams_inst, soilstate_inst, soilhydrology_inst, & waterstate_inst, waterflux_inst, temperature_inst, energyflux_inst) ! ! !DESCRIPTION: @@ -53,10 +62,13 @@ subroutine dyn_hwcontent_init(bounds, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_nolakec + integer , intent(in) :: filter_nolakec(:) + integer , intent(in) :: num_lakec + integer , intent(in) :: filter_lakec(:) type(urbanparams_type) , intent(in) :: urbanparams_inst type(soilstate_type) , intent(in) :: soilstate_inst type(soilhydrology_type) , intent(in) :: soilhydrology_inst - type(lakestate_type) , intent(in) :: lakestate_inst type(waterstate_type) , intent(inout) :: waterstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst type(temperature_type) , intent(inout) :: temperature_inst @@ -64,36 +76,31 @@ subroutine dyn_hwcontent_init(bounds, & ! ! !LOCAL VARIABLES: integer :: g ! grid cell index + !------------------------------------------------------------------------------- - ! initialize heat and water content and dynamic balance fields to zero - do g = bounds%begg, bounds%endg - waterstate_inst%liq2_grc(g) = 0._r8 - waterstate_inst%liq1_grc(g) = 0._r8 - waterstate_inst%ice2_grc(g) = 0._r8 - waterstate_inst%ice1_grc(g) = 0._r8 - - waterflux_inst%qflx_liq_dynbal_grc(g) = 0._r8 - waterflux_inst%qflx_ice_dynbal_grc(g) = 0._r8 - - temperature_inst%heat2_grc(g) = 0._r8 - temperature_inst%heat1_grc(g) = 0._r8 - - energyflux_inst%eflx_dynbal_grc(g) = 0._r8 - enddo - - call dyn_hwcontent( bounds, & - waterstate_inst%liq1_grc(bounds%begg:bounds%endg), & - waterstate_inst%ice1_grc(bounds%begg:bounds%endg), & - temperature_inst%heat1_grc(bounds%begg:bounds%endg) , & + call dyn_water_content(bounds, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & + soilhydrology_inst, waterstate_inst, & + liquid_mass = waterstate_inst%liq1_grc(bounds%begg:bounds%endg), & + ice_mass = waterstate_inst%ice1_grc(bounds%begg:bounds%endg)) + + call dyn_heat_content( bounds, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & urbanparams_inst, soilstate_inst, soilhydrology_inst, & - temperature_inst, waterstate_inst, lakestate_inst) + temperature_inst, waterstate_inst, & + heat_grc = temperature_inst%heat1_grc(bounds%begg:bounds%endg), & + liquid_water_temp_grc = temperature_inst%liquid_water_temp1_grc(bounds%begg:bounds%endg)) end subroutine dyn_hwcontent_init !--------------------------------------------------------------------------- subroutine dyn_hwcontent_final(bounds, & - urbanparams_inst, soilstate_inst, soilhydrology_inst, lakestate_inst, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & + urbanparams_inst, soilstate_inst, soilhydrology_inst, & waterstate_inst, waterflux_inst, temperature_inst, energyflux_inst) ! ! !DESCRIPTION: @@ -104,10 +111,13 @@ subroutine dyn_hwcontent_final(bounds, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_nolakec + integer , intent(in) :: filter_nolakec(:) + integer , intent(in) :: num_lakec + integer , intent(in) :: filter_lakec(:) type(urbanparams_type) , intent(in) :: urbanparams_inst type(soilstate_type) , intent(in) :: soilstate_inst type(soilhydrology_type) , intent(in) :: soilhydrology_inst - type(lakestate_type) , intent(in) :: lakestate_inst type(waterstate_type) , intent(inout) :: waterstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst type(temperature_type) , intent(inout) :: temperature_inst @@ -124,18 +134,41 @@ subroutine dyn_hwcontent_final(bounds, & begg = bounds%begg endg = bounds%endg - call dyn_hwcontent( bounds, & - waterstate_inst%liq2_grc(begg:endg), & - waterstate_inst%ice2_grc(begg:endg), & - temperature_inst%heat2_grc(begg:endg) , & - urbanparams_inst, soilstate_inst, soilhydrology_inst, & - temperature_inst, waterstate_inst, lakestate_inst) + call dyn_water_content(bounds, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & + soilhydrology_inst, waterstate_inst, & + liquid_mass = waterstate_inst%liq2_grc(bounds%begg:bounds%endg), & + ice_mass = waterstate_inst%ice2_grc(bounds%begg:bounds%endg)) - do g = begg, endg - delta_liq(g) = waterstate_inst%liq2_grc(g) - waterstate_inst%liq1_grc(g) - delta_ice(g) = waterstate_inst%ice2_grc(g) - waterstate_inst%ice1_grc(g) - delta_heat(g) = temperature_inst%heat2_grc(g) - temperature_inst%heat1_grc(g) - end do + call dyn_heat_content( bounds, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & + urbanparams_inst, soilstate_inst, soilhydrology_inst, & + temperature_inst, waterstate_inst, & + heat_grc = temperature_inst%heat2_grc(bounds%begg:bounds%endg), & + liquid_water_temp_grc = temperature_inst%liquid_water_temp2_grc(bounds%begg:bounds%endg)) + + if (get_for_testing_zero_dynbal_fluxes()) then + do g = begg, endg + delta_liq(g) = 0._r8 + delta_ice(g) = 0._r8 + delta_heat(g) = 0._r8 + end do + else + do g = begg, endg + delta_liq(g) = waterstate_inst%liq2_grc(g) - waterstate_inst%liq1_grc(g) + delta_ice(g) = waterstate_inst%ice2_grc(g) - waterstate_inst%ice1_grc(g) + delta_heat(g) = temperature_inst%heat2_grc(g) - temperature_inst%heat1_grc(g) + end do + end if + + call AdjustDeltaHeatForDeltaLiq( & + bounds, & + delta_liq = delta_liq(bounds%begg:bounds%endg), & + liquid_water_temp1 = temperature_inst%liquid_water_temp1_grc(bounds%begg:bounds%endg), & + liquid_water_temp2 = temperature_inst%liquid_water_temp2_grc(bounds%begg:bounds%endg), & + delta_heat = delta_heat(bounds%begg:bounds%endg)) call waterflux_inst%qflx_liq_dynbal_dribbler%set_curr_delta(bounds, & delta_liq(begg:endg)) @@ -154,217 +187,151 @@ subroutine dyn_hwcontent_final(bounds, & end subroutine dyn_hwcontent_final + !----------------------------------------------------------------------- + subroutine dyn_water_content(bounds, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & + soilhydrology_inst, waterstate_inst, & + liquid_mass, ice_mass) + ! + ! !DESCRIPTION: + ! Compute gridcell total liquid and ice water contents + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_nolakec + integer , intent(in) :: filter_nolakec(:) + integer , intent(in) :: num_lakec + integer , intent(in) :: filter_lakec(:) + type(soilhydrology_type) , intent(in) :: soilhydrology_inst + type(waterstate_type) , intent(in) :: waterstate_inst + real(r8) , intent(out) :: liquid_mass( bounds%begg: ) ! kg m-2 + real(r8) , intent(out) :: ice_mass( bounds%begg: ) ! kg m-2 + ! + ! !LOCAL VARIABLES: + real(r8) :: liquid_mass_col(bounds%begc:bounds%endc) ! kg m-2 + real(r8) :: ice_mass_col(bounds%begc:bounds%endc) ! kg m-2 + + character(len=*), parameter :: subname = 'dyn_water_content' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(liquid_mass) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(ice_mass) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + + call ComputeLiqIceMassNonLake(bounds, num_nolakec, filter_nolakec, & + soilhydrology_inst, waterstate_inst, & + liquid_mass_col(bounds%begc:bounds%endc), & + ice_mass_col(bounds%begc:bounds%endc)) + + call ComputeLiqIceMassLake(bounds, num_lakec, filter_lakec, & + waterstate_inst, & + liquid_mass_col(bounds%begc:bounds%endc), & + ice_mass_col(bounds%begc:bounds%endc)) + + call c2g(bounds, & + carr = liquid_mass_col(bounds%begc:bounds%endc), & + garr = liquid_mass(bounds%begg:bounds%endg), & + c2l_scale_type = 'urbanf', & + l2g_scale_type = 'unity') + + call c2g(bounds, & + carr = ice_mass_col(bounds%begc:bounds%endc), & + garr = ice_mass(bounds%begg:bounds%endg), & + c2l_scale_type = 'urbanf', & + l2g_scale_type = 'unity') + + end subroutine dyn_water_content + + !--------------------------------------------------------------------------- - subroutine dyn_hwcontent(bounds, gcell_liq, gcell_ice, gcell_heat, & + subroutine dyn_heat_content(bounds, & + num_nolakec, filter_nolakec, & + num_lakec, filter_lakec, & urbanparams_inst, soilstate_inst, soilhydrology_inst, & - temperature_inst, waterstate_inst, lakestate_inst) + temperature_inst, waterstate_inst, & + heat_grc, liquid_water_temp_grc) ! !DESCRIPTION: ! Compute grid-level heat and water content to track conservation with respect to ! dynamic land cover. - - ! !USES: - use landunit_varcon , only : istsoil, istice, istwet, istdlak, istice_mec, istcrop - use column_varcon , only : icol_road_perv, icol_road_imperv, icol_roof, icol_sunwall, icol_shadewall - use clm_varcon , only : cpice, cpliq, denh2o - use clm_varpar , only : nlevsno, nlevgrnd, nlevurb, nlevlak + ! + ! Heat content is computed relative to a baseline of 0 C. So temperatures above 0 C + ! lead to a positive heat content, temperatures below 0 C lead to a negative heat + ! content. For water, the baseline is considered to be ice at 0 C, so for liquid water + ! we include the latent heat of fusion. ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - real(r8) , intent(out) :: gcell_liq ( bounds%begg: ) ! [gridcell] - real(r8) , intent(out) :: gcell_ice ( bounds%begg: ) ! [gridcell] - real(r8) , intent(out) :: gcell_heat( bounds%begg: ) ! [gridcell] + integer , intent(in) :: num_nolakec + integer , intent(in) :: filter_nolakec(:) + integer , intent(in) :: num_lakec + integer , intent(in) :: filter_lakec(:) type(urbanparams_type) , intent(in) :: urbanparams_inst type(soilstate_type) , intent(in) :: soilstate_inst type(soilhydrology_type) , intent(in) :: soilhydrology_inst type(temperature_type) , intent(in) :: temperature_inst type(waterstate_type) , intent(in) :: waterstate_inst - type(lakestate_type) , intent(in) :: lakestate_inst + + real(r8) , intent(out) :: heat_grc( bounds%begg: ) ! total heat content for each grid cell [J/m^2] + real(r8) , intent(out) :: liquid_water_temp_grc( bounds%begg: ) ! weighted average liquid water temperature for each grid cell (K) + ! ! !LOCAL VARIABLES: - integer :: li,lf ! loop initial/final indicies - integer :: ci,cf ! loop initial/final indicies - integer :: pi,pf ! loop initial/final indicies - - integer :: g,l,c,p,k ! loop indicies (grid,lunit,column,pft,vertical level) - - real(r8) :: wtgcell ! weight relative to grid cell - real(r8) :: wtcol ! weight relative to column - real(r8) :: liq ! sum of liquid water at column level - real(r8) :: ice ! sum of frozen water at column level - real(r8) :: heat ! sum of heat content at column level - real(r8) :: cv ! heat capacity [J/(m^2 K)] - - integer ,pointer :: nlev_improad(:) ! number of impervious road layers - real(r8),pointer :: cv_wall(:,:) ! thermal conductivity of urban wall - real(r8),pointer :: cv_roof(:,:) ! thermal conductivity of urban roof - real(r8),pointer :: cv_improad(:,:) ! thermal conductivity of urban impervious road - integer ,pointer :: snl(:) ! number of snow layers - real(r8),pointer :: t_soisno(:,:) ! soil temperature (Kelvin) - real(r8),pointer :: h2osno(:) ! snow water (mm H2O) - real(r8),pointer :: h2osoi_liq(:,:) ! liquid water (kg/m2) - real(r8),pointer :: h2osoi_ice(:,:) ! frozen water (kg/m2) - real(r8),pointer :: watsat(:,:) ! volumetric soil water at saturation (porosity) - real(r8),pointer :: csol(:,:) ! heat capacity, soil solids (J/m**3/Kelvin) - real(r8),pointer :: wa_col(:) ! water in the unconfined aquifer (mm) - real(r8),pointer :: dz(:,:) ! layer depth (m) + integer :: g + + real(r8) :: heat_col(bounds%begc:bounds%endc) ! sum of heat content for all columns [J/m^2] + real(r8) :: heat_liquid_col(bounds%begc:bounds%endc) ! sum of heat content for all columns: liquid water, excluding latent heat [J/m^2] + real(r8) :: cv_liquid_col(bounds%begc:bounds%endc) ! sum of liquid heat capacity for all columns [J/(m^2 K)] + + real(r8) :: heat_liquid_grc(bounds%begg:bounds%endg) ! heat_liquid_col averaged to grid cell [J/m^2] + real(r8) :: cv_liquid_grc(bounds%begg:bounds%endg) ! cv_liquid_col averaged to grid cell [J/(m^2 K)] !------------------------------------------------------------------------------- ! Enforce expected array sizes - SHR_ASSERT_ALL((ubound(gcell_liq) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) - SHR_ASSERT_ALL((ubound(gcell_ice) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) - SHR_ASSERT_ALL((ubound(gcell_heat) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) - - snl => col%snl - dz => col%dz - nlev_improad => urbanparams_inst%nlev_improad - cv_wall => urbanparams_inst%cv_wall - cv_roof => urbanparams_inst%cv_roof - cv_improad => urbanparams_inst%cv_improad - watsat => soilstate_inst%watsat_col - csol => soilstate_inst%csol_col - wa_col => soilhydrology_inst%wa_col - t_soisno => temperature_inst%t_soisno_col - h2osoi_liq => waterstate_inst%h2osoi_liq_col - h2osoi_ice => waterstate_inst%h2osoi_ice_col - h2osno => waterstate_inst%h2osno_col - - ! Get relevant sizes - - do g = bounds%begg,bounds%endg ! loop over grid cells - gcell_liq (g) = 0.0_r8 ! sum for one grid cell - gcell_ice (g) = 0.0_r8 ! sum for one grid cell - gcell_heat (g) = 0.0_r8 ! sum for one grid cell + SHR_ASSERT_ALL((ubound(heat_grc) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(liquid_water_temp_grc) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + + call ComputeHeatNonLake(bounds, num_nolakec, filter_nolakec, & + urbanparams_inst, soilstate_inst, & + temperature_inst, waterstate_inst, soilhydrology_inst, & + heat = heat_col(bounds%begc:bounds%endc), & + heat_liquid = heat_liquid_col(bounds%begc:bounds%endc), & + cv_liquid = cv_liquid_col(bounds%begc:bounds%endc)) + + call ComputeHeatLake(bounds, num_lakec, filter_lakec, & + soilstate_inst, temperature_inst, waterstate_inst, & + heat = heat_col(bounds%begc:bounds%endc), & + heat_liquid = heat_liquid_col(bounds%begc:bounds%endc), & + cv_liquid = cv_liquid_col(bounds%begc:bounds%endc)) + + call c2g(bounds, & + carr = heat_col(bounds%begc:bounds%endc), & + garr = heat_grc(bounds%begg:bounds%endg), & + c2l_scale_type = 'urbanf', & + l2g_scale_type = 'unity') + + call c2g(bounds, & + carr = heat_liquid_col(bounds%begc:bounds%endc), & + garr = heat_liquid_grc(bounds%begg:bounds%endg), & + c2l_scale_type = 'urbanf', & + l2g_scale_type = 'unity') + + call c2g(bounds, & + carr = cv_liquid_col(bounds%begc:bounds%endc), & + garr = cv_liquid_grc(bounds%begg:bounds%endg), & + c2l_scale_type = 'urbanf', & + l2g_scale_type = 'unity') + + do g = bounds%begg, bounds%endg + if (cv_liquid_grc(g) > 0._r8) then + liquid_water_temp_grc(g) = & + (heat_liquid_grc(g) / cv_liquid_grc(g)) + heat_base_temp + else + ! 0 or negative water mass in this grid cell: set an arbitrary temperature + liquid_water_temp_grc(g) = tfrz + end if end do - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - ci = lun%coli(l) - cf = lun%colf(l) - do c = ci,cf ! loop over columns - - liq = 0.0_r8 ! sum for one column - ice = 0.0_r8 - heat = 0.0_r8 - - !--- water & ice, above ground only --- - if ( (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop ) & - .or. (lun%itype(l) == istwet ) & - .or. (lun%itype(l) == istice ) & - .or. (lun%itype(l) == istice_mec ) & - .or. (lun%urbpoi(l) .and. col%itype(c) == icol_roof ) & - .or. (lun%urbpoi(l) .and. col%itype(c) == icol_road_imperv) & - .or. (lun%itype(l) == istdlak ) & - .or. (lun%urbpoi(l) .and. col%itype(c) == icol_road_perv )) then - - if ( snl(c) < 0 ) then - do k = snl(c)+1,0 ! loop over snow layers - liq = liq + h2osoi_liq(c,k) - ice = ice + h2osoi_ice(c,k) - end do - else ! no snow layers exist - ice = ice + waterstate_inst%h2osno_col(c) - end if - end if - - !--- water & ice, below ground only --- - if ( (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop ) & - .or. (lun%itype(l) == istwet ) & - .or. (lun%itype(l) == istice ) & - .or. (lun%itype(l) == istdlak ) & - .or. (lun%itype(l) == istice_mec ) & - .or. (lun%urbpoi(l) .and. col%itype(c) == icol_road_perv )) then - do k = 1,nlevgrnd - liq = liq + h2osoi_liq(c,k) - ice = ice + h2osoi_ice(c,k) - end do - end if - - !--- water & ice, below ground, for lakes --- - if ( lun%itype(l) == istdlak ) then - do k = 1,nlevlak - liq = liq + (1 - lakestate_inst%lake_icefrac_col(c,k)) * col%dz_lake(c,k) * denh2o - ice = ice + lakestate_inst%lake_icefrac_col(c,k) * col%dz_lake(c,k) * denh2o - ! lake layers do not change thickness when freezing, so denh2o should be used - ! (thermal properties are appropriately adjusted; see LakeTemperatureMod) - end do - end if - - !--- water in aquifer --- - if ( (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop ) & - .or. (lun%itype(l) == istwet ) & - .or. (lun%itype(l) == istice ) & - .or. (lun%itype(l) == istice_mec ) & - .or. (lun%urbpoi(l) .and. col%itype(c) == icol_road_perv )) then - liq = liq + soilhydrology_inst%wa_col(c) - end if - - !--- water in canopy (at pft level) --- - if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then ! note: soil specified at LU level - do p = col%patchi(c),col%patchf(c) ! loop over patches - if (patch%active(p)) then - liq = liq + waterstate_inst%h2ocan_patch(p) * patch%wtcol(p) - end if - end do - end if - - !--- heat content, below ground only --- - if (nlevurb > 0) then - do k = 1,nlevurb - if (col%itype(c)==icol_sunwall .OR. col%itype(c)==icol_shadewall) then - cv = cv_wall(l,k) * dz(c,k) - heat = heat + cv*t_soisno(c,k) / 1.e6_r8 - else if (col%itype(c) == icol_roof) then - cv = cv_roof(l,k) * dz(c,k) - heat = heat + cv*t_soisno(c,k) / 1.e6_r8 - end if - end do - end if - do k = 1,nlevgrnd - if (col%itype(c) /= icol_sunwall .and. col%itype(c) /= icol_shadewall & - .and. col%itype(c) /= icol_roof) then - if (col%itype(c) == icol_road_imperv .and. k >= 1 .and. k <= nlev_improad(l)) then - cv = cv_improad(l,k) * dz(c,k) - else if (lun%itype(l) /= istwet .AND. lun%itype(l) /= istice .AND. lun%itype(l) /= istice_mec) then - cv = csol(c,k)*(1-watsat(c,k))*dz(c,k) + (h2osoi_ice(c,k)*cpice + h2osoi_liq(c,k)*cpliq) - else - cv = (h2osoi_ice(c,k)*cpice + h2osoi_liq(c,k)*cpliq) - endif - heat = heat + cv*t_soisno(c,k) / 1.e6_r8 - end if - end do - - !--- heat content, below ground in lake water, for lakes --- - do k = 1,nlevlak - if (lun%itype(l) == istdlak) then - cv = denh2o*col%dz_lake(c,k)*( lakestate_inst%lake_icefrac_col(c,k)*cpice + & - (1 - lakestate_inst%lake_icefrac_col(c,k))*cpliq ) - heat = heat + cv*temperature_inst%t_lake_col(c,k) / 1.e6_r8 - end if - end do - - !--- heat content, above ground only --- - if ( snl(c) < 0 ) then - do k = snl(c)+1,0 ! loop over snow layers - cv = cpliq*h2osoi_liq(c,k) + cpice*h2osoi_ice(c,k) - heat = heat + cv*t_soisno(c,k) / 1.e6_r8 - end do - else if ( h2osno(c) > 0.0_r8 .and. lun%itype(l) /= istdlak) then - ! the heat capacity (not latent heat) of snow without snow layers - ! is currently ignored in LakeTemperature, so it should be ignored here - k = 1 - cv = cpice*h2osno(c) - heat = heat + cv*t_soisno(c,k) / 1.e6_r8 - end if - - !--- scale x/m^2 column-level values into x/m^2 gridcell-level values --- - gcell_liq (g) = gcell_liq (g) + liq * col%wtgcell(c) - gcell_ice (g) = gcell_ice (g) + ice * col%wtgcell(c) - gcell_heat (g) = gcell_heat (g) + heat * col%wtgcell(c) - - end do ! column loop - end do ! landunit loop - - end subroutine dyn_hwcontent + end subroutine dyn_heat_content end module dynConsBiogeophysMod diff --git a/src/dyn_subgrid/dynEDMod.F90 b/src/dyn_subgrid/dynEDMod.F90 index 1c9ae9a874..e1cb1ccb42 100644 --- a/src/dyn_subgrid/dynEDMod.F90 +++ b/src/dyn_subgrid/dynEDMod.F90 @@ -12,7 +12,7 @@ module dynEDMod implicit none private ! - public :: dyn_ED ! transfers weights calculated internally by ED into wtcol. + public :: dyn_ED ! transfers weights calculated internally by fates into wtcol. !------------------------------------------------------------------------ contains diff --git a/src/dyn_subgrid/dynInitColumnsMod.F90 b/src/dyn_subgrid/dynInitColumnsMod.F90 index b70671f575..a7713f0c80 100644 --- a/src/dyn_subgrid/dynInitColumnsMod.F90 +++ b/src/dyn_subgrid/dynInitColumnsMod.F90 @@ -7,18 +7,19 @@ module dynInitColumnsMod ! ! !USES: #include "shr_assert.h" - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use decompMod , only : bounds_type - use abortutils , only : endrun - use clm_varctl , only : iulog - use clm_varcon , only : namec - use TemperatureType , only : temperature_type - use WaterstateType , only : waterstate_type - use GridcellType , only : grc - use LandunitType , only : lun - use ColumnType , only : col - use dynColumnTemplateMod, only : template_col_from_landunit, TEMPLATE_NONE_FOUND + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use decompMod , only : bounds_type + use abortutils , only : endrun + use clm_varctl , only : iulog + use clm_varcon , only : namec + use TemperatureType , only : temperature_type + use WaterstateType , only : waterstate_type + use SoilHydrologyType , only : soilhydrology_type + use GridcellType , only : grc + use LandunitType , only : lun + use ColumnType , only : col + use dynColumnTemplateMod , only : template_col_from_landunit, TEMPLATE_NONE_FOUND ! ! !PUBLIC MEMBER FUNCTIONS: implicit none @@ -44,7 +45,8 @@ module dynInitColumnsMod contains !----------------------------------------------------------------------- - subroutine initialize_new_columns(bounds, cactive_prior, temperature_inst, waterstate_inst) + subroutine initialize_new_columns(bounds, cactive_prior, & + temperature_inst, waterstate_inst, soilhydrology_inst) ! ! !DESCRIPTION: ! Do initialization for all columns that are newly-active in this time step @@ -55,8 +57,9 @@ subroutine initialize_new_columns(bounds, cactive_prior, temperature_inst, water ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! bounds logical , intent(in) :: cactive_prior( bounds%begc: ) ! column-level active flags from prior time step - type(temperature_type) , intent(inout) :: temperature_inst - type(waterstate_type) , intent(inout) :: waterstate_inst + type(temperature_type) , intent(inout) :: temperature_inst + type(waterstate_type) , intent(inout) :: waterstate_inst + type(soilhydrology_type) , intent(inout) :: soilhydrology_inst ! ! !LOCAL VARIABLES: integer :: c ! column index @@ -72,7 +75,8 @@ subroutine initialize_new_columns(bounds, cactive_prior, temperature_inst, water if (col%active(c) .and. .not. cactive_prior(c)) then c_template = initial_template_col_dispatcher(bounds, c, cactive_prior(bounds%begc:bounds%endc)) if (c_template /= TEMPLATE_NONE_FOUND) then - call copy_state(c, c_template, temperature_inst, waterstate_inst) + call copy_state(c, c_template, & + temperature_inst, waterstate_inst, soilhydrology_inst) else write(iulog,*) subname// ' WARNING: No template column found to initialize newly-active column' write(iulog,*) '-- keeping the state that was already in memory, possibly from arbitrary initialization' @@ -94,7 +98,7 @@ function initial_template_col_dispatcher(bounds, c_new, cactive_prior) result(c_ ! Returns TEMPLATE_NONE_FOUND if there is no column to use for initialization ! ! !USES: - use landunit_varcon, only : istsoil, istcrop, istice, istice_mec, istdlak, istwet, isturb_MIN, isturb_MAX + use landunit_varcon, only : istsoil, istcrop, istice_mec, istdlak, istwet, isturb_MIN, isturb_MAX ! ! !ARGUMENTS: integer :: c_template ! function result @@ -118,10 +122,6 @@ function initial_template_col_dispatcher(bounds, c_new, cactive_prior) result(c_ c_template = initial_template_col_soil(c_new) case(istcrop) c_template = initial_template_col_crop(bounds, c_new, cactive_prior(bounds%begc:bounds%endc)) - case(istice) - write(iulog,*) subname// ' ERROR: Ability to initialize a newly-active glacier column not yet implemented' - write(iulog,*) 'Expectation is that only ice_mec columns can grow' - call endrun(decomp_index=c_new, clmlevel=namec, msg=errMsg(sourcefile, __LINE__)) case(istice_mec) write(iulog,*) subname// ' ERROR: Ability to initialize a newly-active glacier mec column not yet implemented' write(iulog,*) 'Expectation is that glacier mec columns should be active from the start of the run wherever they can grow' @@ -211,7 +211,8 @@ end function initial_template_col_crop !----------------------------------------------------------------------- - subroutine copy_state(c_new, c_template, temperature_inst, waterstate_inst) + subroutine copy_state(c_new, c_template, & + temperature_inst, waterstate_inst, soilhydrology_inst) ! ! !DESCRIPTION: ! Copy a subset of state variables from a template column (c_template) to a newly- @@ -222,8 +223,9 @@ subroutine copy_state(c_new, c_template, temperature_inst, waterstate_inst) ! !ARGUMENTS: integer, intent(in) :: c_new ! index of newly-active column integer, intent(in) :: c_template ! index of column to use as a template - type(temperature_type), intent(inout) :: temperature_inst - type(waterstate_type) , intent(inout) :: waterstate_inst + type(temperature_type) , intent(inout) :: temperature_inst + type(waterstate_type) , intent(inout) :: waterstate_inst + type(soilhydrology_type), intent(inout) :: soilhydrology_inst ! ! !LOCAL VARIABLES: @@ -252,6 +254,8 @@ subroutine copy_state(c_new, c_template, temperature_inst, waterstate_inst) waterstate_inst%h2osoi_ice_col(c_new,1:) = waterstate_inst%h2osoi_ice_col(c_template,1:) waterstate_inst%h2osoi_vol_col(c_new,1:) = waterstate_inst%h2osoi_vol_col(c_template,1:) + soilhydrology_inst%wa_col(c_new) = soilhydrology_inst%wa_col(c_template) + end subroutine copy_state diff --git a/src/dyn_subgrid/dynLandunitAreaMod.F90 b/src/dyn_subgrid/dynLandunitAreaMod.F90 index a290c7d731..1d13efa8f0 100644 --- a/src/dyn_subgrid/dynLandunitAreaMod.F90 +++ b/src/dyn_subgrid/dynLandunitAreaMod.F90 @@ -13,7 +13,7 @@ module dynLandunitAreaMod use clm_varctl , only : iulog use clm_varcon , only : ispval, namel use landunit_varcon, only : isturb_hd, isturb_md, isturb_tbd - use landunit_varcon, only : istsoil, istcrop, istice, istdlak, istwet, max_lunit + use landunit_varcon, only : istsoil, istcrop, istdlak, istwet, max_lunit use decompMod , only : bounds_type use abortutils , only : endrun use GridcellType , only : grc @@ -113,8 +113,8 @@ subroutine update_landunit_weights_one_gcell(landunit_weights) ! the areas specified by GLC. In general, the code will NOT be robust if more than ! one landunit is excluded from this list. Meaning: since istice_mec is excluded from ! this list, all other landunits should appear in this list! - integer, parameter :: decrease_order(8) = & - (/istsoil, istcrop, isturb_md, isturb_hd, isturb_tbd, istwet, istdlak, istice/) + integer, parameter :: decrease_order(7) = & + (/istsoil, istcrop, isturb_md, isturb_hd, isturb_tbd, istwet, istdlak/) real(r8), parameter :: tol = 1.e-14 ! tolerance for making sure sum of landunit weights equals 1 diff --git a/src/dyn_subgrid/dynSubgridControlMod.F90 b/src/dyn_subgrid/dynSubgridControlMod.F90 index 0db45f71df..58e3a40359 100644 --- a/src/dyn_subgrid/dynSubgridControlMod.F90 +++ b/src/dyn_subgrid/dynSubgridControlMod.F90 @@ -27,6 +27,7 @@ module dynSubgridControlMod public :: run_has_transient_landcover ! returns true if any aspects of prescribed transient landcover are enabled public :: get_do_harvest ! return the value of the do_harvest control flag public :: get_for_testing_allow_non_annual_changes ! return true if user has requested to allow area changes at times other than the year boundary, for testing purposes + public :: get_for_testing_zero_dynbal_fluxes ! return true if user has requested to set the dynbal water and energy fluxes to zero, for testing purposes ! ! !PRIVATE MEMBER FUNCTIONS: private :: read_namelist ! read namelist variables @@ -45,7 +46,15 @@ module dynSubgridControlMod ! where we artificially create changes more frequently so that we can run short ! tests. This flag is only used for error-checking, not controlling any model ! behavior. - logical :: for_testing_allow_non_annual_changes + logical :: for_testing_allow_non_annual_changes = .false. + + ! The following is only meant for testing: If .true., set the dynbal water and + ! energy fluxes to zero. This is needed in some tests where we have daily rather + ! than annual glacier dynamics: if we allow the true dynbal adjustment fluxes in + ! those tests, we end up with sensible heat fluxes of thousands of W m-2 or more, + ! which causes CAM to blow up. However, note that setting it to true will break + ! water and energy conservation! + logical :: for_testing_zero_dynbal_fluxes = .false. logical :: initialized = .false. ! whether this object has been initialized end type dyn_subgrid_control_type @@ -106,6 +115,7 @@ subroutine read_namelist( NLFilename ) logical :: do_transient_crops logical :: do_harvest logical :: for_testing_allow_non_annual_changes + logical :: for_testing_zero_dynbal_fluxes ! other local variables: integer :: nu_nml ! unit for namelist file integer :: nml_error ! namelist i/o error flag @@ -118,7 +128,8 @@ subroutine read_namelist( NLFilename ) do_transient_pfts, & do_transient_crops, & do_harvest, & - for_testing_allow_non_annual_changes + for_testing_allow_non_annual_changes, & + for_testing_zero_dynbal_fluxes ! Initialize options to default values, in case they are not specified in the namelist flanduse_timeseries = ' ' @@ -126,6 +137,7 @@ subroutine read_namelist( NLFilename ) do_transient_crops = .false. do_harvest = .false. for_testing_allow_non_annual_changes = .false. + for_testing_zero_dynbal_fluxes = .false. if (masterproc) then nu_nml = getavu() @@ -148,13 +160,15 @@ subroutine read_namelist( NLFilename ) call shr_mpi_bcast (do_transient_crops, mpicom) call shr_mpi_bcast (do_harvest, mpicom) call shr_mpi_bcast (for_testing_allow_non_annual_changes, mpicom) + call shr_mpi_bcast (for_testing_zero_dynbal_fluxes, mpicom) dyn_subgrid_control_inst = dyn_subgrid_control_type( & flanduse_timeseries = flanduse_timeseries, & do_transient_pfts = do_transient_pfts, & do_transient_crops = do_transient_crops, & do_harvest = do_harvest, & - for_testing_allow_non_annual_changes = for_testing_allow_non_annual_changes) + for_testing_allow_non_annual_changes = for_testing_allow_non_annual_changes, & + for_testing_zero_dynbal_fluxes = for_testing_zero_dynbal_fluxes) if (masterproc) then write(iulog,*) ' ' @@ -172,7 +186,7 @@ subroutine check_namelist_consistency ! Check consistency of namelist settingsn ! ! !USES: - use clm_varctl , only : iulog, use_cndv, use_ed, use_cn, use_crop + use clm_varctl , only : iulog, use_cndv, use_fates, use_cn, use_crop ! ! !ARGUMENTS: ! @@ -204,8 +218,8 @@ subroutine check_namelist_consistency write(iulog,*) 'ERROR: do_transient_pfts is incompatible with use_cndv' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if (use_ed) then - write(iulog,*) 'ERROR: do_transient_pfts is incompatible with use_ed' + if (use_fates) then + write(iulog,*) 'ERROR: do_transient_pfts is incompatible with use_fates' call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if @@ -215,11 +229,11 @@ subroutine check_namelist_consistency write(iulog,*) 'ERROR: do_transient_crops can only be true if use_crop is true' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if (use_ed) then + if (use_fates) then ! NOTE(wjs, 2017-01-13) ED / FATES does not currently have a mechanism for ! changing its column areas, with the consequent changes in aboveground biomass ! per unit area. See https://github.com/NGEET/ed-clm/issues/173 - write(iulog,*) 'ERROR: do_transient_crops does not currently work with use_ed' + write(iulog,*) 'ERROR: do_transient_crops does not currently work with use_fates' call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if @@ -229,8 +243,8 @@ subroutine check_namelist_consistency write(iulog,*) 'ERROR: do_harvest can only be true if use_cn is true' call endrun(msg=errMsg(sourcefile, __LINE__)) end if - if (use_ed) then - write(iulog,*) 'ERROR: do_harvest currently does not work with use_ed' + if (use_fates) then + write(iulog,*) 'ERROR: do_harvest currently does not work with use_fates' call endrun(msg=errMsg(sourcefile, __LINE__)) end if end if @@ -313,5 +327,22 @@ logical function get_for_testing_allow_non_annual_changes() end function get_for_testing_allow_non_annual_changes + !----------------------------------------------------------------------- + logical function get_for_testing_zero_dynbal_fluxes() + ! + ! !DESCRIPTION: + ! Return true if the user has requested to set the dynbal water and energy fluxes to + ! zero. This should typically only be true for testing: This is needed in some tests + ! where we have daily rather than annual glacier dynamics: if we allow the true dynbal + ! adjustment fluxes in those tests, we end up with sensible heat fluxes of thousands + ! of W m-2 or more, which causes CAM to blow up. However, note that setting it to + ! true will break water and energy conservation! + ! ----------------------------------------------------------------------- + + SHR_ASSERT(dyn_subgrid_control_inst%initialized, errMsg(sourcefile, __LINE__)) + + get_for_testing_zero_dynbal_fluxes = dyn_subgrid_control_inst%for_testing_zero_dynbal_fluxes + + end function get_for_testing_zero_dynbal_fluxes end module dynSubgridControlMod diff --git a/src/dyn_subgrid/dynSubgridDriverMod.F90 b/src/dyn_subgrid/dynSubgridDriverMod.F90 index 11a75b9aea..8703fcb2d9 100644 --- a/src/dyn_subgrid/dynSubgridDriverMod.F90 +++ b/src/dyn_subgrid/dynSubgridDriverMod.F90 @@ -33,7 +33,6 @@ module dynSubgridDriverMod use SoilBiogeochemNitrogenStateType, only : soilbiogeochem_nitrogenstate_type use ch4Mod, only : ch4_type use EnergyFluxType , only : energyflux_type - use LakeStateType , only : lakestate_type use PhotosynthesisMod , only : photosyns_type use SoilHydrologyType , only : soilhydrology_type use SoilStateType , only : soilstate_type @@ -42,7 +41,7 @@ module dynSubgridDriverMod use TemperatureType , only : temperature_type use CropType , only : crop_type use glc2lndMod , only : glc2lnd_type - use filterMod , only : filter_inactive_and_active + use filterMod , only : filter, filter_inactive_and_active ! ! !PUBLIC MEMBER FUNCTIONS: implicit none @@ -102,7 +101,7 @@ subroutine dynSubgrid_init(bounds_proc, glc_behavior, crop_inst) prior_weights = prior_weights_type(bounds_proc) patch_state_updater = patch_state_updater_type(bounds_proc) - column_state_updater = column_state_updater_type(bounds_proc) + column_state_updater = column_state_updater_type(bounds_proc, nclumps) ! Initialize stuff for prescribed transient Patches if (get_do_transient_pfts()) then @@ -154,7 +153,7 @@ end subroutine dynSubgrid_init !----------------------------------------------------------------------- subroutine dynSubgrid_driver(bounds_proc, & - urbanparams_inst, soilstate_inst, soilhydrology_inst, lakestate_inst, & + urbanparams_inst, soilstate_inst, soilhydrology_inst, & waterstate_inst, waterflux_inst, temperature_inst, energyflux_inst, & canopystate_inst, photosyns_inst, crop_inst, glc2lnd_inst, bgc_vegetation_inst, & soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, & @@ -173,7 +172,7 @@ subroutine dynSubgrid_driver(bounds_proc, ! OUTSIDE any loops over clumps in the driver. ! ! !USES: - use clm_varctl , only : use_cn, create_glacier_mec_landunit, use_ed + use clm_varctl , only : use_cn, use_fates use dynInitColumnsMod , only : initialize_new_columns use dynConsBiogeophysMod , only : dyn_hwcontent_init, dyn_hwcontent_final use dynEDMod , only : dyn_ED @@ -182,8 +181,7 @@ subroutine dynSubgrid_driver(bounds_proc, type(bounds_type) , intent(in) :: bounds_proc ! processor-level bounds type(urbanparams_type) , intent(in) :: urbanparams_inst type(soilstate_type) , intent(in) :: soilstate_inst - type(soilhydrology_type) , intent(in) :: soilhydrology_inst - type(lakestate_type) , intent(in) :: lakestate_inst + type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(waterstate_type) , intent(inout) :: waterstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst type(temperature_type) , intent(inout) :: temperature_inst @@ -223,7 +221,9 @@ subroutine dynSubgrid_driver(bounds_proc, call get_clump_bounds(nc, bounds_clump) call dyn_hwcontent_init(bounds_clump, & - urbanparams_inst, soilstate_inst, soilhydrology_inst, lakestate_inst, & + filter(nc)%num_nolakec, filter(nc)%nolakec, & + filter(nc)%num_lakec, filter(nc)%lakec, & + urbanparams_inst, soilstate_inst, soilhydrology_inst, & waterstate_inst, waterflux_inst, temperature_inst, energyflux_inst) call prior_weights%set_prior_weights(bounds_clump) @@ -258,15 +258,12 @@ subroutine dynSubgrid_driver(bounds_proc, call bgc_vegetation_inst%UpdateSubgridWeights(bounds_clump) - if (use_ed) then + if (use_fates) then call dyn_ED(bounds_clump) end if - if (create_glacier_mec_landunit) then - call glc2lnd_inst%update_glc2lnd_non_topo( & - bounds = bounds_clump, & - glc_behavior = glc_behavior) - end if + call glc2lnd_inst%update_glc2lnd_fracs( & + bounds = bounds_clump) ! ======================================================================== ! Do wrapup stuff after land cover change @@ -275,25 +272,32 @@ subroutine dynSubgrid_driver(bounds_proc, ! actually changed some weights in this time step. However, it doesn't do any harm ! (other than a small performance hit) to call this stuff all the time, so we do so ! for simplicity and safety. + ! + ! NOTE(wjs, 2017-02-24) I'm not positive that the above paragraph is 100% true. It + ! is at least *mostly* true, but there may be some subtleties, like resetting of + ! some variables, that are needed even in (some) time steps where we haven't + ! changed weights. ! ======================================================================== call dynSubgrid_wrapup_weight_changes(bounds_clump, glc_behavior) call patch_state_updater%set_new_weights(bounds_clump) - call column_state_updater%set_new_weights(bounds_clump) + call column_state_updater%set_new_weights(bounds_clump, nc) call set_subgrid_diagnostic_fields(bounds_clump) call initialize_new_columns(bounds_clump, & prior_weights%cactive(bounds_clump%begc:bounds_clump%endc), & - temperature_inst, waterstate_inst) + temperature_inst, waterstate_inst, soilhydrology_inst) call dyn_hwcontent_final(bounds_clump, & - urbanparams_inst, soilstate_inst, soilhydrology_inst, lakestate_inst, & + filter(nc)%num_nolakec, filter(nc)%nolakec, & + filter(nc)%num_lakec, filter(nc)%lakec, & + urbanparams_inst, soilstate_inst, soilhydrology_inst, & waterstate_inst, waterflux_inst, temperature_inst, energyflux_inst) if (use_cn) then - call bgc_vegetation_inst%DynamicAreaConservation(bounds_clump, & + call bgc_vegetation_inst%DynamicAreaConservation(bounds_clump, nc, & filter_inactive_and_active(nc)%num_soilp, filter_inactive_and_active(nc)%soilp, & filter_inactive_and_active(nc)%num_soilc, filter_inactive_and_active(nc)%soilc, & prior_weights, patch_state_updater, column_state_updater, & diff --git a/src/dyn_subgrid/dynVarMod.F90.in b/src/dyn_subgrid/dynVarMod.F90.in index de210cb76e..2cc14e669c 100644 --- a/src/dyn_subgrid/dynVarMod.F90.in +++ b/src/dyn_subgrid/dynVarMod.F90.in @@ -245,9 +245,9 @@ contains ! !USES: use ncdio_pio , only : ncd_inqvid, ncd_getatt, var_desc_t ! !ARGUMENTS: - class(dyn_var_type) , intent(in) :: this ! this object - character(len=*) , intent(in) :: attname ! name of the attribute - character(len=*) , intent(out) :: attvalue ! value of the attribute + class(dyn_var_type) , intent(inout):: this ! this object + character(len=*) , intent(in) :: attname ! name of the attribute + character(len=*) , intent(out) :: attvalue ! value of the attribute ! !LOCAL VARIABLES: integer :: varid ! variable id type(var_desc_t) :: vardesc ! variable descriptor diff --git a/src/dyn_subgrid/test/dynColumnStateUpdater_test/test_column_state_updater.pf b/src/dyn_subgrid/test/dynColumnStateUpdater_test/test_column_state_updater.pf index e2416b98e4..a9c456ab04 100644 --- a/src/dyn_subgrid/test/dynColumnStateUpdater_test/test_column_state_updater.pf +++ b/src/dyn_subgrid/test/dynColumnStateUpdater_test/test_column_state_updater.pf @@ -229,11 +229,11 @@ contains if (present(special_type)) then special_type = l_special_type end if - cs_updater = column_state_updater_type(bounds) + cs_updater = column_state_updater_type(bounds, nclumps=1) call cs_updater%set_old_weights(bounds) call this%set_new_lwtgcell(lwtgcell = lwtgcell_new) - call cs_updater%set_new_weights(bounds) + call cs_updater%set_new_weights(bounds, clump_index=1) end subroutine do_all_setup_with_two_vegetated_columns_and_special subroutine do_all_setup_two_veg_and_special_specialShrinks( & @@ -303,11 +303,11 @@ contains real(r8), intent(in) :: cwtlunit_new(:) call this%setup_gridcell_with_four_vegetated_columns(cwtlunit_old) - cs_updater = column_state_updater_type(bounds) + cs_updater = column_state_updater_type(bounds, nclumps=1) call cs_updater%set_old_weights(bounds) call this%set_new_cwtlunit(cwtlunit_new) - call cs_updater%set_new_weights(bounds) + call cs_updater%set_new_weights(bounds, clump_index=1) end subroutine do_all_setup_with_four_vegetated_columns @@ -380,7 +380,7 @@ contains myvar = [2._r8, 3._r8, 4._r8, 5._r8] expected = myvar - call cs_updater%update_column_state_no_special_handling(bounds, myvar) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar) @assertEqual(expected, myvar) end subroutine noSpecialHandling_noAreaChange @@ -408,7 +408,7 @@ contains cwtlunit_new(3) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar) ! Verify ! First make sure that the transformation is conservative; note that this looks at the @@ -449,7 +449,7 @@ contains cwtlunit_new(4) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar) ! Verify ! First make sure that the transformation is conservative; note that this looks at the @@ -482,12 +482,12 @@ contains call this%setup_three_gridcells_with_two_columns_each( & cwtlunit_grc1_old, cwtlunit_grc2_old, cwtlunit_grc3_old) - cs_updater = column_state_updater_type(bounds) + cs_updater = column_state_updater_type(bounds, nclumps=1) call cs_updater%set_old_weights(bounds) call this%set_new_cwtlunit(cwtlunit = & [cwtlunit_grc1_new, cwtlunit_grc2_new, cwtlunit_grc3_new]) - call cs_updater%set_new_weights(bounds) + call cs_updater%set_new_weights(bounds, clump_index=1) myvar = [1._r8, 2._r8, 3._r8, 4._r8, 5._r8, 6._r8] myvar_orig = myvar @@ -504,7 +504,7 @@ contains (cwtlunit_grc3_old(1) + g3_weight_change) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar) ! Verify ! First make sure that the transformation is conservative; note that this looks at the @@ -551,8 +551,8 @@ contains expected_non_conserved_mass = this%cwtgcell_new_minus_old(3) * input_from_glacier ! Exercise - call cs_updater%update_column_state_fill_special_using_natveg(bounds, myvar, & - non_conserved_mass_grc) + call cs_updater%update_column_state_fill_special_using_natveg(bounds, clump_index=1, var=myvar, & + non_conserved_mass_grc=non_conserved_mass_grc) ! Verify @assertEqual(expected_var, myvar, tolerance=tol) @@ -590,8 +590,8 @@ contains myvar(2) * this%cwtgcell_new_minus_old(2)) ! Exercise - call cs_updater%update_column_state_fill_special_using_natveg(bounds, myvar, & - non_conserved_mass_grc) + call cs_updater%update_column_state_fill_special_using_natveg(bounds, clump_index=1, var=myvar, & + non_conserved_mass_grc=non_conserved_mass_grc) ! Verify @assertEqual(expected_var, myvar, tolerance=tol) @@ -631,8 +631,8 @@ contains cwtlunit_new(3) ! Exercise - call cs_updater%update_column_state_fill_special_using_natveg(bounds, myvar, & - non_conserved_mass_grc) + call cs_updater%update_column_state_fill_special_using_natveg(bounds, clump_index=1, var=myvar, & + non_conserved_mass_grc=non_conserved_mass_grc) ! Verify ! First make sure that the transformation is conservative; note that this looks at the @@ -680,8 +680,8 @@ contains expected_non_conserved_mass = this%cwtgcell_new_minus_old(3) * input_from_special ! Exercise - call cs_updater%update_column_state_fill_using_fixed_values(bounds, myvar, & - landunit_values, non_conserved_mass_grc) + call cs_updater%update_column_state_fill_using_fixed_values(bounds, clump_index=1, var=myvar, & + landunit_values=landunit_values, non_conserved_mass_grc=non_conserved_mass_grc) ! Verify @assertEqual(expected_var, myvar, tolerance=tol) @@ -728,8 +728,8 @@ contains myvar(2) * this%cwtgcell_new_minus_old(2)) ! Exercise - call cs_updater%update_column_state_fill_using_fixed_values(bounds, myvar, & - landunit_values, non_conserved_mass_grc) + call cs_updater%update_column_state_fill_using_fixed_values(bounds, clump_index=1, var=myvar, & + landunit_values=landunit_values, non_conserved_mass_grc=non_conserved_mass_grc) ! Verify @assertEqual(expected_var, myvar, tolerance=tol) @@ -772,8 +772,8 @@ contains cwtlunit_new(3) ! Exercise - call cs_updater%update_column_state_fill_using_fixed_values(bounds, myvar, & - landunit_values, non_conserved_mass_grc) + call cs_updater%update_column_state_fill_using_fixed_values(bounds, clump_index=1, var=myvar, & + landunit_values=landunit_values, non_conserved_mass_grc=non_conserved_mass_grc) ! Verify ! First make sure that the transformation is conservative; note that this looks at the @@ -819,8 +819,8 @@ contains expected_non_conserved_mass = this%cwtgcell_new_minus_old(3) * input_from_special ! Exercise - call cs_updater%update_column_state_fill_special_using_fixed_value(bounds, myvar, & - input_from_special, non_conserved_mass_grc) + call cs_updater%update_column_state_fill_special_using_fixed_value(bounds, clump_index=1, var=myvar, & + special_value=input_from_special, non_conserved_mass_grc=non_conserved_mass_grc) ! Verify @assertEqual(expected_var, myvar, tolerance=tol) @@ -866,10 +866,10 @@ contains this%cwtgcell_new_minus_old(2) * fractional_area_old(3)) fractional_area_new(:) = fractional_area_old(:) - call cs_updater%update_column_state_no_special_handling(bounds, fractional_area_new) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=fractional_area_new) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar, & + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar, & fractional_area_old = fractional_area_old, & fractional_area_new = fractional_area_new) @@ -907,10 +907,10 @@ contains expected = myvar fractional_area_new(:) = fractional_area_old(:) - call cs_updater%update_column_state_no_special_handling(bounds, fractional_area_new) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=fractional_area_new) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar, & + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar, & fractional_area_old = fractional_area_old, & fractional_area_new = fractional_area_new) @@ -944,10 +944,10 @@ contains myvar_orig = myvar fractional_area_new(:) = fractional_area_old(:) - call cs_updater%update_column_state_no_special_handling(bounds, fractional_area_new) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=fractional_area_new) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar, & + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar, & fractional_area_old = fractional_area_old, & fractional_area_new = fractional_area_new) @@ -992,11 +992,11 @@ contains * input_from_special fractional_area_new(:) = fractional_area_old(:) - call cs_updater%update_column_state_no_special_handling(bounds, fractional_area_new) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=fractional_area_new) ! Exercise - call cs_updater%update_column_state_fill_special_using_fixed_value(bounds, myvar, & - input_from_special, non_conserved_mass_grc, & + call cs_updater%update_column_state_fill_special_using_fixed_value(bounds, clump_index=1, var=myvar, & + special_value=input_from_special, non_conserved_mass_grc=non_conserved_mass_grc, & fractional_area_old = fractional_area_old, & fractional_area_new = fractional_area_new) @@ -1038,11 +1038,11 @@ contains myvar(2) * this%cwtgcell_new_minus_old(2) * fractional_area_old(2)) fractional_area_new(:) = fractional_area_old(:) - call cs_updater%update_column_state_no_special_handling(bounds, fractional_area_new) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=fractional_area_new) ! Exercise - call cs_updater%update_column_state_fill_special_using_fixed_value(bounds, myvar, & - input_from_special, non_conserved_mass_grc, & + call cs_updater%update_column_state_fill_special_using_fixed_value(bounds, clump_index=1, var=myvar, & + special_value=input_from_special, non_conserved_mass_grc=non_conserved_mass_grc, & fractional_area_old = fractional_area_old, & fractional_area_new = fractional_area_new) @@ -1078,7 +1078,7 @@ contains myvar = [2._r8, 3._r8, 4._r8, 5._r8] - call cs_updater%update_column_state_no_special_handling(bounds, myvar, & + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar, & adjustment = adjustment) adjustment_expected(:) = 0._r8 @@ -1103,7 +1103,7 @@ contains myvar = [2._r8, 3._r8, 4._r8, 5._r8] myvar_orig = myvar - call cs_updater%update_column_state_no_special_handling(bounds, myvar, & + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar, & adjustment = adjustment) adjustment_expected(:) = 0._r8 @@ -1125,8 +1125,8 @@ contains myvar = [2._r8, 3._r8, 4._r8] - call cs_updater%update_column_state_fill_special_using_natveg(bounds, myvar, & - non_conserved_mass_grc, adjustment = adjustment) + call cs_updater%update_column_state_fill_special_using_natveg(bounds, clump_index=1, var=myvar, & + non_conserved_mass_grc = non_conserved_mass_grc, adjustment = adjustment) adjustment_expected(:) = 0._r8 @assertEqual(adjustment_expected, adjustment) @@ -1155,10 +1155,10 @@ contains adjustment(:) = 0._r8 fractional_area_new(:) = fractional_area_old(:) - call cs_updater%update_column_state_no_special_handling(bounds, fractional_area_new) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=fractional_area_new) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar, & + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar, & fractional_area_old = fractional_area_old, & fractional_area_new = fractional_area_new, & adjustment = adjustment) @@ -1197,10 +1197,10 @@ contains adjustment(:) = 0._r8 fractional_area_new(:) = fractional_area_old(:) - call cs_updater%update_column_state_no_special_handling(bounds, fractional_area_new) + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=fractional_area_new) ! Exercise - call cs_updater%update_column_state_no_special_handling(bounds, myvar, & + call cs_updater%update_column_state_no_special_handling(bounds, clump_index=1, var=myvar, & fractional_area_old = fractional_area_old, & fractional_area_new = fractional_area_new, & adjustment = adjustment) diff --git a/src/dyn_subgrid/test/dynInitColumns_test/test_init_columns.pf b/src/dyn_subgrid/test/dynInitColumns_test/test_init_columns.pf index ec756b9c63..88e916ffa1 100644 --- a/src/dyn_subgrid/test/dynInitColumns_test/test_init_columns.pf +++ b/src/dyn_subgrid/test/dynInitColumns_test/test_init_columns.pf @@ -14,6 +14,7 @@ module test_init_columns use shr_kind_mod , only : r8 => shr_kind_r8 use TemperatureType , only : temperature_type use WaterstateType , only : waterstate_type + use SoilHydrologyType, only : soilhydrology_type use dynColumnTemplateMod, only : TEMPLATE_NONE_FOUND implicit none @@ -29,6 +30,7 @@ module test_init_columns ! into setup & teardown methods of the class. type(temperature_type) :: temperature_vars type(waterstate_type) :: waterstate_vars + type(soilhydrology_type) :: soilhydrology_vars contains @@ -77,17 +79,23 @@ contains allocate(waterstate_vars%h2osoi_liq_col(bounds%begc:bounds%endc, -nlevsno+1:nlevgrnd)) allocate(waterstate_vars%h2osoi_ice_col(bounds%begc:bounds%endc, -nlevsno+1:nlevgrnd)) allocate(waterstate_vars%h2osoi_vol_col(bounds%begc:bounds%endc, -nlevsno+1:nlevgrnd)) + allocate(soilhydrology_vars%wa_col(bounds%begc:bounds%endc)) do lev = -nlevsno+1, nlevgrnd do c = bounds%begc, bounds%endc temperature_vars%t_soisno_col(c, lev) = c*1000 + lev - ! Also need to initialize some waterstateType variables, but we don't have any + ! Also need to initialize some waterstate_type variables, but we don't have any ! assertions on them in this test waterstate_vars%h2osoi_liq_col(c, lev) = 0._r8 waterstate_vars%h2osoi_ice_col(c, lev) = 0._r8 waterstate_vars%h2osoi_vol_col(c, lev) = 0._r8 end do end do + + ! Also need to initialize some other variables for which we don't have any assertions + do c = bounds%begc, bounds%endc + soilhydrology_vars%wa_col(c) = 0._r8 + end do end subroutine setup subroutine cleanup() @@ -100,7 +108,8 @@ contains deallocate(waterstate_vars%h2osoi_liq_col) deallocate(waterstate_vars%h2osoi_ice_col) deallocate(waterstate_vars%h2osoi_vol_col) - + deallocate(soilhydrology_vars%wa_col) + end subroutine cleanup ! ------------------------------------------------------------------------ @@ -156,7 +165,8 @@ contains cactive_prior(lun%coli(l2)+1) = .false. col%active(lun%coli(l2)+2) = .false. t_soisno_expected = temperature_vars%t_soisno_col - call initialize_new_columns(bounds, cactive_prior, temperature_vars, waterstate_vars) + call initialize_new_columns(bounds, cactive_prior, & + temperature_vars, waterstate_vars, soilhydrology_vars) @assertEqual(t_soisno_expected, temperature_vars%t_soisno_col) call cleanup() end subroutine test_initialize_new_columns_none @@ -172,7 +182,8 @@ contains ! all cactive_prior points were false, so there's nothing to use as a template: cactive_prior(:) = .false. t_soisno_expected = temperature_vars%t_soisno_col - call initialize_new_columns(bounds, cactive_prior, temperature_vars, waterstate_vars) + call initialize_new_columns(bounds, cactive_prior, & + temperature_vars, waterstate_vars, soilhydrology_vars) @assertEqual(t_soisno_expected, temperature_vars%t_soisno_col) call cleanup() end subroutine test_initialize_new_columns_TEMPLATE_NONE_FOUND @@ -198,7 +209,8 @@ contains ! copied: t_soisno_expected(dest_col,1:) = temperature_vars%t_soisno_col(source_col,1:) - call initialize_new_columns(bounds, cactive_prior, temperature_vars, waterstate_vars) + call initialize_new_columns(bounds, cactive_prior, & + temperature_vars, waterstate_vars, soilhydrology_vars) @assertEqual(t_soisno_expected, temperature_vars%t_soisno_col) call cleanup() diff --git a/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights.pf b/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights.pf index 8e2c5acd91..4cc250320b 100644 --- a/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights.pf +++ b/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights.pf @@ -6,7 +6,7 @@ module test_update_landunit_weights use unittestSubgridMod use dynLandunitAreaMod use shr_kind_mod , only : r8 => shr_kind_r8 - use landunit_varcon , only : istsoil, istcrop, istice, istice_mec, istdlak, istwet + use landunit_varcon , only : istsoil, istcrop, istice_mec, istdlak, istwet use landunit_varcon , only : isturb_tbd, isturb_hd, isturb_md use GridcellType , only : grc use LandunitType , only : lun diff --git a/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights_one_gcell.pf b/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights_one_gcell.pf index d28bf78295..f0563130f3 100644 --- a/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights_one_gcell.pf +++ b/src/dyn_subgrid/test/dynLandunitArea_test/test_update_landunit_weights_one_gcell.pf @@ -4,7 +4,7 @@ module test_update_landunit_weights_one_gcell use pfunit_mod use dynLandunitAreaMod - use landunit_varcon, only : istsoil, istcrop, isturb_md, istice, istice_mec, max_lunit + use landunit_varcon, only : istsoil, istcrop, isturb_md, istice_mec, istdlak, max_lunit use shr_kind_mod , only : r8 => shr_kind_r8 @@ -19,7 +19,8 @@ contains ! Create default version of the landunit weights real(r8), dimension(max_lunit), allocatable :: create_landunit_weights(:) - create_landunit_weights = [.25_r8, .2_r8, .16_r8, .14_r8, .08_r8, .06_r8, .05_r8, .04_r8, .02_r8] + ! Landunit 3 (previously istice) is currently unused, so set its area to 0. + create_landunit_weights = [.25_r8, .2_r8, 0._r8, .3_r8, .08_r8, .06_r8, .05_r8, .04_r8, .02_r8] end function create_landunit_weights @Test @@ -105,11 +106,10 @@ contains landunit_weights = create_landunit_weights() landunit_weights(istice_mec) = 0.99_r8 - ! In the following, we assume that the last element of decrease_order is istice (not - ! to be confused with istice_mec) + ! In the following, we assume that the last element of decrease_order is istdlak expected(:) = 0._r8 expected(istice_mec) = 0.99_r8 - expected(istice) = 0.01_r8 + expected(istdlak) = 0.01_r8 call update_landunit_weights_one_gcell(landunit_weights) @assertEqual(expected, landunit_weights, tolerance=tol) diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 0d568427be..5547f9317b 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -8,7 +8,7 @@ module ColumnType ! -------------------------------------------------------- ! 1 => (istsoil) soil (vegetated or bare soil) ! 2 => (istcrop) crop (only for crop configuration) - ! 3 => (istice) land ice + ! 3 => (UNUSED) (formerly non-multiple elevation class land ice; currently unused) ! 4 => (istice_mec) land ice (multiple elevation classes) ! 5 => (istdlak) deep lake ! 6 => (istwet) wetland @@ -24,6 +24,8 @@ module ColumnType use clm_varcon , only : spval, ispval use shr_sys_mod , only : shr_sys_abort use clm_varctl , only : iulog + use column_varcon , only : is_hydrologically_active + use LandunitType , only : lun ! ! !PUBLIC TYPES: implicit none @@ -74,6 +76,9 @@ module ColumnType ! for init_interp, add information on relative position ! real(r8), pointer :: relative_position (:) ! relative position of column along hillslope + ! other column characteristics + logical , pointer :: hydrologically_active(:) ! true if this column is a hydrologically active type + ! levgrnd_class gives the class in which each layer falls. This is relevant for ! columns where there are 2 or more fundamentally different layer types. For ! example, this distinguishes between soil and bedrock layers. The particular value @@ -142,6 +147,8 @@ subroutine Init(this, begc, endc) allocate(this%n_melt (begc:endc)) ; this%n_melt (:) = nan allocate(this%topo_slope (begc:endc)) ; this%topo_slope (:) = nan allocate(this%topo_std (begc:endc)) ; this%topo_std (:) = nan + allocate(this%hydrologically_active(begc:endc)) ; this%hydrologically_active(:) = .false. + end subroutine Init !------------------------------------------------------------------------ @@ -175,6 +182,7 @@ subroutine Clean(this) deallocate(this%topo_std ) deallocate(this%nbedrock ) deallocate(this%levgrnd_class) + deallocate(this%hydrologically_active) deallocate(this%colu ) deallocate(this%cold ) end subroutine Clean @@ -192,12 +200,18 @@ subroutine update_itype(this, c, itype) integer, intent(in) :: itype ! ! !LOCAL VARIABLES: + integer :: l character(len=*), parameter :: subname = 'update_itype' !----------------------------------------------------------------------- + l = col%landunit(c) + if (col%type_is_dynamic(c)) then col%itype(c) = itype + col%hydrologically_active(c) = is_hydrologically_active( & + col_itype = itype, & + lun_itype = lun%itype(l)) else write(iulog,*) subname//' ERROR: attempt to update itype when type_is_dynamic is false' write(iulog,*) 'c, col%itype(c), itype = ', c, col%itype(c), itype diff --git a/src/main/GetGlobalValuesMod.F90 b/src/main/GetGlobalValuesMod.F90 index e84823b9ea..3cd1f9a306 100644 --- a/src/main/GetGlobalValuesMod.F90 +++ b/src/main/GetGlobalValuesMod.F90 @@ -30,7 +30,7 @@ integer function GetGlobalIndex(decomp_index, clmlevel) use spmdMod , only: iam use clm_varcon , only: nameg, namel, namec, namep use clm_varctl , only: iulog - use mct_mod , only: mct_gsMap, mct_gsmap_op + use mct_mod , only: mct_gsMap, mct_gsMap_orderedPoints use shr_sys_mod, only: shr_sys_abort ! ! Arguments @@ -60,7 +60,7 @@ integer function GetGlobalIndex(decomp_index, clmlevel) end if call get_clmlevel_gsmap(clmlevel=trim(clmlevel), gsmap=gsmap) - call mct_gsmap_op(gsmap, iam, gsmap_ordered) + call mct_gsMap_orderedPoints(gsmap, iam, gsmap_ordered) GetGlobalIndex = gsmap_ordered(decomp_index - beg_index + 1) deallocate(gsmap_ordered) diff --git a/src/main/GridcellType.F90 b/src/main/GridcellType.F90 index 9d1e5aeb40..0b7920a57a 100644 --- a/src/main/GridcellType.F90 +++ b/src/main/GridcellType.F90 @@ -27,6 +27,7 @@ module GridcellType real(r8), pointer :: lon (:) ! longitude (radians) real(r8), pointer :: latdeg (:) ! latitude (degrees) real(r8), pointer :: londeg (:) ! longitude (degrees) + logical , pointer :: active (:) ! just needed for symmetry with other subgrid types integer, pointer :: nbedrock (:) ! index of uppermost bedrock layer integer, pointer :: ncolumns (:) ! number of columns per hillslope @@ -69,6 +70,7 @@ subroutine Init(this, begg, endg) allocate(this%lon (begg:endg)) ; this%lon (:) = nan allocate(this%latdeg (begg:endg)) ; this%latdeg (:) = nan allocate(this%londeg (begg:endg)) ; this%londeg (:) = nan + allocate(this%active (begg:endg)) ; this%active (:) = .true. allocate(this%nbedrock (begg:endg)) ; this%nbedrock (:) = ispval allocate(this%ncolumns (begg:endg)); this%ncolumns (:) = ispval @@ -94,6 +96,7 @@ subroutine Clean(this) deallocate(this%lon ) deallocate(this%latdeg ) deallocate(this%londeg ) + deallocate(this%active ) deallocate(this%nbedrock ) deallocate(this%ncolumns ) deallocate(this%max_dayl ) diff --git a/src/main/LandunitType.F90 b/src/main/LandunitType.F90 index d800f03d91..01c79d2bb9 100644 --- a/src/main/LandunitType.F90 +++ b/src/main/LandunitType.F90 @@ -8,7 +8,7 @@ module LandunitType ! -------------------------------------------------------- ! 1 => (istsoil) soil (vegetated or bare soil landunit) ! 2 => (istcrop) crop (only for crop configuration) - ! 3 => (istice) land ice + ! 3 => (UNUSED) (formerly non-multiple elevation class land ice; currently unused) ! 4 => (istice_mec) land ice (multiple elevation classes) ! 5 => (istdlak) deep lake ! 6 => (istwet) wetland diff --git a/src/main/PatchType.F90 b/src/main/PatchType.F90 index cc52e1822c..d00f5588b0 100644 --- a/src/main/PatchType.F90 +++ b/src/main/PatchType.F90 @@ -90,7 +90,7 @@ module PatchType use shr_kind_mod , only : r8 => shr_kind_r8 use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use clm_varcon , only : ispval - use clm_varctl , only : use_ed + use clm_varctl , only : use_fates ! ! !PUBLIC TYPES: implicit none @@ -112,11 +112,20 @@ module PatchType integer , pointer :: mxy (:) ! m index for laixy(i,j,m),etc. (undefined for special landunits) logical , pointer :: active (:) ! true=>do computations on this patch - ! ED only - logical , pointer :: is_veg (:) + ! fates only + logical , pointer :: is_veg (:) ! This is an ACTIVE fates patch logical , pointer :: is_bareground (:) real(r8), pointer :: wt_ed (:) !TODO mv ? can this be removed + + logical, pointer :: is_fates (:) ! true for patch vector space reserved + ! for FATES. + ! this is static and is true for all + ! patches within fates jurisdiction + ! including patches which are not currently + ! associated with a FATES linked-list patch + + contains procedure, public :: Init @@ -157,11 +166,11 @@ subroutine Init(this, begp, endp) ! is used in RootBiogeophysMod in zeng2001_rootfr- a filter is not used ! in that routine - which would elimate this problem - ! if (.not. use_ed) then allocate(this%itype (begp:endp)); this%itype (:) = ispval - ! end if - if (use_ed) then + allocate(this%is_fates (begp:endp)); this%is_fates (:) = .false. + + if (use_fates) then allocate(this%is_veg (begp:endp)); this%is_veg (:) = .false. allocate(this%is_bareground (begp:endp)); this%is_bareground (:) = .false. allocate(this%wt_ed (begp:endp)); this%wt_ed (:) = nan @@ -185,8 +194,9 @@ subroutine Clean(this) deallocate(this%itype ) deallocate(this%mxy ) deallocate(this%active ) - - if (use_ed) then + deallocate(this%is_fates) + + if (use_fates) then deallocate(this%is_veg) deallocate(this%is_bareground) deallocate(this%wt_ed) diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index 5d198903d2..9841f59b92 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -13,7 +13,6 @@ module TopoMod use LandunitType , only : lun use glc2lndMod , only : glc2lnd_type use glcBehaviorMod , only : glc_behavior_type - use clm_varctl , only : create_glacier_mec_landunit use landunit_varcon, only : istice_mec use filterColMod , only : filter_col_type, col_filter_from_logical_array_active_only ! @@ -198,7 +197,7 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & ! ! Should be called each time step. ! - ! Should be called after glc2lndMod:update_glc2lnd_non_topo, and before + ! Should be called after glc2lndMod:update_glc2lnd_fracs, and before ! atm2lndMod:downscale_forcings ! ! !ARGUMENTS: @@ -228,11 +227,11 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & call glc_behavior%icemec_cols_need_downscaling(bounds, num_icemecc, filter_icemecc, & this%needs_downscaling_col(begc:endc)) - if (create_glacier_mec_landunit) then - call glc2lnd_inst%update_glc2lnd_topo(bounds, & - this%topo_col(begc:endc), & - this%needs_downscaling_col(begc:endc)) - end if + ! In addition to updating topo_col, this also sets some additional elements of + ! needs_downscaling_col to .true. (but leaves the already-.true. values as is.) + call glc2lnd_inst%update_glc2lnd_topo(bounds, & + this%topo_col(begc:endc), & + this%needs_downscaling_col(begc:endc)) ! For any point that isn't downscaled, set its topo value to the atmosphere's ! topographic height. This shouldn't matter, but is useful if topo_col is written to @@ -248,9 +247,7 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & end if end do - if (create_glacier_mec_landunit) then - call glc_behavior%update_glc_classes(bounds, this%topo_col(begc:endc)) - end if + call glc_behavior%update_glc_classes(bounds, this%topo_col(begc:endc)) end subroutine UpdateTopo diff --git a/src/main/accumulMod.F90 b/src/main/accumulMod.F90 index 59cb26ec58..29a52ceb52 100644 --- a/src/main/accumulMod.F90 +++ b/src/main/accumulMod.F90 @@ -9,7 +9,7 @@ module accumulMod ! Subroutine [init_accumulator] defines the values of the accumulated ! field data structure. Subroutine [update_accum_field] does ! the actual accumulation for a given field. - ! Four types of accumulations are possible: + ! Three types of accumulations are possible: ! - Average over time interval. Time average fields are only ! valid at the end of the averaging interval. ! - Running mean over time interval. Running means are valid once the @@ -19,9 +19,17 @@ module accumulMod ! the accumulation to zero. ! ! !USES: +#include "shr_assert.h" use shr_kind_mod, only: r8 => shr_kind_r8 use shr_sys_mod , only: shr_sys_abort - use clm_varctl , only: iulog + use shr_log_mod , only: errMsg => shr_log_errMsg + use abortutils , only: endrun + use clm_varctl , only: iulog, nsrest, nsrStartup + use clm_varcon , only: spval, ispval + use PatchType , only : patch + use ColumnType , only : col + use LandunitType, only : lun + use GridcellType, only : grc ! ! !PUBLIC TYPES: implicit none @@ -33,6 +41,7 @@ module accumulMod public :: print_accum_fields ! Print info about accumulator fields public :: extract_accum_field ! Extracts the current value of an accumulator field public :: update_accum_field ! Update the current value of an accumulator field + public :: clean_accum_fields ! Deallocate space and reset accum fields list interface extract_accum_field module procedure extract_accum_field_sl ! Extract current val of single-level accumulator field @@ -44,29 +53,77 @@ module accumulMod end interface private ! + ! !PRIVATE MEMBER FUNCTIONS: + private :: extract_accum_field_basic ! Extract values for one level of the given field + private :: extract_accum_field_timeavg ! Extract values for one level of the given timeavg field + private :: update_accum_field_timeavg ! Update values for one level of the given timeavg field + private :: update_accum_field_runmean ! Update values for one level of the given runmean field + private :: update_accum_field_runaccum ! Update values for one level of the given runaccum field + private :: find_field ! Find field index given field name + private :: acctype_to_string ! Return a string representation of an ACCTYPE parameter + ! ! !PRIVATE TYPES: + type accum_field character(len= 8) :: name !field name character(len=128) :: desc !field description character(len= 8) :: units !field units - character(len= 8) :: acctype !accumulation type: ["timeavg","runmean","runaccum"] + integer :: acctype !accumulation type (see ACCTYPE parameters below) character(len= 8) :: type1d !subgrid type: ["gridcell","landunit","column" or "pft"] character(len= 8) :: type2d !type2d ('','levsoi','numrad',..etc. ) integer :: beg1d !subgrid type beginning index integer :: end1d !subgrid type ending index - integer :: num1d !total subgrid points integer :: numlev !number of vertical levels in field + logical, pointer :: active(:)!whether each point (patch, column, etc.) is active real(r8) :: initval !initial value of accumulated field real(r8), pointer :: val(:,:) !accumulated field integer :: period !field accumulation period (in model time steps) + + ! In most cases, we could use a 1-d nsteps variable. However, that's awkward within + ! nested loops (with level as the outer loop); also, runaccum can theoretically have + ! different reset points for different levels. + integer, pointer :: nsteps(:,:)!number of steps each point has accumulated, since last reset time + + ! NOTE(wjs, 2017-12-03) We should convert this to fully object-oriented (with + ! inheritance / polymorphism). For now, in the interest of time, I'm going with a + ! semi-object-oriented solution of using procedure pointers. + procedure(extract_accum_field_interface), pointer :: extract_accum_field_func + procedure(update_accum_field_interface) , pointer :: update_accum_field_func end type accum_field + abstract interface + subroutine extract_accum_field_interface(this, level, nstep, field) + use shr_kind_mod, only: r8 => shr_kind_r8 + import :: accum_field + class(accum_field), intent(in) :: this + integer, intent(in) :: level ! level index to extract (1 for a 1-d field) + integer, intent(in) :: nstep ! timestep index + real(r8), intent(inout) :: field(:) ! field values for current time step + end subroutine extract_accum_field_interface + + subroutine update_accum_field_interface(this, level, nstep, field) + use shr_kind_mod, only: r8 => shr_kind_r8 + import :: accum_field + class(accum_field), intent(in) :: this + integer, intent(in) :: level ! level index to update (1 for a 1-d field) + integer, intent(in) :: nstep ! timestep index + real(r8), intent(in) :: field(:) ! field values for current time step + end subroutine update_accum_field_interface + end interface + real(r8), parameter, public :: accumResetVal = -99999._r8 ! used to do an annual reset ( put in for bug 1858) + integer, parameter :: ACCTYPE_TIMEAVG = 1 + integer, parameter :: ACCTYPE_RUNMEAN = 2 + integer, parameter :: ACCTYPE_RUNACCUM = 3 + integer, parameter :: max_accum = 100 !maximum number of accumulated fields type (accum_field) :: accum(max_accum) !array accumulated fields integer :: naccflds = 0 !accumulator field counter + character(len=*), parameter, private :: sourcefile = & + __FILE__ + !------------------------------------------------------------------------ contains @@ -84,17 +141,24 @@ subroutine init_accum_field (name, units, desc, & ! o accumulation period for accumulated field (in iterations) ! o initial value of accumulated field ! + ! Note about initial value: This must be 0 for a timeavg or runaccum field. For a + ! runmean field, initializing to a non-zero value often won't accomplish anything, but + ! can be used to start with a reasonable value in situations such as: (1) the field is + ! extracted before the first update call; (2) edge case situations such as doing a + ! branch run from a restart file that did not contain this field (though it's + ! possible that init_value doesn't matter even in this case). + ! ! !USES: use shr_const_mod, only: SHR_CONST_CDAY use clm_time_manager, only : get_step_size - use decompMod, only : get_proc_bounds, get_proc_global + use decompMod, only : get_proc_bounds ! ! !ARGUMENTS: implicit none character(len=*), intent(in) :: name !field name character(len=*), intent(in) :: units !field units character(len=*), intent(in) :: desc !field description - character(len=*), intent(in) :: accum_type !field type: tavg, runm, runa, ins + character(len=*), intent(in) :: accum_type !field type: timeavg, runmean, runaccum integer , intent(in) :: accum_period !field accumulation period character(len=*), intent(in) :: subgrid_type !["gridcell","landunit","column" or "patch"] integer , intent(in) :: numlev !number of vertical levels @@ -104,24 +168,17 @@ subroutine init_accum_field (name, units, desc, & ! !LOCAL VARIABLES: integer :: nf ! field index integer :: beg1d,end1d ! beggining and end subgrid indices - integer :: num1d ! total number subgrid indices integer :: begp, endp ! per-proc beginning and ending patch indices integer :: begc, endc ! per-proc beginning and ending column indices integer :: begl, endl ! per-proc beginning and ending landunit indices integer :: begg, endg ! per-proc gridcell ending gridcell indices integer :: begCohort, endCohort ! per-proc beg end cohort indices - integer :: numg ! total number of gridcells across all processors - integer :: numl ! total number of landunits across all processors - integer :: numc ! total number of columns across all processors - integer :: nump ! total number of patches across all processors - integer :: numCohort ! total number of cohorts across all processors !------------------------------------------------------------------------ ! Determine necessary indices call get_proc_bounds(begg, endg, begl, endl, begc, endc, begp, endp, & begCohort, endCohort ) - call get_proc_global(numg, numl, numc, nump, numCohort) ! update field index ! Consistency check that number of accumulated does not exceed maximum. @@ -134,14 +191,31 @@ subroutine init_accum_field (name, units, desc, & end if nf = naccflds - ! Note accumulation period must be converted from days - ! to number of iterations + select case (trim(accum_type)) + case ('timeavg') + accum(nf)%acctype = ACCTYPE_TIMEAVG + accum(nf)%extract_accum_field_func => extract_accum_field_timeavg + accum(nf)%update_accum_field_func => update_accum_field_timeavg + case ('runmean') + accum(nf)%acctype = ACCTYPE_RUNMEAN + accum(nf)%extract_accum_field_func => extract_accum_field_basic + accum(nf)%update_accum_field_func => update_accum_field_runmean + case ('runaccum') + accum(nf)%acctype = ACCTYPE_RUNACCUM + accum(nf)%extract_accum_field_func => extract_accum_field_basic + accum(nf)%update_accum_field_func => update_accum_field_runaccum + case default + write(iulog,*) 'init_accum_field ERROR: unknown accum_type ', accum_type + call shr_sys_abort('init_accum_field: unknown accum_type') + end select accum(nf)%name = trim(name) accum(nf)%units = trim(units) accum(nf)%desc = trim(desc) - accum(nf)%acctype = trim(accum_type) accum(nf)%initval = init_value + + ! Note accumulation period must be converted from days + ! to number of iterations accum(nf)%period = accum_period if (accum(nf)%period < 0) then accum(nf)%period = -accum(nf)%period * nint(SHR_CONST_CDAY) / get_step_size() @@ -151,28 +225,27 @@ subroutine init_accum_field (name, units, desc, & case ('gridcell') beg1d = begg end1d = endg - num1d = numg + accum(nf)%active => grc%active case ('landunit') beg1d = begl end1d = endl - num1d = numl + accum(nf)%active => lun%active case ('column') beg1d = begc end1d = endc - num1d = numc + accum(nf)%active => col%active case ('pft') beg1d = begp end1d = endp - num1d = nump + accum(nf)%active => patch%active case default - write(iulog,*)'ACCUMULINIT: unknown subgrid type ',subgrid_type + write(iulog,*)'init_accum_field: unknown subgrid type ',subgrid_type call shr_sys_abort () end select accum(nf)%type1d = trim(subgrid_type) accum(nf)%beg1d = beg1d accum(nf)%end1d = end1d - accum(nf)%num1d = num1d accum(nf)%numlev = numlev if (present(type2d)) then @@ -184,7 +257,18 @@ subroutine init_accum_field (name, units, desc, & ! Allocate and initialize accumulation field allocate(accum(nf)%val(beg1d:end1d,numlev)) - accum(nf)%val(beg1d:end1d,numlev) = init_value + if (accum(nf)%acctype == ACCTYPE_TIMEAVG .or. & + accum(nf)%acctype == ACCTYPE_RUNACCUM) then + if (init_value /= 0._r8) then + write(iulog,*) 'init_accum_field ERROR: for field ', trim(name) + write(iulog,*) 'init_value must be 0 for timeavg and runaccum fields' + call shr_sys_abort('init_accum_field: init_value must be 0 for timeavg and runaccum fields') + end if + end if + accum(nf)%val(beg1d:end1d,1:numlev) = init_value + + allocate(accum(nf)%nsteps(beg1d:end1d,numlev)) + accum(nf)%nsteps(beg1d:end1d,1:numlev) = 0 end subroutine init_accum_field @@ -213,11 +297,13 @@ subroutine print_accum_fields() do nf = 1, naccflds if (accum(nf)%period /= huge(1)) then write(iulog,1003) nf,accum(nf)%name,accum(nf)%units,& - accum(nf)%acctype, accum(nf)%period, accum(nf)%initval, & + acctype_to_string(accum(nf)%acctype), & + accum(nf)%period, accum(nf)%initval, & accum(nf)%desc else write(iulog,1004) nf,accum(nf)%name,accum(nf)%units,& - accum(nf)%acctype, accum(nf)%initval, accum(nf)%desc + acctype_to_string(accum(nf)%acctype), & + accum(nf)%initval, accum(nf)%desc endif end do write(iulog,'(72a1)') ("_",i=1,71) @@ -244,7 +330,6 @@ subroutine extract_accum_field_sl (name, field, nstep) ! is assigned to indicate the time average is not yet valid. ! ! !USES: - use clm_varcon, only : spval, ispval ! ! !ARGUMENTS: implicit none @@ -253,44 +338,21 @@ subroutine extract_accum_field_sl (name, field, nstep) integer , intent(in) :: nstep !timestep index ! ! !LOCAL VARIABLES: - integer :: i,k,nf !indices - integer :: beg,end !subgrid beginning,ending indices - !------------------------------------------------------------------------ - - ! find field index. return if "name" is not on list - - nf = 0 - do i = 1, naccflds - if (name == accum(i)%name) nf = i - end do - if (nf == 0) then - write(iulog,*) 'EXTRACT_ACCUM_FIELD_SL error: field name ',name,' not found' - call shr_sys_abort - endif + integer :: nf ! field index + integer :: numlev ! number of vertical levels - ! error check + character(len=*), parameter :: subname = 'extract_accum_field_sl' + !------------------------------------------------------------------------ - beg = accum(nf)%beg1d - end = accum(nf)%end1d - if (size(field,dim=1) /= end-beg+1) then - write(iulog,*)'ERROR in extract_accum_field for field ',accum(nf)%name - write(iulog,*)'size of first dimension of field is ',& - size(field,dim=1),' and should be ',end-beg+1 - call shr_sys_abort - endif + call find_field(field_name=name, caller_name=subname, field_index=nf) - ! extract field + numlev = accum(nf)%numlev + SHR_ASSERT(numlev == 1, errMsg(sourcefile, __LINE__)) - if (accum(nf)%acctype == 'timeavg' .and. & - mod(nstep,accum(nf)%period) /= 0) then - do k = beg,end - field(k) = spval !assign absurd value when avg not ready - end do - else - do k = beg,end - field(k) = accum(nf)%val(k,1) - end do - end if + call accum(nf)%extract_accum_field_func( & + level = 1, & + nstep = nstep, & + field = field) end subroutine extract_accum_field_sl @@ -304,9 +366,6 @@ subroutine extract_accum_field_ml (name, field, nstep) ! the field type is a time average. In this case, an absurd value ! is assigned to indicate the time average is not yet valid. ! - ! !USES: - use clm_varcon, only : spval - ! ! !ARGUMENTS: implicit none character(len=*), intent(in) :: name !field name @@ -314,57 +373,90 @@ subroutine extract_accum_field_ml (name, field, nstep) integer, intent(in) :: nstep !timestep index ! ! !LOCAL VARIABLES: - integer :: i,j,k,nf !indices - integer :: beg,end !subgrid beginning,ending indices + integer :: j,nf !indices integer :: numlev !number of vertical levels + + character(len=*), parameter :: subname = 'extract_accum_field_ml' !------------------------------------------------------------------------ - ! find field index. return if "name" is not on list + call find_field(field_name=name, caller_name=subname, field_index=nf) - nf = 0 - do i = 1, naccflds - if (name == accum(i)%name) nf = i + numlev = accum(nf)%numlev + SHR_ASSERT((size(field, 2) == numlev), errMsg(sourcefile, __LINE__)) + + do j = 1,numlev + call accum(nf)%extract_accum_field_func( & + level = j, & + nstep = nstep, & + field = field(:,j)) end do - if (nf == 0) then - write(iulog,*) 'EXTRACT_ACCUM_FIELD_ML error: field name ',name,' not found' - call shr_sys_abort - endif - ! error check + end subroutine extract_accum_field_ml - numlev = accum(nf)%numlev - beg = accum(nf)%beg1d - end = accum(nf)%end1d - if (size(field,dim=1) /= end-beg+1) then - write(iulog,*)'ERROR in extract_accum_field for field ',accum(nf)%name - write(iulog,*)'size of first dimension of field is ',& - size(field,dim=1),' and should be ',end-beg+1 - call shr_sys_abort - else if (size(field,dim=2) /= numlev) then - write(iulog,*)'ERROR in extract_accum_field for field ',accum(nf)%name - write(iulog,*)'size of second dimension of field iis ',& - size(field,dim=2),' and should be ',numlev - call shr_sys_abort - endif + !----------------------------------------------------------------------- + subroutine extract_accum_field_basic(this, level, nstep, field) + ! !DESCRIPTION: + ! Extract values for one level of the given field + ! + ! !ARGUMENTS: + class(accum_field), intent(in) :: this + integer, intent(in) :: level ! level index to extract (1 for a 1-d field) + integer, intent(in) :: nstep ! timestep index + real(r8), intent(inout) :: field(:) ! field values for current time step + ! + ! !LOCAL VARIABLES: + integer :: begi,endi !subgrid beginning,ending indices + integer :: k, kf + + character(len=*), parameter :: subname = 'extract_accum_field_basic' + !----------------------------------------------------------------------- - !extract field + begi = this%beg1d + endi = this%end1d + SHR_ASSERT((size(field) == endi-begi+1), errMsg(sourcefile, __LINE__)) - if (accum(nf)%acctype == 'timeavg' .and. & - mod(nstep,accum(nf)%period) /= 0) then - do j = 1,numlev - do k = beg,end - field(k,j) = spval !assign absurd value when avg not ready - end do + do k = begi, endi + kf = k - begi + 1 + field(kf) = this%val(k,level) + end do + + end subroutine extract_accum_field_basic + + !----------------------------------------------------------------------- + subroutine extract_accum_field_timeavg(this, level, nstep, field) + ! !DESCRIPTION: + ! Extract values for one level of the given timeavg field + ! + ! !ARGUMENTS: + class(accum_field), intent(in) :: this + integer, intent(in) :: level ! level index to extract (1 for a 1-d field) + integer, intent(in) :: nstep ! timestep index + real(r8), intent(inout) :: field(:) ! field values for current time step + ! + ! !LOCAL VARIABLES: + integer :: begi,endi !subgrid beginning,ending indices + integer :: k, kf + + character(len=*), parameter :: subname = 'extract_accum_field_basic' + !----------------------------------------------------------------------- + + begi = this%beg1d + endi = this%end1d + SHR_ASSERT((size(field) == endi-begi+1), errMsg(sourcefile, __LINE__)) + + if (mod(nstep,this%period) == 0) then + do k = begi, endi + kf = k - begi + 1 + field(kf) = this%val(k,level) end do else - do j = 1,numlev - do k = beg,end - field(k,j) = accum(nf)%val(k,j) - end do + do k = begi, endi + kf = k - begi + 1 + field(kf) = spval end do end if - end subroutine extract_accum_field_ml + end subroutine extract_accum_field_timeavg !------------------------------------------------------------------------ subroutine update_accum_field_sl (name, field, nstep) @@ -373,6 +465,9 @@ subroutine update_accum_field_sl (name, field, nstep) ! Accumulate single level field over specified time interval. ! The appropriate field is accumulated in the array [accval]. ! + ! Values of 'field' are ignored in inactive points, so it's safe for 'field' to + ! contain garbage in inactive points. + ! ! !ARGUMENTS: implicit none character(len=*), intent(in) :: name !field name @@ -380,82 +475,21 @@ subroutine update_accum_field_sl (name, field, nstep) integer , intent(in) :: nstep !time step index ! ! !LOCAL VARIABLES: - integer :: i,k,nf !indices - integer :: accper !temporary accumulation period - integer :: beg,end !subgrid beginning,ending indices - !------------------------------------------------------------------------ - - ! find field index. return if "name" is not on list - - nf = 0 - do i = 1, naccflds - if (name == accum(i)%name) nf = i - end do - if (nf == 0) then - write(iulog,*) 'UPDATE_ACCUM_FIELD_SL error: field name ',name,' not found' - call shr_sys_abort - endif + integer :: nf ! field index + integer :: numlev ! number of vertical levels - ! error check - - beg = accum(nf)%beg1d - end = accum(nf)%end1d - if (size(field,dim=1) /= end-beg+1) then - write(iulog,*)'ERROR in UPDATE_ACCUM_FIELD_SL for field ',accum(nf)%name - write(iulog,*)'size of first dimension of field is ',size(field,dim=1),& - ' and should be ',end-beg+1 - call shr_sys_abort - endif - - ! accumulate field - - if (accum(nf)%acctype /= 'timeavg' .AND. & - accum(nf)%acctype /= 'runmean' .AND. & - accum(nf)%acctype /= 'runaccum') then - write(iulog,*) 'UPDATE_ACCUM_FIELD_SL error: incorrect accumulation type' - write(iulog,*) ' was specified for field ',name - write(iulog,*)' accumulation type specified is ',accum(nf)%acctype - write(iulog,*)' only [timeavg, runmean, runaccum] are currently acceptable' - call shr_sys_abort() - end if - - - ! reset accumulated field value if necessary and update - ! accumulation field - ! running mean never reset - - if (accum(nf)%acctype == 'timeavg') then - - !time average field reset every accumulation period - !normalize at end of accumulation period - - if ((mod(nstep,accum(nf)%period) == 1 .or. accum(nf)%period == 1) .and. (nstep /= 0))then - accum(nf)%val(beg:end,1) = 0._r8 - end if - accum(nf)%val(beg:end,1) = accum(nf)%val(beg:end,1) + field(beg:end) - if (mod(nstep,accum(nf)%period) == 0) then - accum(nf)%val(beg:end,1) = accum(nf)%val(beg:end,1) / accum(nf)%period - endif - - else if (accum(nf)%acctype == 'runmean') then - - !running mean - reset accumulation period until greater than nstep - - accper = min (nstep,accum(nf)%period) - accum(nf)%val(beg:end,1) = ((accper-1)*accum(nf)%val(beg:end,1) + field(beg:end)) / accper - - else if (accum(nf)%acctype == 'runaccum') then + character(len=*), parameter :: subname = 'update_accum_field_sl' + !------------------------------------------------------------------------ - !running accumulation field reset at trigger -99999 + call find_field(field_name=name, caller_name=subname, field_index=nf) - do k = beg,end - if (nint(field(k)) == -99999) then - accum(nf)%val(k,1) = 0._r8 - end if - end do - accum(nf)%val(beg:end,1) = min(max(accum(nf)%val(beg:end,1) + field(beg:end), 0._r8), 99999._r8) + numlev = accum(nf)%numlev + SHR_ASSERT(numlev == 1, errMsg(sourcefile, __LINE__)) - end if + call accum(nf)%update_accum_field_func( & + level = 1, & + nstep = nstep, & + field = field) end subroutine update_accum_field_sl @@ -465,6 +499,9 @@ subroutine update_accum_field_ml (name, field, nstep) ! !DESCRIPTION: ! Accumulate multi level field over specified time interval. ! + ! Values of 'field' are ignored in inactive points, so it's safe for 'field' to + ! contain garbage in inactive points. + ! ! !ARGUMENTS: implicit none character(len=*), intent(in) :: name !field name @@ -472,96 +509,162 @@ subroutine update_accum_field_ml (name, field, nstep) integer , intent(in) :: nstep !time step index ! ! !LOCAL VARIABLES: - integer :: i,j,k,nf !indices - integer :: accper !temporary accumulation period - integer :: beg,end !subgrid beginning,ending indices - integer :: numlev !number of vertical levels + integer :: j,nf !indices + integer :: numlev !number of vertical levels + + character(len=*), parameter :: subname = 'update_accum_field_ml' !------------------------------------------------------------------------ - ! find field index. return if "name" is not on list + call find_field(field_name=name, caller_name=subname, field_index=nf) - nf = 0 - do i = 1, naccflds - if (name == accum(i)%name) nf = i + numlev = accum(nf)%numlev + SHR_ASSERT((size(field, 2) == numlev), errMsg(sourcefile, __LINE__)) + + do j = 1,numlev + call accum(nf)%update_accum_field_func( & + level = j, & + nstep = nstep, & + field = field(:,j)) end do - if (nf == 0) then - write(iulog,*) 'UPDATE_ACCUM_FIELD_ML error: field name ',name,' not found' - call shr_sys_abort - endif - ! error check + end subroutine update_accum_field_ml - numlev = accum(nf)%numlev - beg = accum(nf)%beg1d - end = accum(nf)%end1d - if (size(field,dim=1) /= end-beg+1) then - write(iulog,*)'ERROR in UPDATE_ACCUM_FIELD_ML for field ',accum(nf)%name - write(iulog,*)'size of first dimension of field is ',size(field,dim=1),& - ' and should be ',end-beg+1 - call shr_sys_abort - else if (size(field,dim=2) /= numlev) then - write(iulog,*)'ERROR in UPDATE_ACCUM_FIELD_ML for field ',accum(nf)%name - write(iulog,*)'size of second dimension of field is ',size(field,dim=2),& - ' and should be ',numlev - call shr_sys_abort - endif + !----------------------------------------------------------------------- + subroutine update_accum_field_timeavg(this, level, nstep, field) + ! + ! !DESCRIPTION: + ! Update values for one level of the given timeavg field + ! + ! !ARGUMENTS: + class(accum_field), intent(in) :: this + integer, intent(in) :: level ! level index to update (1 for a 1-d field) + integer, intent(in) :: nstep ! timestep index + real(r8), intent(in) :: field(:) ! field values for current time step + ! + ! !LOCAL VARIABLES: + integer :: begi,endi !subgrid beginning,ending indices + integer :: k, kf - ! accumulate field + character(len=*), parameter :: subname = 'update_accum_field_timeavg' + !----------------------------------------------------------------------- - if (accum(nf)%acctype /= 'timeavg' .AND. & - accum(nf)%acctype /= 'runmean' .AND. & - accum(nf)%acctype /= 'runaccum') then - write(iulog,*) 'UPDATE_ACCUM_FIELD_ML error: incorrect accumulation type' - write(iulog,*) ' was specified for field ',name - write(iulog,*)' accumulation type specified is ',accum(nf)%acctype - write(iulog,*)' only [timeavg, runmean, runaccum] are currently acceptable' - call shr_sys_abort() - end if + begi = this%beg1d + endi = this%end1d + SHR_ASSERT((size(field) == endi-begi+1), errMsg(sourcefile, __LINE__)) - ! accumulate field + ! time average field: reset every accumulation period; normalize at end of + ! accumulation period - ! reset accumulated field value if necessary and update - ! accumulation field - ! running mean never reset + if ((mod(nstep,this%period) == 1 .or. this%period == 1) .and. (nstep /= 0))then + do k = begi,endi + if (this%active(k)) then + this%val(k,level) = 0._r8 + this%nsteps(k,level) = 0 + end if + end do + end if - if (accum(nf)%acctype == 'timeavg') then + do k = begi,endi + if (this%active(k)) then + kf = k - begi + 1 + this%val(k,level) = this%val(k,level) + field(kf) + this%nsteps(k,level) = this%nsteps(k,level) + 1 + end if + end do - !time average field reset every accumulation period - !normalize at end of accumulation period + if (mod(nstep,this%period) == 0) then + do k = begi,endi + if (this%active(k)) then + this%val(k,level) = this%val(k,level) / this%nsteps(k,level) + end if + end do + end if - if ((mod(nstep,accum(nf)%period) == 1 .or. accum(nf)%period == 1) .and. (nstep /= 0))then - accum(nf)%val(beg:end,1:numlev) = 0._r8 - endif - accum(nf)%val(beg:end,1:numlev) = accum(nf)%val(beg:end,1:numlev) + field(beg:end,1:numlev) - if (mod(nstep,accum(nf)%period) == 0) then - accum(nf)%val(beg:end,1:numlev) = accum(nf)%val(beg:end,1:numlev) / accum(nf)%period - endif + end subroutine update_accum_field_timeavg - else if (accum(nf)%acctype == 'runmean') then + !----------------------------------------------------------------------- + subroutine update_accum_field_runmean(this, level, nstep, field) + ! + ! !DESCRIPTION: + ! Update values for one level of the given runmean field + ! + ! !ARGUMENTS: + class(accum_field), intent(in) :: this + integer, intent(in) :: level ! level index to update (1 for a 1-d field) + integer, intent(in) :: nstep ! timestep index + real(r8), intent(in) :: field(:) ! field values for current time step + ! + ! !LOCAL VARIABLES: + integer :: begi,endi !subgrid beginning,ending indices + integer :: k, kf + integer :: accper ! accumulation period + + character(len=*), parameter :: subname = 'update_accum_field_runmean' + !----------------------------------------------------------------------- + + begi = this%beg1d + endi = this%end1d + SHR_ASSERT((size(field) == endi-begi+1), errMsg(sourcefile, __LINE__)) + + do k = begi,endi + if (this%active(k)) then + kf = k - begi + 1 + this%nsteps(k,level) = this%nsteps(k,level) + 1 + ! Cap nsteps at 'period' - partly to avoid overflow, but also because it doesn't + ! help us to accumulate nsteps beyond a value of 'period' (because nsteps is + ! just used to determine accper, and accper needs to be capped at 'period'). A + ! side-benefit of this capping of nsteps is that accper (the accumulation + ! period) is always equal to nsteps. + this%nsteps(k,level) = min(this%nsteps(k,level), this%period) + accper = this%nsteps(k,level) + this%val(k,level) = & + ((accper-1)*this%val(k,level) + field(kf)) / accper + end if + end do + + end subroutine update_accum_field_runmean - !running mean - reset accumulation period until greater than nstep + !----------------------------------------------------------------------- + subroutine update_accum_field_runaccum(this, level, nstep, field) + ! + ! !DESCRIPTION: + ! Update values for one level of the given runaccum field + ! + ! !ARGUMENTS: + class(accum_field), intent(in) :: this + integer, intent(in) :: level ! level index to update (1 for a 1-d field) + integer, intent(in) :: nstep ! timestep index + real(r8), intent(in) :: field(:) ! field values for current time step + ! + ! !LOCAL VARIABLES: + integer :: begi,endi !subgrid beginning,ending indices + integer :: k, kf - accper = min (nstep,accum(nf)%period) - accum(nf)%val(beg:end,1:numlev) = & - ((accper-1)*accum(nf)%val(beg:end,1:numlev) + field(beg:end,1:numlev)) / accper + character(len=*), parameter :: subname = 'update_accum_field_runaccum' + !----------------------------------------------------------------------- - else if (accum(nf)%acctype == 'runaccum') then + begi = this%beg1d + endi = this%end1d + SHR_ASSERT((size(field) == endi-begi+1), errMsg(sourcefile, __LINE__)) - !running accumulation field reset at trigger -99999 + !running accumulation field; reset at trigger -99999 - do j = 1,numlev - do k = beg,end - if (nint(field(k,j)) == -99999) then - accum(nf)%val(k,j) = 0._r8 - end if - end do - end do - accum(nf)%val(beg:end,1:numlev) = & - min(max(accum(nf)%val(beg:end,1:numlev) + field(beg:end,1:numlev), 0._r8), 99999._r8) + do k = begi,endi + if (this%active(k)) then + kf = k - begi + 1 + if (nint(field(kf)) == -99999) then + this%val(k,level) = 0._r8 + this%nsteps(k,level) = 0 + else + this%val(k,level) = & + min(max(this%val(k,level) + field(kf), 0._r8), 99999._r8) + this%nsteps(k,level) = this%nsteps(k,level) + 1 + end if + end if + end do - end if + end subroutine update_accum_field_runaccum - end subroutine update_accum_field_ml !------------------------------------------------------------------------ subroutine accumulRest( ncid, flag ) @@ -570,7 +673,6 @@ subroutine accumulRest( ncid, flag ) ! Read/write accumulation restart data ! ! !USES: - use clm_varcon , only : ispval use restUtilMod , only : restartvar use ncdio_pio , only : file_desc_t, ncd_double, ncd_int ! @@ -588,9 +690,6 @@ subroutine accumulRest( ncid, flag ) do nf = 1,naccflds - ! Note = below need to allocate rbuf for single level variables, since - ! accum(nf)%val is always 2d - varname = trim(accum(nf)%name) // '_VALUE' if (accum(nf)%numlev == 1) then call restartvar(ncid=ncid, flag=flag, varname=varname, xtype=ncd_double, & @@ -606,6 +705,23 @@ subroutine accumulRest( ncid, flag ) data=accum(nf)%val, readvar=readvar) end if + varname = trim(accum(nf)%name) // '_NSTEPS' + if (accum(nf)%numlev == 1) then + call restartvar(ncid=ncid, flag=flag, varname=varname, xtype=ncd_int, & + dim1name=accum(nf)%type1d, & + long_name='number of accumulated steps for '//trim(accum(nf)%name), & + units='-', & + interpinic_flag='interp', & + data=accum(nf)%nsteps, readvar=readvar) + else + call restartvar(ncid=ncid, flag=flag, varname=varname, xtype=ncd_int, & + dim1name=accum(nf)%type1d, dim2name=accum(nf)%type2d, & + long_name='number of accumulated steps for '//trim(accum(nf)%name), & + units='-', & + interpinic_flag='interp', & + data=accum(nf)%nsteps, readvar=readvar) + end if + varname = trim(accum(nf)%name) // '_PERIOD' call restartvar(ncid=ncid, flag=flag, varname=varname, xtype=ncd_int, & long_name='', units='time steps', & @@ -617,4 +733,95 @@ subroutine accumulRest( ncid, flag ) end subroutine accumulRest + !----------------------------------------------------------------------- + subroutine clean_accum_fields + ! + ! !DESCRIPTION: + ! Deallocate space and reset accum fields list + ! + ! !ARGUMENTS: + ! + ! !LOCAL VARIABLES: + integer :: i + + character(len=*), parameter :: subname = 'clean_accum_fields' + !----------------------------------------------------------------------- + + do i = 1, naccflds + if (associated(accum(i)%val)) then + deallocate(accum(i)%val) + end if + if (associated(accum(i)%nsteps)) then + deallocate(accum(i)%nsteps) + end if + end do + + naccflds = 0 + + end subroutine clean_accum_fields + + + !----------------------------------------------------------------------- + subroutine find_field(field_name, caller_name, field_index) + ! + ! !DESCRIPTION: + ! Find field index given field name + ! + ! Aborts if the given field name isn't found + ! + ! !ARGUMENTS: + character(len=*), intent(in) :: field_name ! field name to find + character(len=*), intent(in) :: caller_name ! name of calling routine (for more informative error messages) + integer , intent(out) :: field_index ! index of given field in accum array + ! + ! !LOCAL VARIABLES: + integer :: i + + character(len=*), parameter :: subname = 'find_field' + !----------------------------------------------------------------------- + + field_index = 0 + do i = 1, naccflds + if (field_name == accum(i)%name) then + field_index = i + exit + end if + end do + if (field_index == 0) then + write(iulog,*) trim(caller_name), 'ERROR: field name ',trim(field_name),' not found' + call endrun('Accumulation field not found') + end if + + end subroutine find_field + + + !----------------------------------------------------------------------- + pure function acctype_to_string(acctype) result(acctype_str) + ! + ! !DESCRIPTION: + ! Return a string representation of an ACCTYPE parameter + ! + ! !ARGUMENTS: + character(len=32) :: acctype_str ! function result + integer, intent(in) :: acctype + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'acctype_to_string' + !----------------------------------------------------------------------- + + select case (acctype) + case (ACCTYPE_TIMEAVG) + acctype_str = 'timeavg' + case (ACCTYPE_RUNMEAN) + acctype_str = 'runmean' + case (ACCTYPE_RUNACCUM) + acctype_str = 'runaccum' + case default + acctype_str = 'unknown' + end select + + end function acctype_to_string + + end module accumulMod diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 8980d8b45d..c54ddcd12a 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -21,7 +21,7 @@ module atm2lndMod use filterColMod , only : filter_col_type use LandunitType , only : lun use ColumnType , only : col - use landunit_varcon, only : istice, istice_mec + use landunit_varcon, only : istice_mec ! ! !PUBLIC TYPES: implicit none @@ -298,7 +298,7 @@ subroutine partition_precip(bounds, atm2lnd_inst, eflx_sh_precip_conversion) l = col%landunit(c) rain_old = forc_rain_c(c) snow_old = forc_snow_c(c) - if (lun%itype(l) == istice .or. lun%itype(l) == istice_mec) then + if (lun%itype(l) == istice_mec) then all_snow_t = atm2lnd_inst%params%precip_repartition_glc_all_snow_t frac_rain_slope = atm2lnd_inst%params%precip_repartition_glc_frac_rain_slope else diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index 586df9b1d3..c2ad4de821 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -10,7 +10,7 @@ module atm2lndType use shr_log_mod , only : errMsg => shr_log_errMsg use clm_varpar , only : numrad, ndst, nlevgrnd !ndst = number of dust bins. use clm_varcon , only : rair, grav, cpair, hfus, tfrz, spval - use clm_varctl , only : iulog, use_c13, use_cn, use_lch4, use_cndv, use_ed, use_luna + use clm_varctl , only : iulog, use_c13, use_cn, use_lch4, use_cndv, use_fates, use_luna use decompMod , only : bounds_type use abortutils , only : endrun use PatchType , only : patch @@ -133,7 +133,7 @@ module atm2lndType real(r8) , pointer :: fsd240_patch (:) => null() ! patch 240hr average of direct beam radiation real(r8) , pointer :: fsi24_patch (:) => null() ! patch 24hr average of diffuse beam radiation real(r8) , pointer :: fsi240_patch (:) => null() ! patch 240hr average of diffuse beam radiation - real(r8) , pointer :: prec365_patch (:) => null() ! patch 365-day running mean of tot. precipitation + real(r8) , pointer :: prec365_col (:) => null() ! col 365-day running mean of tot. precipitation (see comment in UpdateAccVars regarding why this is col-level despite other prec accumulators being patch-level) real(r8) , pointer :: prec60_patch (:) => null() ! patch 60-day running mean of tot. precipitation (mm/s) real(r8) , pointer :: prec10_patch (:) => null() ! patch 10-day running mean of tot. precipitation (mm/s) real(r8) , pointer :: rh30_patch (:) => null() ! patch 30-day running mean of relative humidity @@ -562,8 +562,8 @@ subroutine InitAllocate(this, bounds) allocate(this%prec10_patch (begp:endp)) ; this%prec10_patch (:) = nan allocate(this%prec60_patch (begp:endp)) ; this%prec60_patch (:) = nan allocate(this%rh30_patch (begp:endp)) ; this%rh30_patch (:) = nan - allocate(this%prec365_patch (begp:endp)) ; this%prec365_patch (:) = nan - if (use_ed) then + allocate(this%prec365_col (begc:endc)) ; this%prec365_col (:) = nan + if (use_fates) then allocate(this%prec24_patch (begp:endp)) ; this%prec24_patch (:) = nan allocate(this%rh24_patch (begp:endp)) ; this%rh24_patch (:) = nan allocate(this%wind24_patch (begp:endp)) ; this%wind24_patch (:) = nan @@ -655,81 +655,72 @@ subroutine InitHistory(this, bounds) end if this%forc_t_not_downscaled_grc(begg:endg) = spval - call hist_addfld1d (fname='Tair', units='K', & - avgflag='A', long_name='atmospheric air temperature', & + call hist_addfld1d (fname='Tair_from_atm', units='K', & + avgflag='A', long_name='atmospheric air temperature received from atmosphere (pre-downscaling)', & ptr_gcell=this%forc_t_not_downscaled_grc, default='inactive') this%forc_t_downscaled_col(begc:endc) = spval - call hist_addfld1d (fname='Tair_downscaled', units='K', & - avgflag='A', long_name='atmospheric air temperature downscaled to columns', & + call hist_addfld1d (fname='TBOT', units='K', & + avgflag='A', long_name='atmospheric air temperature (downscaled to columns in glacier regions)', & + ptr_col=this%forc_t_downscaled_col) + call hist_addfld1d (fname='Tair', units='K', & + avgflag='A', long_name='atmospheric air temperature (downscaled to columns in glacier regions)', & ptr_col=this%forc_t_downscaled_col, default='inactive') - this%forc_pbot_not_downscaled_grc(begg:endg) = spval + this%forc_pbot_downscaled_col(begc:endc) = spval + call hist_addfld1d (fname='PBOT', units='Pa', & + avgflag='A', long_name='atmospheric pressure at surface (downscaled to columns in glacier regions)', & + ptr_col=this%forc_pbot_downscaled_col) call hist_addfld1d (fname='PSurf', units='Pa', & - avgflag='A', long_name='surface pressure', & - ptr_gcell=this%forc_pbot_not_downscaled_grc, default='inactive') - - this%forc_rain_not_downscaled_grc(begg:endg) = spval - call hist_addfld1d (fname='Rainf', units='mm/s', & - avgflag='A', long_name='atmospheric rain', & - ptr_gcell=this%forc_rain_not_downscaled_grc, default='inactive') + avgflag='A', long_name='atmospheric pressure at surface (downscaled to columns in glacier regions)', & + ptr_col=this%forc_pbot_downscaled_col, default='inactive') - this%forc_lwrad_not_downscaled_grc(begg:endg) = spval + this%forc_lwrad_downscaled_col(begc:endc) = spval + call hist_addfld1d (fname='FLDS', units='W/m^2', & + avgflag='A', long_name='atmospheric longwave radiation (downscaled to columns in glacier regions)', & + ptr_col=this%forc_lwrad_downscaled_col) call hist_addfld1d (fname='LWdown', units='W/m^2', & - avgflag='A', long_name='atmospheric longwave radiation', & - ptr_gcell=this%forc_lwrad_not_downscaled_grc, default='inactive') + avgflag='A', long_name='atmospheric longwave radiation (downscaled to columns in glacier regions)', & + ptr_col=this%forc_lwrad_downscaled_col, default='inactive') this%forc_rain_not_downscaled_grc(begg:endg) = spval - call hist_addfld1d (fname='RAIN', units='mm/s', & - avgflag='A', long_name='atmospheric rain', & + call hist_addfld1d (fname='RAIN_FROM_ATM', units='mm/s', & + avgflag='A', long_name='atmospheric rain received from atmosphere (pre-repartitioning)', & !scs ptr_lnd=this%forc_rain_not_downscaled_grc) ptr_col=this%forc_rain_downscaled_col) this%forc_snow_not_downscaled_grc(begg:endg) = spval - call hist_addfld1d (fname='SNOW', units='mm/s', & - avgflag='A', long_name='atmospheric snow', & + call hist_addfld1d (fname='SNOW_FROM_ATM', units='mm/s', & + avgflag='A', long_name='atmospheric snow received from atmosphere (pre-repartitioning)', & !scs ptr_lnd=this%forc_snow_not_downscaled_grc) ptr_col=this%forc_snow_downscaled_col) this%forc_rain_downscaled_col(begc:endc) = spval - call hist_addfld1d (fname='RAIN_REPARTITIONED', units='mm/s', & + call hist_addfld1d (fname='RAIN', units='mm/s', & avgflag='A', long_name='atmospheric rain, after rain/snow repartitioning based on temperature', & ptr_col=this%forc_rain_downscaled_col) + call hist_addfld1d (fname='Rainf', units='mm/s', & + avgflag='A', long_name='atmospheric rain, after rain/snow repartitioning based on temperature', & + ptr_col=this%forc_rain_downscaled_col, default='inactive') this%forc_snow_downscaled_col(begc:endc) = spval - call hist_addfld1d (fname='SNOW_REPARTITIONED', units='mm/s', & + call hist_addfld1d (fname='SNOW', units='mm/s', & avgflag='A', long_name='atmospheric snow, after rain/snow repartitioning based on temperature', & ptr_col=this%forc_snow_downscaled_col) - this%forc_t_not_downscaled_grc(begg:endg) = spval - call hist_addfld1d (fname='TBOT', units='K', & - avgflag='A', long_name='atmospheric air temperature', & - ptr_lnd=this%forc_t_not_downscaled_grc) - - this%forc_th_not_downscaled_grc(begg:endg) = spval + this%forc_th_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='THBOT', units='K', & - avgflag='A', long_name='atmospheric air potential temperature', & - ptr_lnd=this%forc_th_not_downscaled_grc) + avgflag='A', long_name='atmospheric air potential temperature (downscaled to columns in glacier regions)', & + ptr_col=this%forc_th_downscaled_col) - this%forc_q_not_downscaled_grc(begg:endg) = spval + this%forc_q_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='QBOT', units='kg/kg', & - avgflag='A', long_name='atmospheric specific humidity', & - ptr_lnd=this%forc_q_not_downscaled_grc) - ! Rename of QBOT for Urban intercomparision project - this%forc_q_not_downscaled_grc(begg:endg) = spval + avgflag='A', long_name='atmospheric specific humidity (downscaled to columns in glacier regions)', & + ptr_col=this%forc_q_downscaled_col) + ! Rename of QBOT for Urban intercomparison project call hist_addfld1d (fname='Qair', units='kg/kg', & - avgflag='A', long_name='atmospheric specific humidity', & - ptr_lnd=this%forc_q_not_downscaled_grc, default='inactive') - - this%forc_lwrad_not_downscaled_grc(begg:endg) = spval - call hist_addfld1d (fname='FLDS', units='W/m^2', & - avgflag='A', long_name='atmospheric longwave radiation', & - ptr_lnd=this%forc_lwrad_not_downscaled_grc) - - this%forc_pbot_not_downscaled_grc(begg:endg) = spval - call hist_addfld1d (fname='PBOT', units='Pa', & - avgflag='A', long_name='atmospheric pressure', & - ptr_lnd=this%forc_pbot_not_downscaled_grc) + avgflag='A', long_name='atmospheric specific humidity (downscaled to columns in glacier regions)', & + ptr_col=this%forc_q_downscaled_col, default='inactive') ! Time averaged quantities this%fsi24_patch(begp:endp) = spval @@ -847,10 +838,10 @@ subroutine InitAccBuffer (this, bounds) ! The following is a running mean with the accumulation period is set to -365 for a 365-day running mean. call init_accum_field (name='PREC365', units='MM H2O/S', & desc='365-day running mean of total precipitation', accum_type='runmean', accum_period=-365, & - subgrid_type='pft', numlev=1, init_value=0._r8) + subgrid_type='column', numlev=1, init_value=0._r8) end if - if ( use_ed ) then + if ( use_fates ) then call init_accum_field (name='PREC24', units='m', & desc='24hr sum of precipitation', accum_type='runmean', accum_period=-1, & subgrid_type='pft', numlev=1, init_value=0._r8) @@ -904,18 +895,28 @@ subroutine InitAccVars(this, bounds) ! ! !LOCAL VARIABLES: integer :: begp, endp + integer :: begc, endc integer :: nstep integer :: ier real(r8), pointer :: rbufslp(:) ! temporary + real(r8), pointer :: rbufslc(:) ! temporary !--------------------------------------------------------------------- begp = bounds%begp; endp = bounds%endp + begc = bounds%begc; endc = bounds%endc ! Allocate needed dynamic memory for single level patch field allocate(rbufslp(begp:endp), stat=ier) if (ier/=0) then write(iulog,*)' in ' - call endrun(msg="extract_accum_hist allocation error for rbufslp"//& + call endrun(msg="InitAccVars allocation error for rbufslp"//& + errMsg(sourcefile, __LINE__)) + endif + ! Allocate needed dynamic memory for single level col field + allocate(rbufslc(begc:endc), stat=ier) + if (ier/=0) then + write(iulog,*)' in ' + call endrun(msg="InitAccVars allocation error for rbufslc"//& errMsg(sourcefile, __LINE__)) endif @@ -946,14 +947,14 @@ subroutine InitAccVars(this, bounds) end if if (use_cndv) then - call extract_accum_field ('PREC365' , rbufslp, nstep) - this%prec365_patch(begp:endp) = rbufslp(begp:endp) + call extract_accum_field ('PREC365' , rbufslc, nstep) + this%prec365_col(begc:endc) = rbufslc(begc:endc) call extract_accum_field ('TDA', rbufslp, nstep) this%t_mo_patch(begp:endp) = rbufslp(begp:endp) end if - if (use_ed) then + if (use_fates) then call extract_accum_field ('PREC24', rbufslp, nstep) this%prec24_patch(begp:endp) = rbufslp(begp:endp) @@ -977,6 +978,7 @@ subroutine InitAccVars(this, bounds) endif deallocate(rbufslp) + deallocate(rbufslc) end subroutine InitAccVars @@ -997,18 +999,26 @@ subroutine UpdateAccVars (this, bounds) integer :: nstep ! timestep number integer :: ier ! error status integer :: begp, endp + integer :: begc, endc real(r8), pointer :: rbufslp(:) ! temporary single level - patch level + real(r8), pointer :: rbufslc(:) ! temporary single level - column level !--------------------------------------------------------------------- begp = bounds%begp; endp = bounds%endp + begc = bounds%begc; endc = bounds%endc nstep = get_nstep() ! Allocate needed dynamic memory for single level patch field - allocate(rbufslp(begp:endp), stat=ier) if (ier/=0) then - write(iulog,*)'update_accum_hist allocation error for rbuf1dp' + write(iulog,*)'UpdateAccVars allocation error for rbufslp' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif + ! Allocate needed dynamic memory for single level col field + allocate(rbufslc(begc:endc), stat=ier) + if (ier/=0) then + write(iulog,*)'UpdateAccVars allocation error for rbufslc' call endrun(msg=errMsg(sourcefile, __LINE__)) endif @@ -1032,9 +1042,18 @@ subroutine UpdateAccVars (this, bounds) call update_accum_field ('FSI240', rbufslp , nstep) call extract_accum_field ('FSI240', this%fsi240_patch , nstep) + ! Precipitation accumulators + ! + ! For CNDV, we use a column-level accumulator. We cannot use a patch-level + ! accumulator for CNDV because this is used for establishment, so must be available + ! for inactive patches. In principle, we could/should switch to column-level for the + ! other precip accumulators, too; we'd just need to be careful about backwards + ! compatibility with old restart files. + do p = begp,endp c = patch%column(p) rbufslp(p) = this%forc_rain_downscaled_col(c) + this%forc_snow_downscaled_col(c) + rbufslc(c) = this%forc_rain_downscaled_col(c) + this%forc_snow_downscaled_col(c) end do if (use_cn) then @@ -1049,8 +1068,10 @@ subroutine UpdateAccVars (this, bounds) if (use_cndv) then ! Accumulate and extract PREC365 (accumulates total precipitation as 365-day running mean) - call update_accum_field ('PREC365', rbufslp, nstep) - call extract_accum_field ('PREC365', this%prec365_patch, nstep) + ! See above comment regarding why this is at the column-level despite other prec + ! accumulators being at the patch level. + call update_accum_field ('PREC365', rbufslc, nstep) + call extract_accum_field ('PREC365', this%prec365_col, nstep) ! Accumulate and extract TDA (accumulates TBOT as 30-day average) and ! also determines t_mo_min @@ -1068,7 +1089,7 @@ subroutine UpdateAccVars (this, bounds) end if - if (use_ed) then + if (use_fates) then call update_accum_field ('PREC24', rbufslp, nstep) call extract_accum_field ('PREC24', this%prec24_patch, nstep) @@ -1122,6 +1143,7 @@ subroutine UpdateAccVars (this, bounds) endif deallocate(rbufslp) + deallocate(rbufslc) end subroutine UpdateAccVars @@ -1251,8 +1273,8 @@ subroutine Clean(this) deallocate(this%fsi240_patch) deallocate(this%prec10_patch) deallocate(this%prec60_patch) - deallocate(this%prec365_patch) - if (use_ed) then + deallocate(this%prec365_col) + if (use_fates) then deallocate(this%prec24_patch) deallocate(this%rh24_patch) deallocate(this%wind24_patch) diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index c7b4076728..83ae6c15ef 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -9,9 +9,9 @@ module clm_driver ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 - use clm_varctl , only : wrtdia, iulog, create_glacier_mec_landunit, use_ed - use clm_varctl , only : use_cn, use_lch4, use_voc, use_noio, use_c13, use_c14 - use clm_varctl , only : use_crop + use clm_varctl , only : wrtdia, iulog, use_fates + use clm_varctl , only : use_cn, use_lch4, use_noio, use_c13, use_c14 + use clm_varctl , only : use_crop, ndep_from_cpl use clm_varctl , only : is_cold_start, is_interpolated_start use clm_time_manager , only : get_nstep, is_beg_curr_day use clm_time_manager , only : get_prev_date, is_first_step @@ -199,14 +199,13 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro need_glacier_initialization = (is_first_step() .and. & (is_cold_start .or. is_interpolated_start)) - if (create_glacier_mec_landunit .and. need_glacier_initialization) then + if (need_glacier_initialization) then !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) do nc = 1, nclumps call get_clump_bounds(nc, bounds_clump) - call glc2lnd_inst%update_glc2lnd_non_topo( & - bounds = bounds_clump, & - glc_behavior = glc_behavior) + call glc2lnd_inst%update_glc2lnd_fracs( & + bounds = bounds_clump) call dynSubgrid_wrapup_weight_changes(bounds_clump, glc_behavior) @@ -305,7 +304,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call t_startf('dyn_subgrid') call dynSubgrid_driver(bounds_proc, & - urbanparams_inst, soilstate_inst, soilhydrology_inst, lakestate_inst, & + urbanparams_inst, soilstate_inst, soilhydrology_inst, & waterstate_inst, waterflux_inst, temperature_inst, energyflux_inst, & canopystate_inst, photosyns_inst, crop_inst, glc2lnd_inst, bgc_vegetation_inst, & soilbiogeochem_state_inst, soilbiogeochem_carbonstate_inst, & @@ -337,8 +336,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call BeginWaterBalance(bounds_clump, & filter(nc)%num_nolakec, filter(nc)%nolakec, & filter(nc)%num_lakec, filter(nc)%lakec, & - filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & soilhydrology_inst, waterstate_inst) + call t_stopf('begwbal') call t_startf('begcnbal_col') @@ -372,7 +371,9 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro if (use_cn) then call t_startf('bgc_interp') - call ndep_interp(bounds_proc, atm2lnd_inst) + if (.not. ndep_from_cpl) then + call ndep_interp(bounds_proc, atm2lnd_inst) + end if call bgc_vegetation_inst%InterpFileInputs(bounds_proc) call t_stopf('bgc_interp') end if @@ -456,10 +457,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! The nourbanp filter is set in dySubgrid_driver (earlier in this call) ! over the patch index range defined by bounds_clump%begp:bounds_proc%endp - if(use_ed) then - + if(use_fates) then call clm_fates%wrap_sunfrac(nc,atm2lnd_inst, canopystate_inst) - else call CanopySunShadeFracs(filter(nc)%nourbanp,filter(nc)%num_nourbanp, & atm2lnd_inst, surfalb_inst, canopystate_inst, & @@ -496,6 +495,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call CanopyTemperature(bounds_clump, & filter(nc)%num_nolakec, filter(nc)%nolakec, & filter(nc)%num_nolakep, filter(nc)%nolakep, & + clm_fates, & atm2lnd_inst, canopystate_inst, soilstate_inst, frictionvel_inst, & waterstate_inst, waterflux_inst, energyflux_inst, temperature_inst) call t_stopf('bgp1') @@ -554,17 +554,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro deallocate(downreg_patch, leafn_patch, froot_carbon, croot_carbon) call t_stopf('canflux') - if (use_ed) then - ! if ED enabled, summarize productivity fluxes onto CLM history file structure - call t_startf('edclmsumprodfluxes') - ! INTERF-TODO: THIS NEEDS A WRAPPER call clm_fates%sumprod(bounds_clump) - call clm_fates%fates2hlm%SummarizeProductivityFluxes( bounds_clump, & - clm_fates%fates(nc)%nsites, & - clm_fates%fates(nc)%sites, & - clm_fates%f2hmap(nc)%fcolumn) - call t_stopf('edclmsumprodfluxes') - endif - ! Fluxes for all urban landunits call t_startf('uflux') @@ -629,12 +618,10 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro atm2lnd_inst, frictionvel_inst, dust_inst) ! VOC emission (A. Guenther's MEGAN (2006) model) - if (use_voc) then - call VOCEmission(bounds_clump, & + call VOCEmission(bounds_clump, & filter(nc)%num_soilp, filter(nc)%soilp, & atm2lnd_inst, canopystate_inst, photosyns_inst, temperature_inst, & vocemis_inst) - end if call t_stopf('bgc') @@ -688,7 +675,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call t_startf('patch2col') call clm_drv_patch2col(bounds_clump, & filter(nc)%num_allc, filter(nc)%allc, filter(nc)%num_nolakec, filter(nc)%nolakec, & - waterstate_inst, energyflux_inst, waterflux_inst) + energyflux_inst, waterflux_inst) call t_stopf('patch2col') ! ============================================================================ @@ -707,9 +694,10 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro filter(nc)%num_urbanc, filter(nc)%urbanc, & filter(nc)%num_snowc, filter(nc)%snowc, & filter(nc)%num_nosnowc, filter(nc)%nosnowc, & + clm_fates, & atm2lnd_inst, soilstate_inst, energyflux_inst, temperature_inst, & waterflux_inst, waterstate_inst, soilhydrology_inst, aerosol_inst, & - canopystate_inst, soil_water_retention_curve) + canopystate_inst, soil_water_retention_curve, topo_inst) ! The following needs to be done after HydrologyNoDrainage (because it needs ! waterflux_inst%qflx_snwcp_ice_col), but before HydrologyDrainage (because @@ -749,7 +737,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro filter(nc)%num_lakesnowc, filter(nc)%lakesnowc, & filter(nc)%num_lakenosnowc, filter(nc)%lakenosnowc, & atm2lnd_inst, temperature_inst, soilstate_inst, waterstate_inst, waterflux_inst, & - energyflux_inst, aerosol_inst, lakestate_inst) + energyflux_inst, aerosol_inst, lakestate_inst, topo_inst) ! Calculate column-integrated aerosol masses, and ! mass concentrations for radiative calculations and output @@ -769,7 +757,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call SnowAge_grain(bounds_clump, & filter(nc)%num_lakesnowc, filter(nc)%lakesnowc, & filter(nc)%num_lakenosnowc, filter(nc)%lakenosnowc, & - waterflux_inst, waterstate_inst, temperature_inst) + waterflux_inst, waterstate_inst, temperature_inst, & + atm2lnd_inst) call t_stopf('hylake') @@ -797,7 +786,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call SnowAge_grain(bounds_clump, & filter(nc)%num_snowc, filter(nc)%snowc, & filter(nc)%num_nosnowc, filter(nc)%nosnowc, & - waterflux_inst, waterstate_inst, temperature_inst) + waterflux_inst, waterstate_inst, temperature_inst, & + atm2lnd_inst) call t_stopf('snow_init') ! ============================================================================ @@ -832,18 +822,13 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! Prescribed biogeography - prescribed canopy structure, some prognostic carbon fluxes - if ((.not. use_cn) .and. (.not. use_ed) .and. (doalb)) then + if ((.not. use_cn) .and. (.not. use_fates) .and. (doalb)) then call t_startf('SatellitePhenology') call SatellitePhenology(bounds_clump, filter(nc)%num_nolakep, filter(nc)%nolakep, & waterstate_inst, canopystate_inst) call t_stopf('SatellitePhenology') end if - ! Zero some of the FATES->CLM communicators - if (use_ed) then - call clm_fates%fates2hlm%SetValues(bounds_clump,0._r8) - end if - ! Dry Deposition of chemical tracers (Wesely (1998) parameterizaion) call t_startf('depvel') @@ -890,27 +875,25 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro end if - if ( use_ed .and. is_beg_curr_day() ) then ! run ED at the start of each day + if ( use_fates .and. is_beg_curr_day() ) then ! run fates at the start of each day if ( masterproc ) then - write(iulog,*) 'clm: calling ED model ', get_nstep() + write(iulog,*) 'clm: calling FATES model ', get_nstep() end if - ! INTERF-TODO: THIS CHECK WILL BE TURNED ON IN FUTURE VERSION -! call clm_fates%check_hlm_active(nc, bounds_clump) - call clm_fates%dynamics_driv( nc, bounds_clump, & atm2lnd_inst, soilstate_inst, temperature_inst, & - waterstate_inst, canopystate_inst, soilbiogeochem_carbonflux_inst) + waterstate_inst, canopystate_inst, soilbiogeochem_carbonflux_inst,& + frictionvel_inst) ! TODO(wjs, 2016-04-01) I think this setFilters call should be replaced by a ! call to reweight_wrapup, if it's needed at all. call setFilters( bounds_clump, glc_behavior ) - end if ! use_ed branch + end if ! use_fates branch - if ( use_ed ) then + if ( use_fates ) then call EDBGCDyn(bounds_clump, & filter(nc)%num_soilc, filter(nc)%soilc, & @@ -918,7 +901,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro filter(nc)%num_pcropp, filter(nc)%pcropp, doalb, & bgc_vegetation_inst%cnveg_carbonflux_inst, & bgc_vegetation_inst%cnveg_carbonstate_inst, & - clm_fates%fates2hlm, & soilbiogeochem_carbonflux_inst, soilbiogeochem_carbonstate_inst, & soilbiogeochem_state_inst, & soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & @@ -934,10 +916,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro c13_soilbiogeochem_carbonflux_inst, c13_soilbiogeochem_carbonstate_inst, & c14_soilbiogeochem_carbonflux_inst, c14_soilbiogeochem_carbonstate_inst, & soilbiogeochem_nitrogenflux_inst, soilbiogeochem_nitrogenstate_inst, & - clm_fates%fates2hlm, & - clm_fates%fates(nc)%sites, & - clm_fates%fates(nc)%nsites, & - clm_fates%f2hmap(nc)%fcolumn ) + clm_fates, nc) end if @@ -1025,16 +1004,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro aerosol_inst, canopystate_inst, waterstate_inst, & lakestate_inst, temperature_inst, surfalb_inst) - ! INTERF-TOD: THIS ACTUALLY WON'T BE TO HARD TO PULL OUT - ! ED_Norman_Radiation() is the last thing called - ! in SurfaceAlbedo, we can simply remove it - ! The clm_fates interfac called below will split - ! ED norman radiation into two parts - ! the calculation of values relevant to FATES - ! and then the transfer back to CLM/ALM memory stucts - - !call clm_fates%radiation() - call t_stopf('surfalb') ! Albedos for urban columns @@ -1075,7 +1044,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro atm2lnd_inst, surfalb_inst, temperature_inst, frictionvel_inst, & waterstate_inst, waterflux_inst, irrigation_inst, energyflux_inst, & solarabs_inst, drydepvel_inst, & - vocemis_inst, fireemis_inst, dust_inst, ch4_inst, lnd2atm_inst, & + vocemis_inst, fireemis_inst, dust_inst, ch4_inst, glc_behavior, & + lnd2atm_inst, & net_carbon_exchange_grc = net_carbon_exchange_grc(bounds_proc%begg:bounds_proc%endg)) deallocate(net_carbon_exchange_grc) call t_stopf('lnd2atm') @@ -1084,19 +1054,17 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! Determine gridcell averaged properties to send to glc ! ============================================================================ - if (create_glacier_mec_landunit) then - call t_startf('lnd2glc') - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) - do nc = 1,nclumps - call get_clump_bounds(nc, bounds_clump) - call lnd2glc_inst%update_lnd2glc(bounds_clump, & - filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & - temperature_inst, glacier_smb_inst, topo_inst, & - init=.false.) - end do - !$OMP END PARALLEL DO - call t_stopf('lnd2glc') - end if + call t_startf('lnd2glc') + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) + do nc = 1,nclumps + call get_clump_bounds(nc, bounds_clump) + call lnd2glc_inst%update_lnd2glc(bounds_clump, & + filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & + temperature_inst, glacier_smb_inst, topo_inst, & + init=.false.) + end do + !$OMP END PARALLEL DO + call t_stopf('lnd2glc') ! ============================================================================ ! Write global average diagnostics to standard output @@ -1113,8 +1081,8 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro ! ============================================================================ ! FIX(SPM,032414) double check why this isn't called for ED - ! FIX(SPM, 082814) - in the ED branch RF and I commented out the if(.not. - ! use_ed) then statement ... double check if this is required and why + ! FIX(SPM, 082814) - in the fates branch RF and I commented out the if(.not. + ! use_fates) then statement ... double check if this is required and why if (nstep > 0) then call t_startf('accum') @@ -1312,12 +1280,11 @@ end subroutine clm_drv_init !----------------------------------------------------------------------- subroutine clm_drv_patch2col (bounds, & num_allc, filter_allc, num_nolakec, filter_nolakec, & - waterstate_inst, energyflux_inst, waterflux_inst) + energyflux_inst, waterflux_inst) ! ! !DESCRIPTION: - ! Averages over all patchs for variables defined over both soil and lake - ! to provide the column-level averages of state and flux variables - ! defined at the patch level. + ! Averages over all patches for variables defined over both soil and lake to provide + ! the column-level averages of flux variables defined at the patch level. ! ! !USES: use WaterStateType , only : waterstate_type @@ -1332,7 +1299,6 @@ subroutine clm_drv_patch2col (bounds, & integer , intent(in) :: filter_allc(:) ! column filter for all active points integer , intent(in) :: num_nolakec ! number of column non-lake points in column filter integer , intent(in) :: filter_nolakec(:) ! column filter for non-lake points - type(waterstate_type) , intent(inout) :: waterstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst type(energyflux_type) , intent(inout) :: energyflux_inst ! @@ -1349,12 +1315,6 @@ subroutine clm_drv_patch2col (bounds, & ! are included here for lakes are computed elsewhere, e.g., in ! LakeFluxesMod.) - ! Averaging for patch water state variables - - call p2c (bounds, num_nolakec, filter_nolakec, & - waterstate_inst%h2ocan_patch(bounds%begp:bounds%endp), & - waterstate_inst%h2ocan_col(bounds%begc:bounds%endc)) - ! Averaging for patch evaporative flux variables call p2c (bounds, num_nolakec, filter_nolakec, & diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index b393e9dd65..38890d7c91 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -11,8 +11,8 @@ module clm_initializeMod use abortutils , only : endrun use clm_varctl , only : nsrest, nsrStartup, nsrContinue, nsrBranch use clm_varctl , only : is_cold_start, is_interpolated_start - use clm_varctl , only : create_glacier_mec_landunit, iulog - use clm_varctl , only : use_lch4, use_cn, use_cndv, use_c13, use_c14, use_ed + use clm_varctl , only : iulog + use clm_varctl , only : use_lch4, use_cn, use_cndv, use_c13, use_c14, use_fates use clm_varctl , only : nhillslope use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft, wt_glc_mec, topo_glc_mec, nhillcol use perf_mod , only : t_startf, t_stopf @@ -24,7 +24,8 @@ module clm_initializeMod use PatchType , only : patch ! instance use reweightMod , only : reweight_wrapup use filterMod , only : allocFilters, filter - use EDVecCohortType , only : ed_vec_cohort ! instance, used for domain decomp + use FatesInterfaceMod, only : set_fates_global_elements + use clm_instMod ! implicit none @@ -139,11 +140,7 @@ subroutine initialize1( ) write(iulog,*) 'Attempting to read ldomain from ',trim(fatmlndfrc) call shr_sys_flush(iulog) endif - if (create_glacier_mec_landunit) then - call surfrd_get_grid(begg, endg, ldomain, fatmlndfrc) - else - call surfrd_get_grid(begg, endg, ldomain, fatmlndfrc) - endif + call surfrd_get_grid(begg, endg, ldomain, fatmlndfrc) if (masterproc) then call domain_check(ldomain) endif @@ -165,13 +162,8 @@ subroutine initialize1( ) allocate (wt_nat_patch (begg:endg, natpft_lb:natpft_ub )) allocate (wt_cft (begg:endg, cft_lb:cft_ub )) allocate (fert_cft (begg:endg, cft_lb:cft_ub )) - if (create_glacier_mec_landunit) then - allocate (wt_glc_mec (begg:endg, maxpatch_glcmec)) - allocate (topo_glc_mec(begg:endg, maxpatch_glcmec)) - else - allocate (wt_glc_mec (1,1)) - allocate (topo_glc_mec(1,1)) - endif + allocate (wt_glc_mec (begg:endg, maxpatch_glcmec)) + allocate (topo_glc_mec(begg:endg, maxpatch_glcmec)) if(use_hillslope) then allocate (nhillcol (begg:endg )) endif @@ -184,6 +176,22 @@ subroutine initialize1( ) call surfrd_get_data(begg, endg, ldomain, fsurdat) + ! ------------------------------------------------------------------------ + ! Ask Fates to evaluate its own dimensioning needs. + ! This determines the total amount of space it requires in its largest + ! dimension. We are currently calling that the "cohort" dimension, but + ! it is really a utility dimension that captures the models largest + ! size need. + ! Sets: + ! fates_maxElementsPerPatch + ! fates_maxElementsPerSite (where a site is roughly equivalent to a column) + ! + ! (Note: fates_maxELementsPerSite is the critical variable used by CLM + ! to allocate space) + ! ------------------------------------------------------------------------ + + call set_fates_global_elements(use_fates) + ! ------------------------------------------------------------------------ ! Determine decomposition of subgrid scale landunits, columns, patches ! ------------------------------------------------------------------------ @@ -204,11 +212,6 @@ subroutine initialize1( ) call col%Init (bounds_proc%begc, bounds_proc%endc) call patch%Init(bounds_proc%begp, bounds_proc%endp) - if ( use_ed ) then - ! INTERF-TODO: THIS GUY NEEDS TO BE MOVED TO THE INTERFACE - call ed_vec_cohort%Init(bounds_proc%begCohort,bounds_proc%endCohort) - end if - ! Build hierarchy and topological info for derived types ! This is needed here for the following call to decompInit_glcp @@ -277,13 +280,13 @@ subroutine initialize2( ) use clm_varpar , only : nlevsno use clm_varcon , only : spval use clm_varctl , only : finidat, finidat_interp_source, finidat_interp_dest, fsurdat - use clm_varctl , only : use_century_decomp, single_column, scmlat, scmlon, use_cn, use_ed - use clm_varctl , only : use_crop + use clm_varctl , only : use_century_decomp, single_column, scmlat, scmlon, use_cn, use_fates + use clm_varctl , only : use_crop, ndep_from_cpl use clm_varorb , only : eccen, mvelpp, lambm0, obliqr use clm_time_manager , only : get_step_size, get_curr_calday use clm_time_manager , only : get_curr_date, get_nstep, advance_timestep use clm_time_manager , only : timemgr_init, timemgr_restart_io, timemgr_restart, is_restart - use C14BombSpikeMod , only : C14_init_BombSpike, use_c14_bombspike + use CIsoAtmTimeseriesMod , only : C14_init_BombSpike, use_c14_bombspike, C13_init_TimeSeries, use_c13_timeseries use DaylengthMod , only : InitDaylength, daylength use dynSubgridDriverMod , only : dynSubgrid_init use fileutils , only : getfil @@ -294,7 +297,6 @@ subroutine initialize2( ) use restFileMod , only : restFile_getfile, restFile_open, restFile_close use restFileMod , only : restFile_read, restFile_write use ndepStreamMod , only : ndep_init, ndep_interp - use CNDriverMod , only : CNDriverInit use LakeCon , only : LakeConInit use SatellitePhenologyMod , only : SatellitePhenologyInit, readAnnualVegetation, interpMonthlyVeg use SnowSnicarMod , only : SnowAge_init, SnowOptics_init @@ -388,11 +390,10 @@ subroutine initialize2( ) call InitDaylength(bounds_proc, declin=declin, declinm1=declinm1) ! Initialize maximum daylength, based on latitude and maximum declination - ! maximum declination hardwired for present-day orbital parameters, - ! +/- 23.4667 degrees = +/- 0.409571 radians, use negative value for S. Hem + ! given by the obliquity use negative value for S. Hem do g = bounds_proc%begg,bounds_proc%endg - max_decl = 0.409571 + max_decl = obliqr if (grc%lat(g) < 0._r8) max_decl = -max_decl grc%max_dayl(g) = daylength(grc%lat(g), max_decl) end do @@ -484,6 +485,10 @@ subroutine initialize2( ) if ( use_c14 .and. use_c14_bombspike ) then call C14_init_BombSpike() end if + + if ( use_c13 .and. use_c13_timeseries ) then + call C13_init_TimeSeries() + end if else call SatellitePhenologyInit(bounds_proc) end if @@ -576,8 +581,10 @@ subroutine initialize2( ) if (use_cn) then call t_startf('init_ndep') - call ndep_init(bounds_proc, NLFilename) - call ndep_interp(bounds_proc, atm2lnd_inst) + if (.not. ndep_from_cpl) then + call ndep_init(bounds_proc, NLFilename) + call ndep_interp(bounds_proc, atm2lnd_inst) + end if call t_stopf('init_ndep') end if @@ -644,20 +651,18 @@ subroutine initialize2( ) ! Initialize sno export state to send to glc !------------------------------------------------------------ - if (create_glacier_mec_landunit) then - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) - do nc = 1,nclumps - call get_clump_bounds(nc, bounds_clump) - - call t_startf('init_lnd2glc') - call lnd2glc_inst%update_lnd2glc(bounds_clump, & - filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & - temperature_inst, glacier_smb_inst, topo_inst, & - init=.true.) - call t_stopf('init_lnd2glc') - end do - !$OMP END PARALLEL DO - end if + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump) + do nc = 1,nclumps + call get_clump_bounds(nc, bounds_clump) + + call t_startf('init_lnd2glc') + call lnd2glc_inst%update_lnd2glc(bounds_clump, & + filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & + temperature_inst, glacier_smb_inst, topo_inst, & + init=.true.) + call t_stopf('init_lnd2glc') + end do + !$OMP END PARALLEL DO !------------------------------------------------------------ ! Deallocate wt_nat_patch @@ -669,13 +674,11 @@ subroutine initialize2( ) deallocate(wt_nat_patch) ! -------------------------------------------------------------- - ! Initialise the ED model state structure + ! Initialise the fates model state structure ! -------------------------------------------------------------- - if ( use_ed .and. .not.is_restart() ) then - - call clm_fates%init_coldstart(waterstate_inst,canopystate_inst) - + if ( use_fates .and. .not.is_restart() .and. finidat == ' ') then + call clm_fates%init_coldstart(waterstate_inst,canopystate_inst,soilstate_inst, frictionvel_inst) end if ! topo_glc_mec was allocated in initialize1, but needed to be kept around through diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 029c8531db..1c63659cba 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -8,11 +8,11 @@ module clm_instMod use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type use clm_varpar , only : ndecomp_pools, nlevdecomp_full - use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_ed, use_voc, use_hillslope + use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_fates, use_hillslope use clm_varctl , only : use_century_decomp, use_crop use clm_varcon , only : bdsno, c13ratio, c14ratio - use landunit_varcon , only : istice, istice_mec, istsoil + use landunit_varcon , only : istice_mec, istsoil use perf_mod , only : t_startf, t_stopf use controlMod , only : NLFilename @@ -82,6 +82,7 @@ module clm_instMod use SoilHydrologyInitTimeConstMod , only : SoilHydrologyInitTimeConst use SurfaceAlbedoMod , only : SurfaceAlbedoInitTimeConst use LakeCon , only : LakeConInit + use SoilBiogeochemPrecisionControlMod, only: SoilBiogeochemPrecisionControlInit ! implicit none public ! By default everything is public @@ -115,7 +116,7 @@ module clm_instMod type(glc2lnd_type) :: glc2lnd_inst type(lnd2atm_type) :: lnd2atm_inst type(lnd2glc_type) :: lnd2glc_inst - type(glc_behavior_type) :: glc_behavior + type(glc_behavior_type), target :: glc_behavior type(topo_type) :: topo_inst class(hillslope_geomorphology_type), allocatable :: hillslope_inst class(soil_water_retention_curve_type) , allocatable :: soil_water_retention_curve @@ -124,6 +125,7 @@ module clm_instMod ! Eventually bgc_vegetation_inst will be an allocatable instance of an abstract ! interface type(cn_vegetation_type) :: bgc_vegetation_inst + class(nutrient_competition_method_type), allocatable :: nutrient_competition_method ! Soil biogeochem types @@ -165,7 +167,7 @@ subroutine clm_instReadNML( NLFilename ) ! Read in any namelists that must be read for any clm object instances that need it call canopystate_inst%ReadNML( NLFilename ) call photosyns_inst%ReadNML( NLFilename ) - if (use_cn .or. use_ed) then + if (use_cn .or. use_fates) then call crop_inst%ReadNML( NLFilename ) end if @@ -182,6 +184,7 @@ subroutine clm_instInit(bounds) use SoilBiogeochemDecompCascadeBGCMod , only : init_decompcascade_bgc use SoilBiogeochemDecompCascadeCNMod , only : init_decompcascade_cn use SoilBiogeochemDecompCascadeContype , only : init_decomp_cascade_constants + use SoilBiogeochemCompetitionMod , only : SoilBiogeochemCompetitionInit use initVerticalMod , only : initVertical use accumulMod , only : print_accum_fields @@ -227,7 +230,7 @@ subroutine clm_instInit(bounds) ! feedback may not activate on time (or at all). So, as a compromise, we start with ! a small amount of snow in places that are likely to be snow-covered for much or ! all of the year. - if (lun%itype(l)==istice .or. lun%itype(l)==istice_mec) then + if (lun%itype(l)==istice_mec) then h2osno_col(c) = 100._r8 else if (lun%itype(l)==istsoil .and. abs(grc%latdeg(g)) >= 60._r8) then h2osno_col(c) = 100._r8 @@ -256,14 +259,7 @@ subroutine clm_instInit(bounds) ! Initialize clm->drv and drv->clm data structures call atm2lnd_inst%Init( bounds, NLFilename ) - call lnd2atm_inst%Init( bounds ) - - ! Initialize glc2lnd and lnd2glc even if running without create_glacier_mec_landunit, - ! because at least some variables (such as the icemask) are referred to in code that - ! is executed even when running without glc_mec. - ! - ! NOTE(wjs, 2016-04-01) I'm not sure if that's true any more (it isn't true for - ! icemask), but I'm keeping this as is for now anyway. + call lnd2atm_inst%Init( bounds, NLFilename ) call glc2lnd_inst%Init( bounds, glc_behavior ) call lnd2glc_inst%Init( bounds ) @@ -304,7 +300,7 @@ subroutine clm_instInit(bounds) call energyflux_inst%Init(bounds, temperature_inst%t_grnd_col(begc:endc), & IsSimpleBuildTemp(), IsProgBuildTemp() ) - call aerosol_inst%Init(bounds) + call aerosol_inst%Init(bounds, NLFilename) call frictionvel_inst%Init(bounds) @@ -339,17 +335,15 @@ subroutine clm_instInit(bounds) call topo_inst%Init(bounds) ! Note - always initialize the memory for ch4_inst - call ch4_inst%Init(bounds, soilstate_inst%cellorg_col(begc:endc, 1:), fsurdat) + call ch4_inst%Init(bounds, soilstate_inst%cellorg_col(begc:endc, 1:), fsurdat, nlfilename) - if (use_voc ) then - call vocemis_inst%Init(bounds) - end if + call vocemis_inst%Init(bounds) call fireemis_inst%Init(bounds) call drydepvel_inst%Init(bounds) - if (use_cn .or. use_ed ) then + if (use_cn .or. use_fates ) then ! Initialize soilbiogeochem_state_inst @@ -389,7 +383,7 @@ subroutine clm_instInit(bounds) end if - if ( use_cn .or. use_ed) then + if ( use_cn .or. use_fates) then ! Initalize soilbiogeochem nitrogen types @@ -400,26 +394,25 @@ subroutine clm_instInit(bounds) call soilbiogeochem_nitrogenflux_inst%Init(bounds) + ! Initialize precision control for soil biogeochemistry + call SoilBiogeochemPrecisionControlInit( soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & + c14_soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst) + end if ! end of if use_cn ! Note - always call Init for bgc_vegetation_inst: some pieces need to be initialized always call bgc_vegetation_inst%Init(bounds, nlfilename) - if (use_cn .or. use_ed) then + if (use_cn .or. use_fates) then call crop_inst%Init(bounds) end if - ! NOTE (MV, 10-24-2014): because ed_allsites is currently passed as arguments to - ! biogeophys routines in the present implementation - it needs to be allocated - - ! if use_ed is not set, then this will not contain any significant memory - ! if use_ed is true, then the actual memory for all of the ED data structures - ! is allocated in the call to EDInitMod - called from clm_initialize - ! NOTE (SPM, 10-27-2015) ... check on deallocation of ed_allsites_inst - ! NOTE (RGK, 04-25-2016) : Updating names, ED is now part of FATES - ! Incrementally changing to ED names to FATES - - call clm_fates%Init(bounds,use_ed) - call clm_fates%init_allocate() + + ! Initialize the Functionaly Assembled Terrestrial Ecosystem Simulator (FATES) + ! + if (use_fates) then + call clm_fates%Init(bounds) + end if deallocate (h2osno_col) deallocate (snow_depth_col) @@ -460,7 +453,6 @@ subroutine clm_instRest(bounds, ncid, flag) ! ! !USES: use ncdio_pio , only : file_desc_t - use EDRestVectorMod , only : EDRest use UrbanParamsType , only : IsSimpleBuildTemp, IsProgBuildTemp use decompMod , only : get_proc_bounds, get_proc_clumps, get_clump_bounds @@ -525,35 +517,43 @@ subroutine clm_instRest(bounds, ncid, flag) call ch4_inst%restart(bounds, ncid, flag=flag) end if - if (use_cn .or. use_ed) then + if ( use_cn ) then + ! Need to do vegetation restart before soil bgc restart to get totvegc_col for purpose + ! of resetting soil carbon at exit spinup when no vegetation is growing. + call bgc_vegetation_inst%restart(bounds, ncid, flag=flag) + + call soilbiogeochem_nitrogenstate_inst%restart(bounds, ncid, flag=flag, & + totvegc_col=bgc_vegetation_inst%get_totvegc_col(bounds)) + call soilbiogeochem_nitrogenflux_inst%restart(bounds, ncid, flag=flag) + + call crop_inst%restart(bounds, ncid, flag=flag) + end if + + if (use_cn .or. use_fates) then call soilbiogeochem_state_inst%restart(bounds, ncid, flag=flag) - call soilbiogeochem_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c12') + call soilbiogeochem_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c12', & + totvegc_col=bgc_vegetation_inst%get_totvegc_col(bounds)) + if (use_c13) then call c13_soilbiogeochem_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c13', & + totvegc_col=bgc_vegetation_inst%get_totvegc_col(bounds), & c12_soilbiogeochem_carbonstate_inst=soilbiogeochem_carbonstate_inst) end if if (use_c14) then call c14_soilbiogeochem_carbonstate_inst%restart(bounds, ncid, flag=flag, carbon_type='c14', & + totvegc_col=bgc_vegetation_inst%get_totvegc_col(bounds), & c12_soilbiogeochem_carbonstate_inst=soilbiogeochem_carbonstate_inst) end if call soilbiogeochem_carbonflux_inst%restart(bounds, ncid, flag=flag) endif - if ( use_cn ) then - - call soilbiogeochem_nitrogenstate_inst%restart(bounds, ncid, flag=flag) - call soilbiogeochem_nitrogenflux_inst%restart(bounds, ncid, flag=flag) - - call bgc_vegetation_inst%restart(bounds, ncid, flag=flag) - - call crop_inst%restart(bounds, ncid, flag=flag) - end if - if (use_ed) then + if (use_fates) then - ! Bounds are not passed to FATES init_restart because - ! we call a loop on clumps within this subroutine anyway - call clm_fates%init_restart(ncid,flag, waterstate_inst, canopystate_inst) + call clm_fates%restart(bounds, ncid, flag=flag, & + waterstate_inst=waterstate_inst, & + canopystate_inst=canopystate_inst, & + frictionvel_inst=frictionvel_inst) end if diff --git a/src/main/clm_varcon.F90 b/src/main/clm_varcon.F90 index 45756f96ab..6812e507a8 100644 --- a/src/main/clm_varcon.F90 +++ b/src/main/clm_varcon.F90 @@ -73,7 +73,7 @@ module clm_varcon real(r8) :: tkair = 0.023_r8 ! thermal conductivity of air [W/m/K] real(r8) :: tkice = 2.290_r8 ! thermal conductivity of ice [W/m/K] real(r8) :: tkwat = 0.57_r8 ! thermal conductivity of water [W/m/K] - real(r8) :: tfrz = SHR_CONST_TKFRZ ! freezing temperature [K] + real(r8), parameter :: tfrz = SHR_CONST_TKFRZ ! freezing temperature [K] real(r8), parameter :: tcrit = 2.5_r8 ! critical temperature to determine rain or snow real(r8) :: o2_molar_const = 0.209_r8 ! constant atmospheric O2 molar ratio (mol/mol) real(r8) :: oneatm = 1.01325e5_r8 ! one standard atmospheric pressure [Pa] @@ -125,6 +125,8 @@ module clm_varcon real(r8) :: csol_bedrock = 2.0e6_r8 ! vol. heat capacity of granite/sandstone J/(m3 K)(Shabbir, 2000) real(r8), parameter :: zmin_bedrock = 0.4_r8 ! minimum soil depth [m] + real(r8), parameter :: aquifer_water_baseline = 5000._r8 ! baseline value for water in the unconfined aquifer [mm] + !!! C13 real(r8), parameter :: preind_atm_del13c = -6.0 ! preindustrial value for atmospheric del13C real(r8), parameter :: preind_atm_ratio = SHR_CONST_PDB + (preind_atm_del13c * SHR_CONST_PDB)/1000.0 ! 13C/12C diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 47969bdf94..ead23e7511 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -94,10 +94,10 @@ module clm_varctl character(len=fname_len), public :: fsnowaging = ' ' ! snow aging parameters file name !---------------------------------------------------------- - ! Flag to turn on MEGAN VOC's + ! Flag to read ndep rather than obtain it from coupler !---------------------------------------------------------- - - logical, public :: use_voc = .true. + + logical, public :: ndep_from_cpl = .false. !---------------------------------------------------------- ! Interpolation of finidat if requested @@ -193,11 +193,11 @@ module clm_varctl logical, public :: use_c14 = .false. ! true => use C-14 model !---------------------------------------------------------- - ! ED switches + ! fates switches !---------------------------------------------------------- - logical, public :: use_ed = .false. ! true => use ED - logical, public :: use_ed_spit_fire = .false. ! true => use spitfire model + logical, public :: use_fates = .false. ! true => use ED + logical, public :: use_fates_spitfire = .false. ! true => use spitfire model !---------------------------------------------------------- ! LUNA switches @@ -261,9 +261,6 @@ module clm_varctl ! glacier_mec control variables: default values (may be overwritten by namelist) !---------------------------------------------------------- - ! glacier_mec landunit is not created (set in controlMod) - logical , public :: create_glacier_mec_landunit = .false. - ! true => CLM glacier area & topography changes dynamically logical , public :: glc_do_dynglacier = .false. @@ -311,6 +308,11 @@ module clm_varctl ! namelist: write CH4 extra diagnostic output logical, public :: hist_wrtch4diag = .false. + !---------------------------------------------------------- + ! ED/FATES + !---------------------------------------------------------- + character(len=fname_len), public :: fates_paramfile = ' ' + !---------------------------------------------------------- ! Migration of CPP variables !---------------------------------------------------------- diff --git a/src/main/clm_varpar.F90 b/src/main/clm_varpar.F90 index aafc38ea64..d2011dcae4 100644 --- a/src/main/clm_varpar.F90 +++ b/src/main/clm_varpar.F90 @@ -11,7 +11,7 @@ module clm_varpar use clm_varctl , only: use_century_decomp, use_c13, use_c14 use clm_varctl , only: iulog, use_crop, create_crop_landunit, irrigate use clm_varctl , only: use_vichydro, soil_layerstruct - use clm_varctl , only: use_ed + use clm_varctl , only: use_fates ! ! !PUBLIC TYPES: @@ -190,7 +190,7 @@ subroutine clm_varpar_init() write(iulog, *) end if - if ( use_ed ) then + if ( use_fates ) then i_cwd = 0 if (use_century_decomp) then ndecomp_pools = 6 diff --git a/src/main/column_varcon.F90 b/src/main/column_varcon.F90 index 06dc5cfbbf..287df93b72 100644 --- a/src/main/column_varcon.F90 +++ b/src/main/column_varcon.F90 @@ -46,6 +46,10 @@ function is_hydrologically_active(col_itype, lun_itype) & ! Returns a logical value saying whether the given column type is hydrologically ! active ! + ! Note that calling this can be bad for performance, because it operates on a single + ! point rather than a loop. So in performance-critical parts of the code (or just + ! about anywhere, really), you should use the pre-set col%hydrologically_active(c). + ! ! !USES: use landunit_varcon, only : istsoil, istcrop ! diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index da1bc2e436..80e2194958 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -35,7 +35,7 @@ module controlMod use HumanIndexMod , only: HumanIndexReadNML use CNPrecisionControlMod , only: CNPrecisionControlReadNML use CNSharedParamsMod , only: anoxia_wtsat, use_fun - use C14BombSpikeMod , only: use_c14_bombspike, atm_c14_filename + use CIsoAtmTimeseriesMod , only: use_c14_bombspike, atm_c14_filename, use_c13_timeseries, atm_c13_filename use SoilBiogeochemCompetitionMod , only: suplnitro, suplnNon use SoilBiogeochemLittVertTranspMod , only: som_adv_flux, max_depth_cryoturb use SoilBiogeochemVerticalProfileMod , only: surfprof_exp @@ -43,6 +43,7 @@ module controlMod use SoilHydrologyMod , only: soilHydReadNML use CNFireFactoryMod , only: CNFireReadNML use CanopyFluxesMod , only: CanopyFluxesReadNML + use seq_drydep_mod , only: drydep_method, DD_XLND, n_drydep use clm_varctl ! ! !PUBLIC TYPES: @@ -208,7 +209,8 @@ subroutine control_init( ) namelist /clm_inparm/ use_c13, use_c14 - namelist /clm_inparm/ use_ed, use_ed_spit_fire + + namelist /clm_inparm/ fates_paramfile, use_fates, use_fates_spitfire ! CLM 5.0 nitrogen flags namelist /clm_inparm/ use_flexibleCN, use_luna @@ -229,7 +231,7 @@ subroutine control_init( ) namelist /clm_inparm/ use_dynroot namelist /clm_inparm/ & - use_c14_bombspike, atm_c14_filename + use_c14_bombspike, atm_c14_filename, use_c13_timeseries, atm_c13_filename ! All old cpp-ifdefs are below and have been converted to namelist variables @@ -330,28 +332,17 @@ subroutine control_init( ) end if call clm_varctl_set( nsrest_in=override_nsrest ) end if - - if (maxpatch_glcmec > 0) then - create_glacier_mec_landunit = .true. - else - create_glacier_mec_landunit = .false. - end if - if (use_crop .and. (use_c13 .or. use_c14)) then - call endrun(msg=' ERROR:: CROP and C13/C14 can NOT be on at the same time'//& - errMsg(sourcefile, __LINE__)) + if (maxpatch_glcmec <= 0) then + call endrun(msg=' ERROR: maxpatch_glcmec must be at least 1 ' // & + errMsg(sourcefile, __LINE__)) end if - + if (use_crop .and. .not. create_crop_landunit) then call endrun(msg=' ERROR: prognostic crop Patches require create_crop_landunit=.true.'//& errMsg(sourcefile, __LINE__)) end if - if (.not. use_crop .and. irrigate) then - call endrun(msg=' ERROR: irrigate = .true. requires CROP model active.'//& - errMsg(sourcefile, __LINE__)) - end if - if (use_lch4 .and. use_vertsoilc) then anoxia = .true. else @@ -359,18 +350,43 @@ subroutine control_init( ) end if ! ---------------------------------------------------------------------- - !TURN OFF MEGAN VOCs if crop prognostic is on - ! This is a temporary place holder and should be removed once MEGAN VOCs and - ! crop ar compatible - if (use_crop) then - use_voc = .false. - end if + ! Check compatibility with the FATES model + if ( use_fates ) then - ! ---------------------------------------------------------------------- - ! ABORT if use_cn AND use_ed are both true - if (use_ed .and. use_cn) then - call endrun(msg=' ERROR: use_cn and use_ed cannot both be set to true.'//& - errMsg(sourcefile, __LINE__)) + if ( use_cn) then + call endrun(msg=' ERROR: use_cn and use_fates cannot both be set to true.'//& + errMsg(sourcefile, __LINE__)) + end if + + if ( use_hydrstress) then + call endrun(msg=' ERROR: use_hydrstress and use_fates cannot both be set to true.'//& + errMsg(sourcefile, __LINE__)) + end if + + if ( use_crop ) then + call endrun(msg=' ERROR: use_crop and use_fates cannot both be set to true.'//& + errMsg(sourcefile, __LINE__)) + end if + + if( use_lch4 ) then + call endrun(msg=' ERROR: use_lch4 (methane) and use_fates cannot both be set to true.'//& + errMsg(sourcefile, __LINE__)) + end if + + if ( n_drydep > 0 .and. drydep_method /= DD_XLND ) then + call endrun(msg=' ERROR: dry deposition via ML Welsey is not compatible with FATES.'//& + errMsg(sourcefile, __LINE__)) + end if + + if( use_luna ) then + call endrun(msg=' ERROR: luna is not compatible with FATES.'//& + errMsg(sourcefile, __LINE__)) + end if + + if (use_ozone ) then + call endrun(msg=' ERROR: ozone is not compatible with FATES.'//& + errMsg(sourcefile, __LINE__)) + end if end if ! If nfix_timeconst is equal to the junk default value, then it was not specified @@ -554,7 +570,6 @@ subroutine control_spmd() call mpi_bcast (use_crop, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_fertilizer, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_grainproduct, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (use_voc, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_ozone, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_snicar_frc, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_vancouver, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -597,8 +612,10 @@ subroutine control_spmd() call mpi_bcast (use_c13, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_c14, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (use_ed, 1, MPI_LOGICAL, 0, mpicom, ier) - call mpi_bcast (use_ed_spit_fire, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_fates, 1, MPI_LOGICAL, 0, mpicom, ier) + + call mpi_bcast (use_fates_spitfire, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (fates_paramfile, len(fates_paramfile) , MPI_CHARACTER, 0, mpicom, ier) ! flexibleCN nitrogen model call mpi_bcast (use_flexibleCN, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -646,6 +663,8 @@ subroutine control_spmd() if (use_cn) then call mpi_bcast (use_c14_bombspike, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (atm_c14_filename, len(atm_c14_filename), MPI_CHARACTER, 0, mpicom, ier) + call mpi_bcast (use_c13_timeseries, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (atm_c13_filename, len(atm_c13_filename), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (use_fun, 1, MPI_LOGICAL, 0, mpicom, ier) end if @@ -680,7 +699,6 @@ subroutine control_spmd() call mpi_bcast (n_melt_glcmec, 1, MPI_REAL8, 0, mpicom, ier) ! glacier_mec variables - call mpi_bcast (create_glacier_mec_landunit, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (maxpatch_glcmec, 1, MPI_INTEGER, 0, mpicom, ier) call mpi_bcast (glc_do_dynglacier, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (glcmec_downscale_longwave, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -814,6 +832,8 @@ subroutine control_print () if (use_cn) then write(iulog, *) ' use_c13 : ', use_c13 + write(iulog, *) ' use_c13_timeseries : ', use_c13_timeseries + write(iulog, *) ' atm_c13_filename : ', atm_c13_filename write(iulog, *) ' use_c14 : ', use_c14 write(iulog, *) ' use_c14_bombspike : ', use_c14_bombspike write(iulog, *) ' atm_c14_filename : ', atm_c14_filename @@ -836,20 +856,18 @@ subroutine control_print () write(iulog,*) ' snow-covered fraction during melt (mm) =', int_snow_max write(iulog,*) ' SCA shape parameter for glc_mec columns (n_melt_glcmec) =', n_melt_glcmec - if (create_glacier_mec_landunit) then - write(iulog,*) ' glc number of elevation classes =', maxpatch_glcmec + write(iulog,*) ' glc number of elevation classes =', maxpatch_glcmec if (glcmec_downscale_longwave) then write(iulog,*) ' Longwave radiation will be downscaled' else write(iulog,*) ' Longwave radiation will NOT be downscaled' endif - if (glc_do_dynglacier) then - write(iulog,*) ' glc CLM glacier areas and topography WILL evolve dynamically' - else - write(iulog,*) ' glc CLM glacier areas and topography will NOT evolve dynamically' - end if - write(iulog,*) ' glc snow persistence max days = ', glc_snow_persistence_max_days - endif + if (glc_do_dynglacier) then + write(iulog,*) ' glc CLM glacier areas and topography WILL evolve dynamically' + else + write(iulog,*) ' glc CLM glacier areas and topography will NOT evolve dynamically' + end if + write(iulog,*) ' glc snow persistence max days = ', glc_snow_persistence_max_days if (nsrest == nsrStartup) then if (finidat /= ' ') then @@ -927,6 +945,13 @@ subroutine control_print () write(iulog, *) ' carbon_resp_opt = ', carbon_resp_opt end if write(iulog, *) ' use_luna = ', use_luna + + write(iulog, *) ' ED/FATES: ' + write(iulog, *) ' use_fates = ', use_fates + if (use_fates) then + write(iulog, *) ' use_fates_spitfire = ', use_fates_spitfire + write(iulog, *) ' fates_paramfile = ', fates_paramfile + end if end subroutine control_print diff --git a/src/main/decompInitMod.F90 b/src/main/decompInitMod.F90 index 2a94eda31c..166ec29068 100644 --- a/src/main/decompInitMod.F90 +++ b/src/main/decompInitMod.F90 @@ -11,16 +11,16 @@ module decompInitMod use shr_log_mod , only : errMsg => shr_log_errMsg use spmdMod , only : masterproc, iam, npes, mpicom, comp_id use abortutils , only : endrun - use clm_varctl , only : iulog, use_ed + use clm_varctl , only : iulog, use_fates use clm_varcon , only : grlnd use GridcellType , only : grc use LandunitType , only : lun use ColumnType , only : col - use PatchType , only : patch - use EDVecCohortType , only : ed_vec_cohort + use PatchType , only : patch use glcBehaviorMod , only : glc_behavior_type use decompMod use mct_mod , only : mct_gsMap_init, mct_gsMap_ngseg, mct_gsMap_nlseg, mct_gsmap_gsize + use FatesInterfaceMod, only : fates_maxElementsPerSite ! ! !PUBLIC TYPES: implicit none @@ -503,7 +503,7 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) integer :: numl ! total number of landunits across all processors integer :: numc ! total number of columns across all processors integer :: nump ! total number of patches across all processors - integer :: numCohort ! ED cohorts + integer :: numCohort ! fates cohorts integer :: icells ! temporary integer :: ilunits ! temporary integer :: icols ! temporary @@ -551,7 +551,7 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) pstart(:) = 0 allocate(pcount(begg:endg)) pcount(:) = 0 - if ( use_ed ) then + if ( use_fates ) then allocate(coStart(begg:endg)) coStart(:) = 0 endif @@ -569,7 +569,7 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) lcount(gi) = ilunits ! number of landunits for local gridcell index gi ccount(gi) = icols ! number of columns for local gridcell index gi pcount(gi) = ipatches ! number of patches for local gridcell index gi - coCount(gi) = icohorts ! number of ED cohorts for local gricell index gi + coCount(gi) = icohorts ! number of fates cohorts for local gricell index gi enddo @@ -638,7 +638,7 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) endif call scatter_data_from_master(pstart, arrayglob, grlnd) - if ( use_ed ) then + if ( use_fates ) then arrayglob(:) = 0 call gather_data_to_master(coCount, arrayglob, grlnd) if (masterproc) then @@ -726,12 +726,14 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) call mct_gsMap_init(gsmap_patch_gdc2glo, gindex, mpicom, comp_id, locsize, globsize) deallocate(gindex) - if ( use_ed ) then - ! ED cohort gsMap + ! FATES gsmap for the cohort/element vector + + if ( use_fates ) then allocate(gindex(begCohort:endCohort)) ioff(:) = 0 + ci = begc do coi = begCohort,endCohort - ci = ed_vec_cohort%column(coi) ! function call to get column for this cohort idx + if ( mod(coi, fates_maxElementsPerSite ) == 0 ) ci = ci + 1 gi = col%gridcell(ci) ! convert column into gridcell gindex(coi) = coStart(gi) + ioff(gi) ioff(gi) = ioff(gi) + 1 @@ -747,7 +749,7 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) deallocate(lstart, lcount) deallocate(cstart, ccount) deallocate(pstart, pcount) - if ( use_ed ) then + if ( use_fates ) then deallocate(coStart,coCount) endif deallocate(ioff) diff --git a/src/main/decompMod.F90 b/src/main/decompMod.F90 index 99390f0c72..13204fabca 100644 --- a/src/main/decompMod.F90 +++ b/src/main/decompMod.F90 @@ -60,7 +60,7 @@ module decompMod integer,public :: numl ! total number of landunits on all procs integer,public :: numc ! total number of columns on all procs integer,public :: nump ! total number of patchs on all procs - integer,public :: numCohort ! total number of ED cohorts on all procs + integer,public :: numCohort ! total number of fates cohorts on all procs type bounds_type integer :: begg, endg ! beginning and ending gridcell index @@ -231,7 +231,7 @@ subroutine get_clump_bounds_new (n, bounds) !------------------------------------------------------------------------------ ! Make sure this IS being called from a threaded region #ifdef _OPENMP - ! FIX(SPM, 090314) - for debugging ED and openMP + ! FIX(SPM, 090314) - for debugging fates and openMP !write(iulog,*) 'SPM omp debug decompMod 1 ', & !OMP_GET_NUM_THREADS(),OMP_GET_MAX_THREADS(),OMP_GET_THREAD_NUM() @@ -301,7 +301,7 @@ subroutine get_proc_bounds_new (bounds) !------------------------------------------------------------------------------ ! Make sure this is NOT being called from a threaded region #ifdef _OPENMP - ! FIX(SPM, 090314) - for debugging ED and openMP + ! FIX(SPM, 090314) - for debugging fates and openMP !write(*,*) 'SPM omp debug decompMod 2 ', & !OMP_GET_NUM_THREADS(),OMP_GET_MAX_THREADS(),OMP_GET_THREAD_NUM() @@ -394,7 +394,7 @@ subroutine get_proc_global(ng, nl, nc, np, nCohorts) integer, optional, intent(out) :: nl ! total number of landunits across all processors integer, optional, intent(out) :: nc ! total number of columns across all processors integer, optional, intent(out) :: np ! total number of patchs across all processors - integer, optional, intent(out) :: nCohorts ! total number ED cohorts + integer, optional, intent(out) :: nCohorts ! total number fates cohorts !------------------------------------------------------------------------------ if (present(np)) np = nump diff --git a/src/main/filterColMod.F90 b/src/main/filterColMod.F90 index cec06f501f..0c3e63ce85 100644 --- a/src/main/filterColMod.F90 +++ b/src/main/filterColMod.F90 @@ -58,6 +58,9 @@ module filterColMod ! of interest public :: col_filter_from_grcflags_ltypes + ! Create a filter from another filter subset by a column-level logical array + public :: col_filter_from_filter_and_logical_array + ! !PRIVATE ROUTINES: ! Whether a given column should be included in the filter based on the active flag @@ -324,6 +327,45 @@ function col_filter_from_grcflags_ltypes(bounds, grcflags, ltypes, include_inact end function col_filter_from_grcflags_ltypes + !----------------------------------------------------------------------- + function col_filter_from_filter_and_logical_array(bounds, num_orig, filter_orig, logical_col) & + result(filter) + ! + ! !DESCRIPTION: + ! Create a filter from another filter subset by a column-level logical array + ! + ! !ARGUMENTS: + type(filter_col_type) :: filter ! function result + + ! Accepts separate num & indices arguments rather than a filter of filter_col_type so + ! that this function can be called with old-style filters, where these were stored + ! separately rather than being bundled together. + type(bounds_type), intent(in) :: bounds + integer, intent(in) :: num_orig ! number of points in original filter + integer, intent(in) :: filter_orig(:) ! column indices in original filter + logical, intent(in) :: logical_col(bounds%begc:) ! column-level logical array + ! + ! !LOCAL VARIABLES: + integer :: fc, c + + character(len=*), parameter :: subname = 'col_filter_from_filter_and_logical_array' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(logical_col) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + filter = col_filter_empty(bounds) + + do fc = 1, num_orig + c = filter_orig(fc) + if (logical_col(c)) then + filter%num = filter%num + 1 + filter%indices(filter%num) = c + end if + end do + + end function col_filter_from_filter_and_logical_array + + !----------------------------------------------------------------------- pure function include_based_on_active(c, include_inactive) result(include_point) ! diff --git a/src/main/filterMod.F90 b/src/main/filterMod.F90 index 09dd1cdaf6..2831abb6a3 100644 --- a/src/main/filterMod.F90 +++ b/src/main/filterMod.F90 @@ -12,7 +12,7 @@ module filterMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun - use clm_varctl , only : iulog, create_glacier_mec_landunit + use clm_varctl , only : iulog use decompMod , only : bounds_type use GridcellType , only : grc use LandunitType , only : lun @@ -297,7 +297,6 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio use decompMod , only : BOUNDS_LEVEL_CLUMP use pftconMod , only : npcropmin use landunit_varcon , only : istsoil, istcrop, istice_mec - use column_varcon , only : is_hydrologically_active use clm_varcon , only : ispval ! ! !ARGUMENTS: @@ -407,8 +406,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio f = 0 do c = bounds%begc,bounds%endc if (col%active(c) .or. include_inactive) then - l =col%landunit(c) - if (is_hydrologically_active(col_itype=col%itype(c), lun_itype=lun%itype(l))) then + if (col%hydrologically_active(c)) then f = f + 1 this_filter(nc)%hydrologyc(f) = c end if @@ -561,8 +559,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio ! this region, in order to provide SMB forcing for the bare ground elevation ! class (elevation class 0). if ( glc_behavior%melt_replaced_by_ice_grc(g) .and. & - (lun%itype(l) == istice_mec .or. & - (lun%itype(l) == istsoil .and. create_glacier_mec_landunit))) then + (lun%itype(l) == istice_mec .or. lun%itype(l) == istsoil)) then f = f + 1 this_filter(nc)%do_smb_c(f) = c end if diff --git a/src/main/glc2lndMod.F90 b/src/main/glc2lndMod.F90 index c95dad014b..9df55b5e70 100644 --- a/src/main/glc2lndMod.F90 +++ b/src/main/glc2lndMod.F90 @@ -3,15 +3,6 @@ module glc2lndMod !----------------------------------------------------------------------- ! !DESCRIPTION: ! Handle arrays used for exchanging data from glc to clm. - ! For now glc datais send and received on the lnd decomposition and grid. - ! - ! The fields sent from the lnd component to the glc component via - ! the coupler are labeled 's2x', or sno to coupler. - ! The fields received by the lnd component from the glc component - ! via the coupler are labeled 'x2s', or coupler to sno. - ! 'Sno' is a misnomer in that the exchanged data are related to - ! the ice beneath the snow, not the snow itself. But by CESM convention, - ! 'ice' refers to sea ice, not land ice. ! ! !USES: #include "shr_assert.h" @@ -20,7 +11,7 @@ module glc2lndMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use clm_varpar , only : maxpatch_glcmec - use clm_varctl , only : iulog + use clm_varctl , only : iulog, glc_do_dynglacier use clm_varcon , only : nameg, spval, ispval use abortutils , only : endrun use GridcellType , only : grc @@ -40,16 +31,25 @@ module glc2lndMod ! glc -> land variables structure type, public :: glc2lnd_type - real(r8), pointer :: frac_grc (:,:) => null() - real(r8), pointer :: topo_grc (:,:) => null() - real(r8), pointer :: hflx_grc (:,:) => null() + ! ------------------------------------------------------------------------ + ! Public data + ! ------------------------------------------------------------------------ + + ! Where we should do runoff routing that is appropriate for having a dynamic icesheet underneath. + real(r8), pointer :: glc_dyn_runoff_routing_grc (:) => null() + + ! ------------------------------------------------------------------------ + ! Private data + ! ------------------------------------------------------------------------ + + type(glc_behavior_type), pointer, private :: glc_behavior ! reference to the glc_behavior instance - ! TODO(wjs, 2016-04-01) If the setting of icemask and icemask_coupled_fluxes were - ! moved out of lnd_import_export into this module, then these two variables could be - ! made private. + real(r8), pointer, private :: frac_grc (:,:) => null() + real(r8), pointer, private :: topo_grc (:,:) => null() + real(r8), pointer, private :: hflx_grc (:,:) => null() ! Area in which GLC model can accept surface mass balance, received from glc (0-1) - real(r8), pointer :: icemask_grc (:) => null() + real(r8), pointer, private :: icemask_grc (:) => null() ! icemask_coupled_fluxes_grc is like icemask_grc, but the mask only contains icesheet ! points that potentially send non-zero fluxes to the coupler. i.e., it does not @@ -62,10 +62,7 @@ module glc2lndMod ! could theoretically have an icesheet whose areas are evolving, and CLM is updating ! its glacier areas to match, but where we're zeroing out the fluxes sent to the ! coupler, and so we're using the non-dynamic form of runoff routing in CLM.) - real(r8), pointer :: icemask_coupled_fluxes_grc (:) => null() - - ! Where we should do runoff routing that is appropriate for having a dynamic icesheet underneath. - logical , pointer :: glc_dyn_runoff_routing_grc (:) => null() + real(r8), pointer, private :: icemask_coupled_fluxes_grc (:) => null() contains @@ -75,9 +72,19 @@ module glc2lndMod procedure, public :: Init procedure, public :: Clean - procedure, public :: update_glc2lnd_non_topo ! update everything except topographic heights + + ! In each timestep, these routines should be called in order (though they don't need + ! to be called all at once): + ! - set_glc2lnd_fields + ! - update_glc2lnd_fracs + ! - update_glc2lnd_topo + procedure, public :: set_glc2lnd_fields ! set coupling fields sent from glc to lnd + procedure, public :: update_glc2lnd_fracs ! update subgrid fractions based on input from GLC procedure, public :: update_glc2lnd_topo ! update topographic heights + ! For unit testing only: + procedure, public :: for_test_set_glc2lnd_fields_directly ! set glc2lnd fields directly in a unit testing context + ! ------------------------------------------------------------------------ ! Private routines ! ------------------------------------------------------------------------ @@ -95,9 +102,6 @@ module glc2lndMod ! update glc_dyn_runoff_routing field based on input from GLC procedure, private :: update_glc2lnd_dyn_runoff_routing - ! update subgrid fractions based on input from GLC - procedure, private :: update_glc2lnd_fracs - end type glc2lnd_type character(len=*), parameter, private :: sourcefile = & @@ -112,7 +116,7 @@ subroutine Init(this, bounds, glc_behavior) class(glc2lnd_type) :: this type(bounds_type), intent(in) :: bounds - type(glc_behavior_type), intent(in) :: glc_behavior + type(glc_behavior_type), intent(in), target :: glc_behavior call this%InitAllocate(bounds) call this%InitHistory(bounds) @@ -141,7 +145,7 @@ subroutine InitAllocate(this, bounds) allocate(this%hflx_grc (begg:endg,0:maxpatch_glcmec)) ; this%hflx_grc (:,:) = nan allocate(this%icemask_grc (begg:endg)) ; this%icemask_grc (:) = nan allocate(this%icemask_coupled_fluxes_grc (begg:endg)) ; this%icemask_coupled_fluxes_grc (:) = nan - allocate(this%glc_dyn_runoff_routing_grc (begg:endg)) ; this%glc_dyn_runoff_routing_grc (:) = .false. + allocate(this%glc_dyn_runoff_routing_grc (begg:endg)) ; this%glc_dyn_runoff_routing_grc (:) = nan end subroutine InitAllocate @@ -163,13 +167,11 @@ subroutine InitHistory(this, bounds) begg = bounds%begg endg = bounds%endg - - if (maxpatch_glcmec > 0) then - this%icemask_grc(begg:endg) = spval - call hist_addfld1d (fname='ICE_MODEL_FRACTION', units='unitless', & - avgflag='I', long_name='Ice sheet model fractional coverage', & - ptr_gcell=this%icemask_grc) - end if + + this%icemask_grc(begg:endg) = spval + call hist_addfld1d (fname='ICE_MODEL_FRACTION', units='unitless', & + avgflag='I', long_name='Ice sheet model fractional coverage', & + ptr_gcell=this%icemask_grc, default='inactive') end subroutine InitHistory @@ -182,38 +184,33 @@ subroutine InitCold(this, bounds, glc_behavior) ! !ARGUMENTS: class(glc2lnd_type) :: this type(bounds_type), intent(in) :: bounds - type(glc_behavior_type), intent(in) :: glc_behavior + type(glc_behavior_type), intent(in), target :: glc_behavior ! ! !LOCAL VARIABLES: integer :: begg, endg - integer :: g character(len=*), parameter :: subname = 'InitCold' !----------------------------------------------------------------------- begg = bounds%begg endg = bounds%endg - + + this%glc_behavior => glc_behavior + this%frac_grc(begg:endg, :) = 0.0_r8 this%topo_grc(begg:endg, :) = 0.0_r8 this%hflx_grc(begg:endg, :) = 0.0_r8 - ! Since we don't have GLC's icemask yet in initialization, we use has_virtual_columns - ! as a rough initial guess. Note that has_virtual_columns is guaranteed to be a - ! superset of the icemask. - do g = begg, endg - if (glc_behavior%has_virtual_columns_grc(g)) then - this%icemask_grc(g) = 1._r8 - else - this%icemask_grc(g) = 0._r8 - end if - end do - - ! initialize icemask_coupled_fluxes to 0; this seems safest in case we aren't coupled - ! to CISM (to ensure that we use the uncoupled form of runoff routing) + ! When running with a stub glc model, it's important that icemask_grc be initialized + ! to 0 everywhere. With an active glc model, icemask_grc will be updated in the first + ! time step, and it isn't needed before then, so it's safe to initialize it to 0. + ! Since icemask is 0, icemask_coupled_fluxes needs to be 0, too (and the latter is + ! safest in case we aren't coupled to CISM, to ensure that we use the uncoupled form + ! of runoff routing). + this%icemask_grc(begg:endg) = 0.0_r8 this%icemask_coupled_fluxes_grc(begg:endg) = 0.0_r8 - call this%update_glc2lnd_dyn_runoff_routing(bounds, glc_behavior) + call this%update_glc2lnd_dyn_runoff_routing(bounds) end subroutine InitCold @@ -241,51 +238,109 @@ subroutine Clean(this) end subroutine Clean - !----------------------------------------------------------------------- - subroutine update_glc2lnd_non_topo(this, bounds, glc_behavior) + subroutine set_glc2lnd_fields(this, bounds, glc_present, x2l, & + index_x2l_Sg_ice_covered, index_x2l_Sg_topo, index_x2l_Flgg_hflx, & + index_x2l_Sg_icemask, index_x2l_Sg_icemask_coupled_fluxes) ! ! !DESCRIPTION: - ! Update values to derived-type CLM variables based on input from GLC (via the coupler) + ! Set coupling fields sent from glc to lnd ! - ! This does NOT update topographic heights: those are updated in the separate - ! update_glc2lnd_topo routine + ! If glc_present is true, then the given fields are all assumed to be valid; if + ! glc_present is false, then these fields are ignored. ! - ! icemask, icemask_coupled_fluxes, and glc_dyn_runoff_routing are always updated - ! (although note that this routine should only be called when - ! create_glacier_mec_landunit is true, or some similar condition; this should be - ! controlled in a conditional around the call to this routine); fracs are updated if - ! glc_do_dynglacier is true + ! !ARGUMENTS: + class(glc2lnd_type), intent(inout) :: this + type(bounds_type) , intent(in) :: bounds + logical , intent(in) :: glc_present ! true if running with a non-stub glc model + real(r8) , intent(in) :: x2l(:, bounds%begg: ) ! driver import state to land model [field, gridcell] + integer , intent(in) :: index_x2l_Sg_ice_covered( 0: ) ! indices of ice-covered field in x2l, for each elevation class + integer , intent(in) :: index_x2l_Sg_topo( 0: ) ! indices of topo field in x2l, for each elevation class + integer , intent(in) :: index_x2l_Flgg_hflx( 0: ) ! indices of heat flux field in x2l, for each elevation class + integer , intent(in) :: index_x2l_Sg_icemask ! index of icemask field in x2l + integer , intent(in) :: index_x2l_Sg_icemask_coupled_fluxes ! index of icemask_coupled_fluxes field in x2l ! - ! !USES: - use clm_varctl , only : glc_do_dynglacier + ! !LOCAL VARIABLES: + integer :: g + integer :: icemec_class + + character(len=*), parameter :: subname = 'set_glc2lnd_fields' + !----------------------------------------------------------------------- + + SHR_ASSERT((ubound(x2l, 2) == bounds%endg), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(index_x2l_Sg_ice_covered) == (/maxpatch_glcmec/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(index_x2l_Sg_topo) == (/maxpatch_glcmec/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(index_x2l_Flgg_hflx) == (/maxpatch_glcmec/)), errMsg(sourcefile, __LINE__)) + + if (glc_present) then + do g = bounds%begg, bounds%endg + do icemec_class = 0, maxpatch_glcmec + this%frac_grc(g,icemec_class) = x2l(index_x2l_Sg_ice_covered(icemec_class),g) + this%topo_grc(g,icemec_class) = x2l(index_x2l_Sg_topo(icemec_class),g) + this%hflx_grc(g,icemec_class) = x2l(index_x2l_Flgg_hflx(icemec_class),g) + end do + this%icemask_grc(g) = x2l(index_x2l_Sg_icemask,g) + this%icemask_coupled_fluxes_grc(g) = x2l(index_x2l_Sg_icemask_coupled_fluxes,g) + end do + + call this%check_glc2lnd_icemask(bounds) + call this%check_glc2lnd_icemask_coupled_fluxes(bounds) + call this%update_glc2lnd_dyn_runoff_routing(bounds) + else + if (glc_do_dynglacier) then + call endrun(' ERROR: With glc_present false (e.g., a stub glc model), glc_do_dynglacier must be false '// & + errMsg(sourcefile, __LINE__)) + end if + end if + + end subroutine set_glc2lnd_fields + + !----------------------------------------------------------------------- + subroutine for_test_set_glc2lnd_fields_directly(this, bounds, & + topo, icemask) + ! + ! !DESCRIPTION: + ! Set glc2lnd fields directly in a unit testing context + ! + ! This currently only provides a mechanism to set fields that are actually needed in + ! our unit tests. More could be added later. + ! + ! Also: In contrast to the production version (set_glc2lnd_fields), this does NOT + ! currently update glc2lnd_dyn_runoff_routing (because doing so would require having a + ! sensible glc_behavior, which we may not have; and also, we currently don't need this + ! field in a unit testing context). (Note: If we eventually want/need to update + ! glc2lnd_dyn_runoff_routing, and thus need a fully sensible glc_behavior, then we + ! should extract the self-calls at the end of set_glc2lnd_fields + ! (check_glc2lnd_icemask, check_glc2lnd_icemask_coupled_fluxes, + ! update_glc2lnd_dyn_runoff_routing) into a private routine like + ! set_glc2lnd_fields_wrapup, which could be called by both set_glc2lnd_fields and this + ! routine.) ! ! !ARGUMENTS: - class(glc2lnd_type) , intent(inout) :: this - type(bounds_type) , intent(in) :: bounds - type(glc_behavior_type) , intent(in) :: glc_behavior + class(glc2lnd_type), intent(inout) :: this + type(bounds_type) , intent(in) :: bounds + real(r8), intent(in), optional :: topo( bounds%begg: , 0: ) ! topographic height [gridcell, elevclass] + real(r8), intent(in), optional :: icemask( bounds%begg: ) ! ! !LOCAL VARIABLES: - character(len=*), parameter :: subname = 'update_glc2lnd_non_topo' + character(len=*), parameter :: subname = 'for_test_set_glc2lnd_fields_directly' !----------------------------------------------------------------------- - ! Note that nothing is needed to update icemask or icemask_coupled_fluxes here, - ! because these values have already been set in lnd_import_export. However, we do - ! some sanity-checking of those fields here. - call this%check_glc2lnd_icemask(bounds, glc_behavior) - call this%check_glc2lnd_icemask_coupled_fluxes(bounds) - - call this%update_glc2lnd_dyn_runoff_routing(bounds, glc_behavior) + if (present(topo)) then + SHR_ASSERT_ALL((ubound(topo) == (/bounds%endg, maxpatch_glcmec/)), errMsg(sourcefile, __LINE__)) + this%topo_grc(bounds%begg:bounds%endg, 0:maxpatch_glcmec) = topo(bounds%begg:bounds%endg, 0:maxpatch_glcmec) + end if - if (glc_do_dynglacier) then - call this%update_glc2lnd_fracs(bounds) + if (present(icemask)) then + SHR_ASSERT_ALL((ubound(icemask) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + this%icemask_grc(bounds%begg:bounds%endg) = icemask(bounds%begg:bounds%endg) end if - end subroutine update_glc2lnd_non_topo + end subroutine for_test_set_glc2lnd_fields_directly !----------------------------------------------------------------------- - subroutine check_glc2lnd_icemask(this, bounds, glc_behavior) + subroutine check_glc2lnd_icemask(this, bounds) ! ! !DESCRIPTION: ! Do a sanity check on the icemask received from CISM via coupler. @@ -296,7 +351,6 @@ subroutine check_glc2lnd_icemask(this, bounds, glc_behavior) ! !ARGUMENTS: class(glc2lnd_type), intent(in) :: this type(bounds_type) , intent(in) :: bounds - type(glc_behavior_type) , intent(in) :: glc_behavior ! ! !LOCAL VARIABLES: integer :: g ! grid cell index @@ -311,7 +365,7 @@ subroutine check_glc2lnd_icemask(this, bounds, glc_behavior) ! Ensure that icemask is a subset of has_virtual_columns. This is needed because ! we allocated memory based on has_virtual_columns, so it is a problem if the ! ice sheet tries to expand beyond the area defined by has_virtual_columns. - if (.not. glc_behavior%has_virtual_columns_grc(g)) then + if (.not. this%glc_behavior%has_virtual_columns_grc(g)) then write(iulog,'(a)') subname//' ERROR: icemask must be a subset of has_virtual_columns.' write(iulog,'(a)') 'Ensure that the glacier_region_behavior namelist item is set correctly.' write(iulog,'(a)') '(It should specify "virtual" for the region corresponding to the GLC domain.)' @@ -326,7 +380,7 @@ subroutine check_glc2lnd_icemask(this, bounds, glc_behavior) ! because we only compute SMB in the region given by melt_replaced_by_ice ! (according to the logic for building the do_smb filter), and we need SMB ! everywhere inside the icemask. - if (.not. glc_behavior%melt_replaced_by_ice_grc(g)) then + if (.not. this%glc_behavior%melt_replaced_by_ice_grc(g)) then write(iulog,'(a)') subname//' ERROR: icemask must be a subset of melt_replaced_by_ice.' write(iulog,'(a)') 'Ensure that the glacier_region_melt_behavior namelist item is set correctly.' write(iulog,'(a)') '(It should specify "replaced_by_ice" for the region corresponding to the GLC domain.)' @@ -376,17 +430,17 @@ subroutine check_glc2lnd_icemask_coupled_fluxes(this, bounds) end subroutine check_glc2lnd_icemask_coupled_fluxes !----------------------------------------------------------------------- - subroutine update_glc2lnd_dyn_runoff_routing(this, bounds, glc_behavior) + subroutine update_glc2lnd_dyn_runoff_routing(this, bounds) ! ! !DESCRIPTION: ! Update glc_dyn_runoff_routing field based on updated icemask_coupled_fluxes field ! ! !USES: + use domainMod , only : ldomain ! ! !ARGUMENTS: class(glc2lnd_type), intent(inout) :: this type(bounds_type) , intent(in) :: bounds ! bounds - type(glc_behavior_type) , intent(in) :: glc_behavior ! ! !LOCAL VARIABLES: integer :: g ! grid cell index @@ -396,26 +450,66 @@ subroutine update_glc2lnd_dyn_runoff_routing(this, bounds, glc_behavior) ! Wherever we have an icesheet that is computing and sending fluxes to the coupler - ! which particularly means it is computing a calving flux - we will use the - ! "glc_dyn_runoff_routing" scheme. In other places - including places where CISM is - ! not running at all, as well as places where CISM is running in diagnostic-only mode - ! and therefore is not sending a calving flux - we use the alternative - ! glc_dyn_runoff_routing=false scheme. This is needed to conserve water correctly in - ! the absence of a calving flux. + ! "glc_dyn_runoff_routing" scheme, with 0 < glc_dyn_runoff_routing <= 1. + ! In these places, all or part of the snowcap flux goes to CISM rather than the runoff model. + ! In other places - including places where CISM is not running at all, as well as places + ! where CISM is running in diagnostic-only mode and therefore is not sending a calving flux - + ! we have glc_dyn_runoff_routing = 0, and the snowcap flux goes to the runoff model. + ! This is needed to conserve water correctly in the absence of a calving flux. do g = bounds%begg, bounds%endg - if (this%icemask_coupled_fluxes_grc(g) > 0._r8) then - this%glc_dyn_runoff_routing_grc(g) = .true. + + ! Set glc_dyn_runoff_routing_grc(g) to a value in the range [0,1]. + ! + ! This value gives the grid cell fraction that is deemed to be coupled to the + ! dynamic ice sheet model. For this fraction of the grid cell, snowcap fluxes are + ! sent to the ice sheet model. The remainder of the grid cell sends snowcap fluxes + ! to the runoff model. + ! + ! Note: The coupler (in prep_glc_mod.F90) assumes that the fraction coupled to the + ! dynamic ice sheet model is min(lfrac, Sg_icemask_l), where lfrac is the + ! "frac" component of fraction_lx, and Sg_icemask_l is obtained by mapping + ! Sg_icemask_g from the glc to the land grid. Here, ldomain%frac is + ! equivalent to lfrac, and this%icemask_grc is equivalent to Sg_icemask_l. + ! However, here we use icemask_coupled_fluxes_grc, so that we route all snow + ! capping to runoff in areas where the ice sheet is not generating calving + ! fluxes. In addition, here we need to divide by lfrac, because the coupler + ! multiplies by it later (and, for example, if lfrac = 0.1 and + ! icemask_coupled_fluxes = 1, we want all snow capping to go to the ice + ! sheet model, not to the runoff model). + ! + ! Note: In regions where CLM overlaps the CISM domain, this%icemask_grc(g) typically + ! is nearly equal to ldomain%frac(g). So an alternative would be to simply set + ! glc_dyn_runoff_routing_grc(g) = icemask_grc(g). + ! The reason to cap glc_dyn_runoff_routing at lfrac is to avoid sending the + ! ice sheet model a greater mass of water (in the form of snowcap fluxes) + ! than is allowed to fall on a CLM grid cell that is part ocean. + + ! TODO(wjs, 2017-05-08) Ideally, we wouldn't have this duplication in logic + ! between the coupler and CLM. The best solution would be to have the coupler + ! itself do the partitioning of the snow capping flux between the ice sheet model + ! and the runoff model. A next-best solution would be to have the coupler send a + ! field to CLM telling it what fraction of snow capping should go to the runoff + ! model in each grid cell. + + if (ldomain%frac(g) == 0._r8) then + ! Avoid divide by 0; note that, in this case, the amount going to runoff isn't + ! important for system-wide conservation, so we could really choose anything we + ! want. + this%glc_dyn_runoff_routing_grc(g) = this%icemask_coupled_fluxes_grc(g) else - this%glc_dyn_runoff_routing_grc(g) = .false. + this%glc_dyn_runoff_routing_grc(g) = & + min(ldomain%frac(g), this%icemask_coupled_fluxes_grc(g)) / & + ldomain%frac(g) end if - if (this%glc_dyn_runoff_routing_grc(g)) then + if (this%glc_dyn_runoff_routing_grc(g) > 0.0_r8) then ! Ensure that glc_dyn_runoff_routing is a subset of melt_replaced_by_ice. This ! is needed because glacial melt is only sent to the runoff stream in the region ! given by melt_replaced_by_ice (because the latter is used to create the do_smb ! filter, and the do_smb filter controls where glacial melt is computed). - if (.not. glc_behavior%melt_replaced_by_ice_grc(g)) then + if (.not. this%glc_behavior%melt_replaced_by_ice_grc(g)) then write(iulog,'(a)') subname//' ERROR: icemask_coupled_fluxes must be a subset of melt_replaced_by_ice.' write(iulog,'(a)') 'Ensure that the glacier_region_melt_behavior namelist item is set correctly.' write(iulog,'(a)') '(It should specify "replaced_by_ice" for the region corresponding to the GLC domain.)' @@ -440,6 +534,8 @@ subroutine update_glc2lnd_fracs(this, bounds) ! ! The weights updated here are some col%wtlunit and lun%wtgcell values ! + ! If glc_do_dynglacier is false, nothing is changed + ! ! !USES: use column_varcon , only : col_itype_to_icemec_class use subgridWeightsMod , only : set_landunit_weight @@ -458,53 +554,55 @@ subroutine update_glc2lnd_fracs(this, bounds) character(len=*), parameter :: subname = 'update_glc2lnd_fracs' !----------------------------------------------------------------------- - - do g = bounds%begg, bounds%endg - ! Values from GLC are only valid within the icemask, so we only update CLM's areas there - if (this%icemask_grc(g) > 0._r8) then - ! Set total icemec landunit area - area_ice_mec = sum(this%frac_grc(g, 1:maxpatch_glcmec)) - call set_landunit_weight(g, istice_mec, area_ice_mec) - - ! If new landunit area is greater than 0, then update column areas - ! (If new landunit area is 0, col%wtlunit is arbitrary, so we might as well keep the existing values) - if (area_ice_mec > 0) then - ! Determine index of the glc_mec landunit - l_ice_mec = grc%landunit_indices(istice_mec, g) - if (l_ice_mec == ispval) then - write(iulog,*) subname//' ERROR: no ice_mec landunit found within the icemask, for g = ', g - call endrun() - end if - - frac_assigned(1:maxpatch_glcmec) = .false. - do c = lun%coli(l_ice_mec), lun%colf(l_ice_mec) - icemec_class = col_itype_to_icemec_class(col%itype(c)) - col%wtlunit(c) = this%frac_grc(g, icemec_class) / lun%wtgcell(l_ice_mec) - frac_assigned(icemec_class) = .true. - end do - - ! Confirm that all elevation classes that have non-zero area according to - ! this%frac have been assigned to a column in CLM's data structures - error = .false. - do icemec_class = 1, maxpatch_glcmec - if (this%frac_grc(g, icemec_class) > 0._r8 .and. & - .not. frac_assigned(icemec_class)) then - error = .true. + if (glc_do_dynglacier) then + do g = bounds%begg, bounds%endg + ! Values from GLC are only valid within the icemask, so we only update CLM's areas there + if (this%icemask_grc(g) > 0._r8) then + + ! Set total icemec landunit area + area_ice_mec = sum(this%frac_grc(g, 1:maxpatch_glcmec)) + call set_landunit_weight(g, istice_mec, area_ice_mec) + + ! If new landunit area is greater than 0, then update column areas + ! (If new landunit area is 0, col%wtlunit is arbitrary, so we might as well keep the existing values) + if (area_ice_mec > 0) then + ! Determine index of the glc_mec landunit + l_ice_mec = grc%landunit_indices(istice_mec, g) + if (l_ice_mec == ispval) then + write(iulog,*) subname//' ERROR: no ice_mec landunit found within the icemask, for g = ', g + call endrun() end if - end do - if (error) then - write(iulog,*) subname//' ERROR: at least one glc_mec column has non-zero area from the coupler,' - write(iulog,*) 'but there was no slot in memory for this column; g = ', g - write(iulog,*) 'this%frac_grc(g, 1:maxpatch_glcmec) = ', & - this%frac_grc(g, 1:maxpatch_glcmec) - write(iulog,*) 'frac_assigned(1:maxpatch_glcmec) = ', & - frac_assigned(1:maxpatch_glcmec) - call endrun() - end if ! error - end if ! area_ice_mec > 0 - end if ! this%icemask_grc(g) > 0 - end do ! g + + frac_assigned(1:maxpatch_glcmec) = .false. + do c = lun%coli(l_ice_mec), lun%colf(l_ice_mec) + icemec_class = col_itype_to_icemec_class(col%itype(c)) + col%wtlunit(c) = this%frac_grc(g, icemec_class) / lun%wtgcell(l_ice_mec) + frac_assigned(icemec_class) = .true. + end do + + ! Confirm that all elevation classes that have non-zero area according to + ! this%frac have been assigned to a column in CLM's data structures + error = .false. + do icemec_class = 1, maxpatch_glcmec + if (this%frac_grc(g, icemec_class) > 0._r8 .and. & + .not. frac_assigned(icemec_class)) then + error = .true. + end if + end do + if (error) then + write(iulog,*) subname//' ERROR: at least one glc_mec column has non-zero area from the coupler,' + write(iulog,*) 'but there was no slot in memory for this column; g = ', g + write(iulog,*) 'this%frac_grc(g, 1:maxpatch_glcmec) = ', & + this%frac_grc(g, 1:maxpatch_glcmec) + write(iulog,*) 'frac_assigned(1:maxpatch_glcmec) = ', & + frac_assigned(1:maxpatch_glcmec) + call endrun() + end if ! error + end if ! area_ice_mec > 0 + end if ! this%icemask_grc(g) > 0 + end do ! g + end if ! glc_do_dynglacier end subroutine update_glc2lnd_fracs @@ -518,9 +616,8 @@ subroutine update_glc2lnd_topo(this, bounds, topo_col, needs_downscaling_col) ! anywhere where topo_col is updated, because these points will need downscaling. ! (Leaves other array elements in needs_downscaling_col untouched.) ! - ! This should only be called when create_glacier_mec_landunit is true, or some - ! similar condition (this should be controlled in a conditional around the call to - ! this routine). + ! If glc_do_dynglacier is false, then both topographic heights and + ! needs_downscaling_col are left unchanged. ! ! !USES: use landunit_varcon , only : istice_mec @@ -542,32 +639,34 @@ subroutine update_glc2lnd_topo(this, bounds, topo_col, needs_downscaling_col) SHR_ASSERT_ALL((ubound(topo_col) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) SHR_ASSERT_ALL((ubound(needs_downscaling_col) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) - do c = bounds%begc, bounds%endc - l = col%landunit(c) - g = col%gridcell(c) + if (glc_do_dynglacier) then + do c = bounds%begc, bounds%endc + l = col%landunit(c) + g = col%gridcell(c) - ! Values from GLC are only valid within the icemask, so we only update CLM's topo values there - if (this%icemask_grc(g) > 0._r8) then - if (lun%itype(l) == istice_mec) then - icemec_class = col_itype_to_icemec_class(col%itype(c)) - else - ! If not on a glaciated column, assign topography to the bare-land value determined by GLC. - icemec_class = 0 - end if + ! Values from GLC are only valid within the icemask, so we only update CLM's topo values there + if (this%icemask_grc(g) > 0._r8) then + if (lun%itype(l) == istice_mec) then + icemec_class = col_itype_to_icemec_class(col%itype(c)) + else + ! If not on a glaciated column, assign topography to the bare-land value determined by GLC. + icemec_class = 0 + end if - ! Note that we do downscaling over all column types. This is for consistency: - ! interpretation of results would be difficult if some non-glacier column types - ! were downscaled but others were not. - ! - ! BUG(wjs, 2016-11-15, bugz 2377) Actually, do not downscale over urban points: - ! this currently isn't allowed because the urban code references some - ! non-downscaled, gridcell-level atmospheric forcings - if (.not. lun%urbpoi(l)) then - topo_col(c) = this%topo_grc(g, icemec_class) - needs_downscaling_col(c) = .true. + ! Note that we do downscaling over all column types. This is for consistency: + ! interpretation of results would be difficult if some non-glacier column types + ! were downscaled but others were not. + ! + ! BUG(wjs, 2016-11-15, bugz 2377) Actually, do not downscale over urban points: + ! this currently isn't allowed because the urban code references some + ! non-downscaled, gridcell-level atmospheric forcings + if (.not. lun%urbpoi(l)) then + topo_col(c) = this%topo_grc(g, icemec_class) + needs_downscaling_col(c) = .true. + end if end if - end if - end do + end do + end if end subroutine update_glc2lnd_topo diff --git a/src/main/glcBehaviorMod.F90 b/src/main/glcBehaviorMod.F90 index da09084b79..2fa47857ea 100644 --- a/src/main/glcBehaviorMod.F90 +++ b/src/main/glcBehaviorMod.F90 @@ -76,6 +76,12 @@ module glcBehaviorMod ! smb in that case. logical, allocatable, public :: melt_replaced_by_ice_grc(:) + ! If ice_runoff_melted_grc(g) is true, then ice runoff generated by the + ! CLM physics over glacier columns in gridcell g is melted (generating a negative + ! sensible heat flux) and runs off as liquid. If it is false, then ice runoff is + ! sent to the river model as ice (a crude parameterization of iceberg calving). + logical, allocatable, public :: ice_runoff_melted_grc(:) + ! ------------------------------------------------------------------------ ! Private data ! ------------------------------------------------------------------------ @@ -148,7 +154,8 @@ module glcBehaviorMod ! !PRIVATE MEMBER DATA: - ! Longest name allowed for glacier_region_behavior and glacier_region_melt_behavior + ! Longest name allowed for glacier_region_behavior, glacier_region_melt_behavior and + ! glacier_region_ice_runoff_behavior integer, parameter :: max_behavior_name_len = 32 ! Smallest and largest allowed values for a glacier region ID @@ -184,22 +191,26 @@ subroutine Init(this, begg, endg, NLFilename) integer, allocatable :: glacier_region_map(:) character(len=max_behavior_name_len) :: glacier_region_behavior(min_glacier_region_id:max_glacier_region_id) character(len=max_behavior_name_len) :: glacier_region_melt_behavior(min_glacier_region_id:max_glacier_region_id) + character(len=max_behavior_name_len) :: glacier_region_ice_runoff_behavior(min_glacier_region_id:max_glacier_region_id) character(len=*), parameter :: subname = 'Init' !----------------------------------------------------------------------- allocate(glacier_region_map(begg:endg)) call this%read_surface_dataset(begg, endg, glacier_region_map(begg:endg)) - call this%read_namelist(NLFilename, glacier_region_behavior, glacier_region_melt_behavior) + call this%read_namelist(NLFilename, glacier_region_behavior, & + glacier_region_melt_behavior, glacier_region_ice_runoff_behavior) call this%InitFromInputs(begg, endg, & - glacier_region_map(begg:endg), glacier_region_behavior, glacier_region_melt_behavior) + glacier_region_map(begg:endg), glacier_region_behavior, & + glacier_region_melt_behavior, glacier_region_ice_runoff_behavior) end subroutine Init !----------------------------------------------------------------------- subroutine InitFromInputs(this, begg, endg, & - glacier_region_map, glacier_region_behavior_str, glacier_region_melt_behavior_str) + glacier_region_map, glacier_region_behavior_str, glacier_region_melt_behavior_str, & + glacier_region_ice_runoff_behavior_str) ! ! !DESCRIPTION: ! Initialize a glc_behavior_type object given a map of glacier region IDs and an @@ -235,6 +246,12 @@ subroutine InitFromInputs(this, begg, endg, & ! - 'remains_in_place' character(len=*), intent(in) :: glacier_region_melt_behavior_str(min_glacier_region_id:) + ! string giving treatment of ice runoff for each glacier region ID + ! allowed values are: + ! - 'remains_ice' + ! - 'melted' + character(len=*), intent(in) :: glacier_region_ice_runoff_behavior_str(min_glacier_region_id:) + ! ! !LOCAL VARIABLES: ! whether each glacier region ID is present in the glacier_region_map @@ -246,10 +263,14 @@ subroutine InitFromInputs(this, begg, endg, & ! integer codes corresponding to glacier_region_melt_behavior_str integer :: glacier_region_melt_behavior(min_glacier_region_id:max_glacier_region_id) + ! integer codes corresponding to glacier_region_ice_runoff_behavior_str + integer :: glacier_region_ice_runoff_behavior(min_glacier_region_id:max_glacier_region_id) + integer :: g integer :: my_id integer :: my_behavior integer :: my_melt_behavior + integer :: my_ice_runoff_behavior ! possible glacier_region_behavior codes integer, parameter :: BEHAVIOR_MULTIPLE = 1 @@ -260,8 +281,12 @@ subroutine InitFromInputs(this, begg, endg, & integer, parameter :: MELT_BEHAVIOR_REPLACED_BY_ICE = 1 integer, parameter :: MELT_BEHAVIOR_REMAINS_IN_PLACE = 2 - ! value indicating that a behavior code has not been set (either for - ! glacier_region_behavior or glacier_region_melt_behavior) + ! possible glacier_region_ice_runoff_behavior codes + integer, parameter :: ICE_RUNOFF_BEHAVIOR_REMAINS_ICE = 1 + integer, parameter :: ICE_RUNOFF_BEHAVIOR_MELTED = 2 + + ! value indicating that a behavior code has not been set (for glacier_region_behavior, + ! glacier_region_melt_behavior or glacier_region_ice_runoff_behavior) integer, parameter :: BEHAVIOR_UNSET = -1 character(len=*), parameter :: subname = 'InitFromInputs' @@ -275,6 +300,7 @@ subroutine InitFromInputs(this, begg, endg, & call translate_glacier_region_behavior call translate_glacier_region_melt_behavior + call translate_glacier_region_ice_runoff_behavior call this%InitAllocate(begg, endg) @@ -282,10 +308,12 @@ subroutine InitFromInputs(this, begg, endg, & my_id = glacier_region_map(g) my_behavior = glacier_region_behavior(my_id) my_melt_behavior = glacier_region_melt_behavior(my_id) + my_ice_runoff_behavior = glacier_region_ice_runoff_behavior(my_id) ! This should only happen due to a programming error, not due to a user input error SHR_ASSERT(my_behavior /= BEHAVIOR_UNSET, errMsg(sourcefile, __LINE__)) SHR_ASSERT(my_melt_behavior /= BEHAVIOR_UNSET, errMsg(sourcefile, __LINE__)) + SHR_ASSERT(my_ice_runoff_behavior /= BEHAVIOR_UNSET, errMsg(sourcefile, __LINE__)) if (my_behavior == BEHAVIOR_VIRTUAL) then this%has_virtual_columns_grc(g) = .true. @@ -299,6 +327,12 @@ subroutine InitFromInputs(this, begg, endg, & this%melt_replaced_by_ice_grc(g) = .true. end if + if (my_ice_runoff_behavior == ICE_RUNOFF_BEHAVIOR_MELTED) then + this%ice_runoff_melted_grc(g) = .true. + else + this%ice_runoff_melted_grc(g) = .false. + end if + ! For now, allow_multiple_columns_grc is simply the opposite of ! collapse_to_atm_topo_grc. However, we maintain the separate ! allow_multiple_columns_grc so that the public interface can stay the same if we @@ -408,6 +442,36 @@ subroutine translate_glacier_region_melt_behavior end do end subroutine translate_glacier_region_melt_behavior + subroutine translate_glacier_region_ice_runoff_behavior + integer :: i + + do i = min_glacier_region_id, max_glacier_region_id + glacier_region_ice_runoff_behavior(i) = BEHAVIOR_UNSET + + if (glacier_region_present(i)) then + SHR_ASSERT_ALL((ubound(glacier_region_ice_runoff_behavior_str) >= (/i/)), errMsg(sourcefile, __LINE__)) + + select case (glacier_region_ice_runoff_behavior_str(i)) + case ('remains_ice') + glacier_region_ice_runoff_behavior(i) = ICE_RUNOFF_BEHAVIOR_REMAINS_ICE + case('melted') + glacier_region_ice_runoff_behavior(i) = ICE_RUNOFF_BEHAVIOR_MELTED + case (behavior_str_unset) + write(iulog,*) ' ERROR: glacier_region_ice_runoff_behavior not specified for ID ', i + write(iulog,*) 'You probably need to extend the glacier_region_ice_runoff_behavior namelist array' + call endrun(msg=' ERROR: glacier_region_ice_runoff_behavior not specified for ID '// & + errMsg(sourcefile, __LINE__)) + case default + write(iulog,*) ' ERROR: Unknown glacier_region_ice_runoff_behavior for ID ', i + write(iulog,*) glacier_region_ice_runoff_behavior_str(i) + write(iulog,*) 'Allowable values are: remains_ice, melted' + call endrun(msg=' ERROR: Unknown glacier_region_ice_runoff_behavior'// & + errMsg(sourcefile, __LINE__)) + end select + end if + end do + end subroutine translate_glacier_region_ice_runoff_behavior + end subroutine InitFromInputs @@ -465,6 +529,7 @@ subroutine InitAllocate(this, begg, endg) allocate(this%allow_multiple_columns_grc(begg:endg)); this%allow_multiple_columns_grc(:) = .false. allocate(this%melt_replaced_by_ice_grc(begg:endg)); this%melt_replaced_by_ice_grc(:) = .false. allocate(this%collapse_to_atm_topo_grc(begg:endg)); this%collapse_to_atm_topo_grc(:) = .false. + allocate(this%ice_runoff_melted_grc(begg:endg)); this%ice_runoff_melted_grc(:) = .false. end subroutine InitAllocate @@ -515,7 +580,8 @@ subroutine read_surface_dataset(begg, endg, glacier_region_map) end subroutine read_surface_dataset !----------------------------------------------------------------------- - subroutine read_namelist(NLFilename, glacier_region_behavior, glacier_region_melt_behavior) + subroutine read_namelist(NLFilename, glacier_region_behavior, & + glacier_region_melt_behavior, glacier_region_ice_runoff_behavior) ! ! !DESCRIPTION: ! Read local namelist items @@ -529,8 +595,12 @@ subroutine read_namelist(NLFilename, glacier_region_behavior, glacier_region_mel ! ! !ARGUMENTS: character(len=*), intent(in) :: NLFilename ! Namelist filename - character(len=max_behavior_name_len), intent(out) :: glacier_region_behavior(min_glacier_region_id:max_glacier_region_id) - character(len=max_behavior_name_len), intent(out) :: glacier_region_melt_behavior(min_glacier_region_id:max_glacier_region_id) + character(len=max_behavior_name_len), intent(out) :: & + glacier_region_behavior(min_glacier_region_id:max_glacier_region_id) + character(len=max_behavior_name_len), intent(out) :: & + glacier_region_melt_behavior(min_glacier_region_id:max_glacier_region_id) + character(len=max_behavior_name_len), intent(out) :: & + glacier_region_ice_runoff_behavior(min_glacier_region_id:max_glacier_region_id) ! ! !LOCAL VARIABLES: integer :: unitn ! unit for namelist file @@ -540,11 +610,13 @@ subroutine read_namelist(NLFilename, glacier_region_behavior, glacier_region_mel !----------------------------------------------------------------------- namelist /clm_glacier_behavior/ & - glacier_region_behavior, glacier_region_melt_behavior + glacier_region_behavior, glacier_region_melt_behavior, & + glacier_region_ice_runoff_behavior ! Initialize options to default values glacier_region_behavior(:) = behavior_str_unset glacier_region_melt_behavior(:) = behavior_str_unset + glacier_region_ice_runoff_behavior(:) = behavior_str_unset if (masterproc) then unitn = getavu() @@ -565,6 +637,7 @@ subroutine read_namelist(NLFilename, glacier_region_behavior, glacier_region_mel call shr_mpi_bcast(glacier_region_behavior, mpicom) call shr_mpi_bcast(glacier_region_melt_behavior, mpicom) + call shr_mpi_bcast(glacier_region_ice_runoff_behavior, mpicom) if (masterproc) then write(iulog,*) ' ' @@ -822,6 +895,7 @@ subroutine update_collapsed_columns_classes(this, bounds, collapse_filterc, topo integer :: c ! column index integer :: elev_class ! elevation class of the single column on the ice_mec landunit integer :: err_code + integer :: new_coltype character(len=*), parameter :: subname = 'update_collapsed_columns_classes' !----------------------------------------------------------------------- @@ -847,7 +921,10 @@ subroutine update_collapsed_columns_classes(this, bounds, collapse_filterc, topo call endrun(msg=subname//': ERROR getting elevation class') end if - call col%update_itype(c = c, itype = icemec_class_to_col_itype(elev_class)) + new_coltype = icemec_class_to_col_itype(elev_class) + if (new_coltype /= col%itype(c)) then + call col%update_itype(c = c, itype = new_coltype) + end if end do end subroutine update_collapsed_columns_classes diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 175d048346..2a00e57265 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -12,7 +12,7 @@ module histFileMod use shr_sys_mod , only : shr_sys_flush use spmdMod , only : masterproc use abortutils , only : endrun - use clm_varctl , only : iulog, use_vertsoilc, use_ed + use clm_varctl , only : iulog, use_vertsoilc, use_fates use clm_varcon , only : spval, ispval, dzsoi_decomp use clm_varcon , only : grlnd, nameg, namel, namec, namep, nameCohort use decompMod , only : get_proc_bounds, get_proc_global, bounds_type @@ -22,7 +22,11 @@ module histFileMod use ColumnType , only : col use PatchType , only : patch use ncdio_pio - use EDtypesMod , only : nlevsclass_ed + use EDtypesMod , only : nlevsclass_ed, nlevage_ed + use EDtypesMod , only : nfsc, ncwd + use EDtypesMod , only : nlevleaf, nclmax, numpft_ed + use EDTypesMod , only : maxpft + ! implicit none save @@ -37,6 +41,7 @@ module histFileMod integer , public, parameter :: max_namlen = 64 ! maximum number of characters for field name integer , public, parameter :: scale_type_strlen = 32 ! maximum number of characters for scale types integer , private, parameter :: avgflag_strlen = 3 ! maximum number of characters for avgflag + integer , private, parameter :: hist_dim_name_length = 16 ! lenngth of character strings in dimension names ! Possible ways to treat multi-layer snow fields at times when no snow is present in a ! given layer. Note that the public parameters are the only ones that can be used by @@ -117,6 +122,7 @@ module histFileMod public :: htapes_fieldlist ! Define the contents of each history file based on namelist ! ! !PRIVATE MEMBER FUNCTIONS: + private :: is_mapping_upto_subgrid ! Is this field being mapped up to a higher subgrid level? private :: masterlist_make_active ! Add a field to a history file default "on" list private :: masterlist_addfld ! Add a field to the master field list private :: masterlist_change_timeavg ! Override default history tape contents for specific tape @@ -159,9 +165,9 @@ module histFileMod character(len=max_namlen) :: name ! field name character(len=max_chars) :: long_name ! long name character(len=max_chars) :: units ! units - character(len=8) :: type1d ! pointer to first dimension type from data type (nameg, etc) - character(len=8) :: type1d_out ! hbuf first dimension type from data type (nameg, etc) - character(len=8) :: type2d ! hbuf second dimension type ["levgrnd","levlak","numrad","ltype","natpft","cft","glc_nec","elevclas","subname(n)"] + character(len=hist_dim_name_length) :: type1d ! pointer to first dimension type from data type (nameg, etc) + character(len=hist_dim_name_length) :: type1d_out ! hbuf first dimension type from data type (nameg, etc) + character(len=hist_dim_name_length) :: type2d ! hbuf second dimension type ["levgrnd","levlak","numrad","ltype","natpft","cft","glc_nec","elevclas","subname(n)"] integer :: beg1d ! on-node 1d clm pointer start index integer :: end1d ! on-node 1d clm pointer end index integer :: num1d ! size of clm pointer first dimension (all nodes) @@ -235,8 +241,8 @@ module histFileMod ! ! NetCDF Id's ! - type(file_desc_t) :: nfid(max_tapes) ! file ids - type(file_desc_t) :: ncid_hist(max_tapes) ! file ids for history restart files + type(file_desc_t), target :: nfid(max_tapes) ! file ids + type(file_desc_t), target :: ncid_hist(max_tapes) ! file ids for history restart files integer :: time_dimid ! time dimension id integer :: hist_interval_dimid ! time bounds dimension id integer :: strlen_dimid ! string dimension id @@ -341,6 +347,12 @@ subroutine masterlist_addfld (fname, type1d, type1d_out, & call endrun(msg=errMsg(sourcefile, __LINE__)) end if + ! Ensure that new field name isn't too long + + if (len_trim(fname) > max_namlen ) then + write(iulog,*) trim(subname),' ERROR: field name too long: ', trim(fname) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if ! Ensure that new field doesn't already exist do n = 1,nfmaster @@ -810,6 +822,41 @@ subroutine htapes_fieldlist() end subroutine htapes_fieldlist + !----------------------------------------------------------------------- + logical function is_mapping_upto_subgrid( type1d, type1d_out ) result ( mapping) + ! + ! !DESCRIPTION: + ! + ! Return true if this field will be mapped into a higher subgrid level + ! If false it will be output on it's native grid + ! + ! !ARGUMENTS: + implicit none + character(len=8), intent(in) :: type1d ! clm pointer 1d type + character(len=8), intent(in) :: type1d_out ! history buffer 1d type + ! + mapping = .false. + if (type1d_out == nameg .or. type1d_out == grlnd) then + if (type1d == namep) then + mapping = .true. + else if (type1d == namec) then + mapping = .true. + else if (type1d == namel) then + mapping = .true. + end if + else if (type1d_out == namel ) then + if (type1d == namep) then + mapping = .true. + else if (type1d == namec) then + mapping = .true. + end if + else if (type1d_out == namec ) then + if (type1d == namep) then + mapping = .true. + end if + end if + end function is_mapping_upto_subgrid + !----------------------------------------------------------------------- subroutine htape_addfld (t, f, avgflag) ! @@ -824,8 +871,8 @@ subroutine htape_addfld (t, f, avgflag) ! ! !LOCAL VARIABLES: integer :: n ! field index on defined tape - character(len=8) :: type1d ! clm pointer 1d type - character(len=8) :: type1d_out ! history buffer 1d type + character(len=hist_dim_name_length) :: type1d ! clm pointer 1d type + character(len=hist_dim_name_length) :: type1d_out ! history buffer 1d type integer :: numa ! total number of atm cells across all processors integer :: numg ! total number of gridcells across all processors integer :: numl ! total number of landunits across all processors @@ -833,6 +880,7 @@ subroutine htape_addfld (t, f, avgflag) integer :: nump ! total number of pfts across all processors integer :: num2d ! size of second dimension (e.g. .number of vertical levels) integer :: beg1d_out,end1d_out ! history output per-proc 1d beginning and ending indices + integer :: beg1d,end1d ! beginning and ending indices for this field (assume already set) integer :: num1d_out ! history output 1d size type(bounds_type) :: bounds character(len=*),parameter :: subname = 'htape_addfld' @@ -929,15 +977,25 @@ subroutine htape_addfld (t, f, avgflag) call endrun(msg=errMsg(sourcefile, __LINE__)) end if + ! Output bounds for the field tape(t)%hlist(n)%field%beg1d_out = beg1d_out tape(t)%hlist(n)%field%end1d_out = end1d_out tape(t)%hlist(n)%field%num1d_out = num1d_out + + ! Fields native bounds + beg1d = masterlist(f)%field%beg1d + end1d = masterlist(f)%field%end1d ! Alloccate and initialize history buffer and related info num2d = tape(t)%hlist(n)%field%num2d - allocate (tape(t)%hlist(n)%hbuf(beg1d_out:end1d_out,num2d)) - allocate (tape(t)%hlist(n)%nacs(beg1d_out:end1d_out,num2d)) + if ( is_mapping_upto_subgrid( type1d, type1d_out ) ) then + allocate (tape(t)%hlist(n)%hbuf(beg1d_out:end1d_out,num2d)) + allocate (tape(t)%hlist(n)%nacs(beg1d_out:end1d_out,num2d)) + else + allocate (tape(t)%hlist(n)%hbuf(beg1d:end1d,num2d)) + allocate (tape(t)%hlist(n)%nacs(beg1d:end1d,num2d)) + end if tape(t)%hlist(n)%hbuf(:,:) = 0._r8 tape(t)%hlist(n)%nacs(:,:) = 0 @@ -972,7 +1030,7 @@ subroutine hist_update_hbuf(bounds) integer :: f ! field index integer :: num2d ! size of second dimension (e.g. number of vertical levels) character(len=*),parameter :: subname = 'hist_update_hbuf' - character(len=8) :: type2d ! hbuf second dimension type ["levgrnd","levlak","numrad","ltype","natpft","cft","glc_nec","elevclas","subname(n)"] + character(len=hist_dim_name_length) :: type2d ! hbuf second dimension type ["levgrnd","levlak","numrad","ltype","natpft","cft","glc_nec","elevclas","subname(n)"] !----------------------------------------------------------------------- do t = 1,ntapes @@ -1001,7 +1059,7 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) ! call to p2g, and the lack of explicit bounds on its arguments; see also bug 1786) ! ! !USES: - use subgridAveMod , only : p2g, c2g, l2g + use subgridAveMod , only : p2g, c2g, l2g, p2l, c2l, p2c use decompMod , only : BOUNDS_LEVEL_PROC ! ! !ARGUMENTS: @@ -1013,11 +1071,12 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) integer :: hpindex ! history pointer index integer :: k ! gridcell, landunit, column or patch index integer :: beg1d,end1d ! beginning and ending indices + integer :: beg1d_out,end1d_out ! beginning and ending indices on output grid logical :: check_active ! true => check 'active' flag of each point (this refers to a point being active, NOT a history field being active) logical :: valid ! true => history operation is valid logical :: map2gcell ! true => map clm pointer field to gridcell - character(len=8) :: type1d ! 1d clm pointerr type ["gridcell","landunit","column","pft"] - character(len=8) :: type1d_out ! 1d history buffer type ["gridcell","landunit","column","pft"] + character(len=hist_dim_name_length) :: type1d ! 1d clm pointerr type ["gridcell","landunit","column","pft"] + character(len=hist_dim_name_length) :: type1d_out ! 1d history buffer type ["gridcell","landunit","column","pft"] character(len=avgflag_strlen) :: avgflag ! time averaging flag character(len=scale_type_strlen) :: p2c_scale_type ! scale type for subgrid averaging of pfts to column character(len=scale_type_strlen) :: c2l_scale_type ! scale type for subgrid averaging of columns to landunits @@ -1026,7 +1085,7 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) integer , pointer :: nacs(:,:) ! accumulation counter real(r8), pointer :: field(:) ! clm 1d pointer field logical , pointer :: active(:) ! flag saying whether each point is active (used for type1d = landunit/column/pft) (this refers to a point being active, NOT a history field being active) - real(r8) :: field_gcell(bounds%begg:bounds%endg) ! gricell level field (used if mapping to gridcell is done) + real(r8), allocatable :: field_gcell(:) ! gricell level field (used if mapping to gridcell is done) integer j character(len=*),parameter :: subname = 'hist_update_hbuf_field_1d' integer k_offset ! offset for mapping sliced subarray pointers when outputting variables in PFT/col vector form @@ -1039,6 +1098,8 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) hbuf => tape(t)%hlist(f)%hbuf beg1d = tape(t)%hlist(f)%field%beg1d end1d = tape(t)%hlist(f)%field%end1d + beg1d_out = tape(t)%hlist(f)%field%beg1d_out + end1d_out = tape(t)%hlist(f)%field%end1d_out type1d = tape(t)%hlist(f)%field%type1d type1d_out = tape(t)%hlist(f)%field%type1d_out p2c_scale_type = tape(t)%hlist(f)%field%p2c_scale_type @@ -1051,24 +1112,29 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) map2gcell = .false. if (type1d_out == nameg .or. type1d_out == grlnd) then + SHR_ASSERT(beg1d_out == bounds%begg, errMsg(sourcefile, __LINE__)) + SHR_ASSERT(end1d_out == bounds%endg, errMsg(sourcefile, __LINE__)) if (type1d == namep) then ! In this and the following calls, we do NOT explicitly subset field using ! bounds (e.g., we do NOT do field(bounds%begp:bounds%endp). This is because, ! for some fields, the lower bound has been reset to 1 due to taking a pointer ! to an array slice. Thus, this code will NOT work properly if done within a ! threaded region! (See also bug 1786) + allocate( field_gcell(beg1d_out:end1d_out) ) call p2g(bounds, & field, & field_gcell(bounds%begg:bounds%endg), & p2c_scale_type, c2l_scale_type, l2g_scale_type) map2gcell = .true. else if (type1d == namec) then + allocate( field_gcell(beg1d_out:end1d_out) ) call c2g(bounds, & field, & field_gcell(bounds%begg:bounds%endg), & c2l_scale_type, l2g_scale_type) map2gcell = .true. else if (type1d == namel) then + allocate( field_gcell(beg1d_out:end1d_out) ) call l2g(bounds, & field, & field_gcell(bounds%begg:bounds%endg), & @@ -1076,13 +1142,60 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) map2gcell = .true. end if end if + if (type1d_out == namel ) then + SHR_ASSERT(beg1d_out == bounds%begl, errMsg(sourcefile, __LINE__)) + SHR_ASSERT(end1d_out == bounds%endl, errMsg(sourcefile, __LINE__)) + if (type1d == namep) then + ! In this and the following calls, we do NOT explicitly subset field using + ! bounds (e.g., we do NOT do field(bounds%begp:bounds%endp). This is because, + ! for some fields, the lower bound has been reset to 1 due to taking a pointer + ! to an array slice. Thus, this code will NOT work properly if done within a + ! threaded region! (See also bug 1786) + allocate( field_gcell(beg1d_out:end1d_out) ) + call p2l(bounds, & + field, & + field_gcell(beg1d_out:end1d_out), & + p2c_scale_type, c2l_scale_type) + map2gcell = .true. + else if (type1d == namec) then + allocate( field_gcell(beg1d_out:end1d_out) ) + call c2l(bounds, & + field, & + field_gcell(beg1d_out:end1d_out), & + c2l_scale_type) + map2gcell = .true. + end if + end if + if (type1d_out == namec ) then + SHR_ASSERT(beg1d_out == bounds%begc, errMsg(sourcefile, __LINE__)) + SHR_ASSERT(end1d_out == bounds%endc, errMsg(sourcefile, __LINE__)) + if (type1d == namep) then + ! In this and the following calls, we do NOT explicitly subset field using + ! bounds (e.g., we do NOT do field(bounds%begp:bounds%endp). This is because, + ! for some fields, the lower bound has been reset to 1 due to taking a pointer + ! to an array slice. Thus, this code will NOT work properly if done within a + ! threaded region! (See also bug 1786) + allocate( field_gcell(beg1d_out:end1d_out) ) + call p2c(bounds, & + field, & + field_gcell(beg1d_out:end1d_out), & + p2c_scale_type) + map2gcell = .true. + end if + end if + if ( map2gcell .and. .not. is_mapping_upto_subgrid(type1d, type1d_out) )then + call endrun(msg=trim(subname)//' ERROR: mapping upto subgrid level is inconsistent'//errMsg(sourcefile, __LINE__)) + end if + if ( .not. map2gcell .and. is_mapping_upto_subgrid(type1d, type1d_out) )then + call endrun(msg=trim(subname)//' ERROR: mapping upto subgrid level is inconsistent'//errMsg(sourcefile, __LINE__)) + end if if (map2gcell) then ! Map to gridcell ! note that in this case beg1d = begg and end1d=endg select case (avgflag) case ('I') ! Instantaneous - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k) /= spval) then hbuf(k,1) = field_gcell(k) else @@ -1091,7 +1204,7 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) nacs(k,1) = 1 end do case ('A', 'SUM') ! Time average / sum - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k) /= spval) then if (nacs(k,1) == 0) hbuf(k,1) = 0._r8 hbuf(k,1) = hbuf(k,1) + field_gcell(k) @@ -1101,7 +1214,7 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) end if end do case ('X') ! Maximum over time - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k) /= spval) then if (nacs(k,1) == 0) hbuf(k,1) = -1.e50_r8 hbuf(k,1) = max( hbuf(k,1), field_gcell(k) ) @@ -1111,7 +1224,7 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) nacs(k,1) = 1 end do case ('M') ! Minimum over time - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k) /= spval) then if (nacs(k,1) == 0) hbuf(k,1) = +1.e50_r8 hbuf(k,1) = min( hbuf(k,1), field_gcell(k) ) @@ -1124,6 +1237,7 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) write(iulog,*) trim(subname),' ERROR: invalid time averaging flag ', avgflag call endrun(msg=errMsg(sourcefile, __LINE__)) end select + deallocate( field_gcell ) else ! Do not map to gridcell @@ -1239,7 +1353,7 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) ! call to p2g, and the lack of explicit bounds on its arguments; see also bug 1786) ! ! !USES: - use subgridAveMod , only : p2g, c2g, l2g + use subgridAveMod , only : p2g, c2g, l2g, p2l, c2l, p2c use decompMod , only : BOUNDS_LEVEL_PROC ! ! !ARGUMENTS: @@ -1253,11 +1367,12 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) integer :: k ! gridcell, landunit, column or patch index integer :: j ! level index integer :: beg1d,end1d ! beginning and ending indices + integer :: beg1d_out,end1d_out ! beginning and ending indices for output level logical :: check_active ! true => check 'active' flag of each point (this refers to a point being active, NOT a history field being active) logical :: valid ! true => history operation is valid logical :: map2gcell ! true => map clm pointer field to gridcell - character(len=8) :: type1d ! 1d clm pointerr type ["gridcell","landunit","column","pft"] - character(len=8) :: type1d_out ! 1d history buffer type ["gridcell","landunit","column","pft"] + character(len=hist_dim_name_length) :: type1d ! 1d clm pointerr type ["gridcell","landunit","column","pft"] + character(len=hist_dim_name_length) :: type1d_out ! 1d history buffer type ["gridcell","landunit","column","pft"] character(len=avgflag_strlen) :: avgflag ! time averaging flag character(len=scale_type_strlen) :: p2c_scale_type ! scale type for subgrid averaging of pfts to column character(len=scale_type_strlen) :: c2l_scale_type ! scale type for subgrid averaging of columns to landunits @@ -1269,7 +1384,7 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) logical :: field_allocated! whether 'field' was allocated here logical , pointer :: active(:) ! flag saying whether each point is active (used for type1d = landunit/column/pft) !(this refers to a point being active, NOT a history field being active) - real(r8) :: field_gcell(bounds%begg:bounds%endg,num2d) ! gridcell level field (used if mapping to gridcell is done) + real(r8), allocatable :: field_gcell(:,:) ! gridcell level field (used if mapping to gridcell is done) character(len=*),parameter :: subname = 'hist_update_hbuf_field_2d' !----------------------------------------------------------------------- @@ -1280,6 +1395,8 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) hbuf => tape(t)%hlist(f)%hbuf beg1d = tape(t)%hlist(f)%field%beg1d end1d = tape(t)%hlist(f)%field%end1d + beg1d_out = tape(t)%hlist(f)%field%beg1d_out + end1d_out = tape(t)%hlist(f)%field%end1d_out type1d = tape(t)%hlist(f)%field%type1d type1d_out = tape(t)%hlist(f)%field%type1d_out p2c_scale_type = tape(t)%hlist(f)%field%p2c_scale_type @@ -1315,30 +1432,80 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) map2gcell = .false. if (type1d_out == nameg .or. type1d_out == grlnd) then + SHR_ASSERT(beg1d_out == bounds%begg, errMsg(sourcefile, __LINE__)) + SHR_ASSERT(end1d_out == bounds%endg, errMsg(sourcefile, __LINE__)) if (type1d == namep) then ! In this and the following calls, we do NOT explicitly subset field using ! (e.g., we do NOT do field(bounds%begp:bounds%endp). This is because, ! for some fields, the lower bound has been reset to 1 due to taking a pointer ! to an array slice. Thus, this code will NOT work properly if done within a ! threaded region! (See also bug 1786) + allocate(field_gcell(bounds%begg:bounds%endg,num2d) ) call p2g(bounds, num2d, & field, & field_gcell(bounds%begg:bounds%endg, :), & p2c_scale_type, c2l_scale_type, l2g_scale_type) map2gcell = .true. else if (type1d == namec) then + allocate(field_gcell(bounds%begg:bounds%endg,num2d) ) call c2g(bounds, num2d, & field, & field_gcell(bounds%begg:bounds%endg, :), & c2l_scale_type, l2g_scale_type) map2gcell = .true. else if (type1d == namel) then + allocate(field_gcell(bounds%begg:bounds%endg,num2d) ) call l2g(bounds, num2d, & field, & field_gcell(bounds%begg:bounds%endg, :), & l2g_scale_type) map2gcell = .true. end if + else if ( type1d_out == namel )then + SHR_ASSERT(beg1d_out == bounds%begl, errMsg(sourcefile, __LINE__)) + SHR_ASSERT(end1d_out == bounds%endl, errMsg(sourcefile, __LINE__)) + if (type1d == namep) then + ! In this and the following calls, we do NOT explicitly subset field using + ! (e.g., we do NOT do field(bounds%begp:bounds%endp). This is because, + ! for some fields, the lower bound has been reset to 1 due to taking a pointer + ! to an array slice. Thus, this code will NOT work properly if done within a + ! threaded region! (See also bug 1786) + allocate(field_gcell(beg1d_out:end1d_out,num2d)) + call p2l(bounds, num2d, & + field, & + field_gcell(beg1d_out:end1d_out, :), & + p2c_scale_type, c2l_scale_type) + map2gcell = .true. + else if (type1d == namec) then + allocate(field_gcell(beg1d_out:end1d_out,num2d)) + call c2l(bounds, num2d, & + field, & + field_gcell(beg1d_out:end1d_out, :), & + c2l_scale_type) + map2gcell = .true. + end if + else if ( type1d_out == namec )then + SHR_ASSERT(beg1d_out == bounds%begc, errMsg(sourcefile, __LINE__)) + SHR_ASSERT(end1d_out == bounds%endc, errMsg(sourcefile, __LINE__)) + if (type1d == namep) then + ! In this and the following calls, we do NOT explicitly subset field using + ! (e.g., we do NOT do field(bounds%begp:bounds%endp). This is because, + ! for some fields, the lower bound has been reset to 1 due to taking a pointer + ! to an array slice. Thus, this code will NOT work properly if done within a + ! threaded region! (See also bug 1786) + allocate(field_gcell(beg1d_out:end1d_out,num2d)) + call p2c(bounds, num2d, & + field, & + field_gcell(beg1d_out:end1d_out, :), & + p2c_scale_type) + map2gcell = .true. + end if + end if + if ( map2gcell .and. .not. is_mapping_upto_subgrid(type1d, type1d_out) )then + call endrun(msg=trim(subname)//' ERROR: mapping upto subgrid level is inconsistent'//errMsg(sourcefile, __LINE__)) + end if + if ( .not. map2gcell .and. is_mapping_upto_subgrid(type1d, type1d_out) )then + call endrun(msg=trim(subname)//' ERROR: mapping upto subgrid level is inconsistent'//errMsg(sourcefile, __LINE__)) end if if (map2gcell) then ! Map to gridcell @@ -1347,7 +1514,7 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) select case (avgflag) case ('I') ! Instantaneous do j = 1,num2d - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k,j) /= spval) then hbuf(k,j) = field_gcell(k,j) else @@ -1358,7 +1525,7 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) end do case ('A', 'SUM') ! Time average / sum do j = 1,num2d - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k,j) /= spval) then if (nacs(k,j) == 0) hbuf(k,j) = 0._r8 hbuf(k,j) = hbuf(k,j) + field_gcell(k,j) @@ -1370,7 +1537,7 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) end do case ('X') ! Maximum over time do j = 1,num2d - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k,j) /= spval) then if (nacs(k,j) == 0) hbuf(k,j) = -1.e50_r8 hbuf(k,j) = max( hbuf(k,j), field_gcell(k,j) ) @@ -1382,7 +1549,7 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) end do case ('M') ! Minimum over time do j = 1,num2d - do k = bounds%begg,bounds%endg + do k = beg1d_out, end1d_out if (field_gcell(k,j) /= spval) then if (nacs(k,j) == 0) hbuf(k,j) = +1.e50_r8 hbuf(k,j) = min( hbuf(k,j), field_gcell(k,j) ) @@ -1396,6 +1563,7 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) write(iulog,*) trim(subname),' ERROR: invalid time averaging flag ', avgflag call endrun(msg=errMsg(sourcefile, __LINE__)) end select + deallocate( field_gcell ) else ! Do not map to gridcell @@ -1619,7 +1787,7 @@ subroutine hfields_normalize (t) integer :: k ! 1d index integer :: j ! 2d index logical :: aflag ! averaging flag - integer :: beg1d_out,end1d_out ! hbuf 1d beginning and ending indices + integer :: beg1d,end1d ! hbuf 1d beginning and ending indices integer :: num2d ! hbuf size of second dimension (e.g. number of vertical levels) character(len=avgflag_strlen) :: avgflag ! averaging flag real(r8), pointer :: hbuf(:,:) ! history buffer @@ -1631,8 +1799,13 @@ subroutine hfields_normalize (t) do f = 1,tape(t)%nflds avgflag = tape(t)%hlist(f)%avgflag - beg1d_out = tape(t)%hlist(f)%field%beg1d_out - end1d_out = tape(t)%hlist(f)%field%end1d_out + if ( is_mapping_upto_subgrid(tape(t)%hlist(f)%field%type1d, tape(t)%hlist(f)%field%type1d_out) )then + beg1d = tape(t)%hlist(f)%field%beg1d_out + end1d = tape(t)%hlist(f)%field%end1d_out + else + beg1d = tape(t)%hlist(f)%field%beg1d + end1d = tape(t)%hlist(f)%field%end1d + end if num2d = tape(t)%hlist(f)%field%num2d nacs => tape(t)%hlist(f)%nacs hbuf => tape(t)%hlist(f)%hbuf @@ -1644,7 +1817,7 @@ subroutine hfields_normalize (t) end if do j = 1, num2d - do k = beg1d_out, end1d_out + do k = beg1d, end1d if (aflag .and. nacs(k,j) /= 0) then hbuf(k,j) = hbuf(k,j) / float(nacs(k,j)) end if @@ -1686,7 +1859,6 @@ subroutine htape_create (t, histrest) ! !USES: use clm_varpar , only : nlevgrnd, nlevsno, nlevlak, nlevurb, numrad, nlevcan, nvegwcs,nlevsoi use clm_varpar , only : natpft_size, cft_size, maxpatch_glcmec, nlevdecomp_full - use clm_varpar , only : mxpft use landunit_varcon , only : max_lunit use clm_varctl , only : caseid, ctitle, fsurdat, finidat, paramfile use clm_varctl , only : version, hostname, username, conventions, source @@ -1716,7 +1888,7 @@ subroutine htape_create (t, histrest) integer :: numa ! total number of atm cells across all processors logical :: avoid_pnetcdf ! whether we should avoid using pnetcdf logical :: lhistrest ! local history restart flag - type(file_desc_t) :: lnfid ! local file id + type(file_desc_t), pointer :: lnfid ! local file id character(len= 8) :: curdate ! current date character(len= 8) :: curtime ! current time character(len=256) :: name ! name of attribute @@ -1738,6 +1910,11 @@ subroutine htape_create (t, histrest) ! define output write precsion for tape ncprec = tape(t)%ncprec + if (lhistrest) then + lnfid => ncid_hist(t) + else + lnfid => nfid(t) + endif ! BUG(wjs, 2014-10-20, bugz 1730) Workaround for ! http://bugs.cgd.ucar.edu/show_bug.cgi?id=1730 @@ -1840,36 +2017,40 @@ subroutine htape_create (t, histrest) call ncd_defdim(lnfid, 'cft', cft_size, dimid) call htape_add_cft_metadata(lnfid) end if - if (maxpatch_glcmec > 0) then - call ncd_defdim(lnfid, 'glc_nec' , maxpatch_glcmec , dimid) - ! elevclas (in contrast to glc_nec) includes elevation class 0 (bare land) - ! (although on the history file it will go 1:(nec+1) rather than 0:nec) - call ncd_defdim(lnfid, 'elevclas' , maxpatch_glcmec + 1, dimid) - end if + call ncd_defdim(lnfid, 'glc_nec' , maxpatch_glcmec , dimid) + ! elevclas (in contrast to glc_nec) includes elevation class 0 (bare land) + ! (although on the history file it will go 1:(nec+1) rather than 0:nec) + call ncd_defdim(lnfid, 'elevclas' , maxpatch_glcmec + 1, dimid) do n = 1,num_subs call ncd_defdim(lnfid, subs_name(n), subs_dim(n), dimid) end do - call ncd_defdim(lnfid, 'string_length', 8, strlen_dimid) + call ncd_defdim(lnfid, 'string_length', hist_dim_name_length, strlen_dimid) call ncd_defdim(lnfid, 'scale_type_string_length', scale_type_strlen, dimid) call ncd_defdim( lnfid, 'levdcmp', nlevdecomp_full, dimid) - if(use_ed)then - call ncd_defdim(lnfid, 'levscls', nlevsclass_ed, dimid) - call ncd_defdim(lnfid, 'levscpf', nlevsclass_ed*mxpft, dimid) + if(use_fates)then + call ncd_defdim(lnfid, 'fates_levscag', nlevsclass_ed * nlevage_ed, dimid) + call ncd_defdim(lnfid, 'fates_levscls', nlevsclass_ed, dimid) + call ncd_defdim(lnfid, 'fates_levpft', maxpft, dimid) + call ncd_defdim(lnfid, 'fates_levage', nlevage_ed, dimid) + call ncd_defdim(lnfid, 'fates_levfuel', nfsc, dimid) + call ncd_defdim(lnfid, 'fates_levcwdsc', ncwd, dimid) + call ncd_defdim(lnfid, 'fates_levscpf', nlevsclass_ed*maxpft, dimid) + call ncd_defdim(lnfid, 'fates_levcan', nclmax, dimid) + call ncd_defdim(lnfid, 'fates_levcnlf', nlevleaf * nclmax, dimid) + call ncd_defdim(lnfid, 'fates_levcnlfpf', nlevleaf * nclmax * numpft_ed, dimid) end if if ( .not. lhistrest )then call ncd_defdim(lnfid, 'hist_interval', 2, hist_interval_dimid) call ncd_defdim(lnfid, 'time', ncd_unlimited, time_dimid) - nfid(t) = lnfid if (masterproc)then write(iulog,*) trim(subname), & ' : Successfully defined netcdf history file ',t call shr_sys_flush(iulog) end if else - ncid_hist(t) = lnfid if (masterproc)then write(iulog,*) trim(subname), & ' : Successfully defined netcdf restart history file ',t @@ -2070,7 +2251,7 @@ subroutine htape_timeconst3D(t, & else if (ifld == 5) then long_name='slope of soil water retention curve'; units = 'unitless' else if (ifld == 6) then - long_name='saturated hydraulic conductivity'; units = 'unitless' + long_name='saturated hydraulic conductivity'; units = 'mm s-1' else call endrun(msg=' ERROR: bad 3D time-constant field index'//errMsg(sourcefile, __LINE__)) end if @@ -2273,7 +2454,12 @@ subroutine htape_timeconst(t, mode) use domainMod , only : ldomain, lon1d, lat1d use clm_time_manager, only : get_nstep, get_curr_date, get_curr_time use clm_time_manager, only : get_ref_date, get_calendar, NO_LEAP_C, GREGORIAN_C - use EDTypesMod, only : levsclass_ed, pft_levscpf_ed, scls_levscpf_ed + use EDTypesMod, only : fates_hdim_levsclass, fates_hdim_pfmap_levscpf, fates_hdim_scmap_levscpf + use EDTypesMod, only : fates_hdim_levage, fates_hdim_levpft + use EDTypesMod, only : fates_hdim_scmap_levscag, fates_hdim_agmap_levscag + use EDTypesMod, only : fates_hdim_levfuel, fates_hdim_levcwdsc + use EDTypesMod, only : fates_hdim_levcan, fates_hdim_canmap_levcnlf, fates_hdim_lfmap_levcnlf + use EDTypesMod, only : fates_hdim_canmap_levcnlfpf, fates_hdim_lfmap_levcnlfpf, fates_hdim_pftmap_levcnlfpf ! ! !ARGUMENTS: integer, intent(in) :: t ! tape index @@ -2352,15 +2538,41 @@ subroutine htape_timeconst(t, mode) ncid=nfid(t)) end if - if(use_ed)then - call ncd_defvar(varname='levscls', xtype=tape(t)%ncprec, dim1name='levscls', & - long_name='diameter size class lower bound', units='cm', ncid=nfid(t)) - call ncd_defvar(varname='pft_levscpf',xtype=ncd_int, dim1name='levscpf', & - long_name='pft index of the combined pft-size class dimension', units='-', ncid=nfid(t)) - call ncd_defvar(varname='scls_levscpf',xtype=ncd_int, dim1name='levscpf', & - long_name='size index of the combined pft-size class dimension', units='-', ncid=nfid(t)) + if(use_fates)then + + call ncd_defvar(varname='fates_levscls', xtype=tape(t)%ncprec, dim1name='fates_levscls', & + long_name='FATES diameter size class lower bound', units='cm', ncid=nfid(t)) + call ncd_defvar(varname='fates_scmap_levscag', xtype=ncd_int, dim1name='fates_levscag', & + long_name='FATES size-class map into size x patch age', units='-', ncid=nfid(t)) + call ncd_defvar(varname='fates_agmap_levscag', xtype=ncd_int, dim1name='fates_levscag', & + long_name='FATES age-class map into size x patch age', units='-', ncid=nfid(t)) + call ncd_defvar(varname='fates_pftmap_levscpf',xtype=ncd_int, dim1name='fates_levscpf', & + long_name='FATES pft index of the combined pft-size class dimension', units='-', ncid=nfid(t)) + call ncd_defvar(varname='fates_scmap_levscpf',xtype=ncd_int, dim1name='fates_levscpf', & + long_name='FATES size index of the combined pft-size class dimension', units='-', ncid=nfid(t)) + call ncd_defvar(varname='fates_levage',xtype=tape(t)%ncprec, dim1name='fates_levage', & + long_name='FATES patch age (yr)', ncid=nfid(t)) + call ncd_defvar(varname='fates_levpft',xtype=ncd_int, dim1name='fates_levpft', & + long_name='FATES pft number', ncid=nfid(t)) + call ncd_defvar(varname='fates_levfuel',xtype=ncd_int, dim1name='fates_levfuel', & + long_name='FATES fuel index', ncid=nfid(t)) + call ncd_defvar(varname='fates_levcwdsc',xtype=ncd_int, dim1name='fates_levcwdsc', & + long_name='FATES cwd size class', ncid=nfid(t)) + call ncd_defvar(varname='fates_levcan',xtype=ncd_int, dim1name='fates_levcan', & + long_name='FATES canopy level', ncid=nfid(t)) + call ncd_defvar(varname='fates_canmap_levcnlf',xtype=ncd_int, dim1name='fates_levcnlf', & + long_name='FATES canopy level of combined canopy-leaf dimension', ncid=nfid(t)) + call ncd_defvar(varname='fates_lfmap_levcnlf',xtype=ncd_int, dim1name='fates_levcnlf', & + long_name='FATES leaf level of combined canopy-leaf dimension', ncid=nfid(t)) + call ncd_defvar(varname='fates_canmap_levcnlfpf',xtype=ncd_int, dim1name='fates_levcnlfpf', & + long_name='FATES canopy level of combined canopy x leaf x pft dimension', ncid=nfid(t)) + call ncd_defvar(varname='fates_lfmap_levcnlfpf',xtype=ncd_int, dim1name='fates_levcnlfpf', & + long_name='FATES leaf level of combined canopy x leaf x pft dimension', ncid=nfid(t)) + call ncd_defvar(varname='fates_pftmap_levcnlfpf',xtype=ncd_int, dim1name='fates_levcnlfpf', & + long_name='FATES PFT level of combined canopy x leaf x pft dimension', ncid=nfid(t)) end if + elseif (mode == 'write') then if ( masterproc ) write(iulog, *) ' zsoi:',zsoi call ncd_io(varname='levgrnd', data=zsoi, ncid=nfid(t), flag='write') @@ -2382,10 +2594,22 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') endif - if(use_ed)then - call ncd_io(varname='levscls',data=levsclass_ed, ncid=nfid(t), flag='write') - call ncd_io(varname='pft_levscpf',data=pft_levscpf_ed, ncid=nfid(t), flag='write') - call ncd_io(varname='scls_levscpf',data=scls_levscpf_ed, ncid=nfid(t), flag='write') + if(use_fates)then + call ncd_io(varname='fates_scmap_levscag',data=fates_hdim_scmap_levscag, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_agmap_levscag',data=fates_hdim_agmap_levscag, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_levscls',data=fates_hdim_levsclass, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_pftmap_levscpf',data=fates_hdim_pfmap_levscpf, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_scmap_levscpf',data=fates_hdim_scmap_levscpf, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_levage',data=fates_hdim_levage, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_levpft',data=fates_hdim_levpft, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_levfuel',data=fates_hdim_levfuel, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_levcwdsc',data=fates_hdim_levcwdsc, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_levcan',data=fates_hdim_levcan, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_canmap_levcnlf',data=fates_hdim_canmap_levcnlf, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_lfmap_levcnlf',data=fates_hdim_lfmap_levcnlf, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_canmap_levcnlfpf',data=fates_hdim_canmap_levcnlfpf, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_lfmap_levcnlfpf',data=fates_hdim_lfmap_levcnlfpf, ncid=nfid(t), flag='write') + call ncd_io(varname='fates_pftmap_levcnlfpf',data=fates_hdim_pftmap_levcnlfpf, ncid=nfid(t), flag='write') end if endif @@ -2623,6 +2847,8 @@ subroutine hfields_write(t, mode) integer :: f ! field index integer :: k ! 1d index integer :: c,l,p ! indices + integer :: beg1d ! on-node 1d field pointer start index + integer :: end1d ! on-node 1d field pointer end index integer :: beg1d_out ! on-node 1d hbuf pointer start index integer :: end1d_out ! on-node 1d hbuf pointer end index integer :: num1d_out ! size of hbuf first dimension (overall all nodes) @@ -2634,8 +2860,9 @@ subroutine hfields_write(t, mode) character(len=max_chars) :: units ! units character(len=max_namlen):: varname ! variable name character(len=32) :: avgstr ! time averaging type - character(len=8) :: type1d_out ! history output 1d type - character(len=8) :: type2d ! history output 2d type + character(len=hist_dim_name_length) :: type1d ! field 1d type + character(len=hist_dim_name_length) :: type1d_out ! history output 1d type + character(len=hist_dim_name_length) :: type2d ! history output 2d type character(len=32) :: dim1name ! temporary character(len=32) :: dim2name ! temporary real(r8), pointer :: histo(:,:) ! temporary @@ -2663,7 +2890,10 @@ subroutine hfields_write(t, mode) long_name = tape(t)%hlist(f)%field%long_name units = tape(t)%hlist(f)%field%units avgflag = tape(t)%hlist(f)%avgflag + type1d = tape(t)%hlist(f)%field%type1d type1d_out = tape(t)%hlist(f)%field%type1d_out + beg1d = tape(t)%hlist(f)%field%beg1d + end1d = tape(t)%hlist(f)%field%end1d beg1d_out = tape(t)%hlist(f)%field%beg1d_out end1d_out = tape(t)%hlist(f)%field%end1d_out num1d_out = tape(t)%hlist(f)%field%num1d_out @@ -2792,14 +3022,14 @@ subroutine hfields_1dinfo(t, mode) integer , pointer :: icarr(:) ! temporary integer , pointer :: ilarr(:) ! temporary integer , pointer :: iparr(:) ! temporary - type(file_desc_t) :: ncid ! netcdf file + type(file_desc_t), pointer :: ncid ! netcdf file type(bounds_type) :: bounds character(len=*),parameter :: subname = 'hfields_1dinfo' !----------------------------------------------------------------------- call get_proc_bounds(bounds) - ncid = nfid(t) + ncid => nfid(t) if (mode == 'define') then @@ -3345,7 +3575,7 @@ subroutine hist_restart_ncd (bounds, ncid, flag, rdate) character(len=max_namlen),allocatable :: tname(:) character(len=max_chars), allocatable :: tunits(:),tlongname(:) - character(len=8), allocatable :: tmpstr(:,:) + character(len=hist_dim_name_length), allocatable :: tmpstr(:,:) character(len=scale_type_strlen), allocatable :: p2c_scale_type(:) character(len=scale_type_strlen), allocatable :: c2l_scale_type(:) character(len=scale_type_strlen), allocatable :: l2g_scale_type(:) @@ -3353,9 +3583,9 @@ subroutine hist_restart_ncd (bounds, ncid, flag, rdate) integer :: start(2) character(len=1) :: hnum ! history file index - character(len=8) :: type1d ! clm pointer 1d type - character(len=8) :: type1d_out ! history buffer 1d type - character(len=8) :: type2d ! history buffer 2d type + character(len=hist_dim_name_length) :: type1d ! clm pointer 1d type + character(len=hist_dim_name_length) :: type1d_out ! history buffer 1d type + character(len=hist_dim_name_length) :: type2d ! history buffer 2d type character(len=32) :: dim1name ! temporary character(len=32) :: dim2name ! temporary type(var_desc_t) :: name_desc ! variable descriptor for name @@ -4245,8 +4475,8 @@ subroutine hist_addfld1d (fname, units, avgflag, long_name, type1d_out, & ! !LOCAL VARIABLES: integer :: p,c,l,g ! indices integer :: hpindex ! history buffer pointer index - character(len=8) :: l_type1d ! 1d data type - character(len=8) :: l_type1d_out ! 1d output type + character(len=hist_dim_name_length) :: l_type1d ! 1d data type + character(len=hist_dim_name_length) :: l_type1d_out ! 1d output type character(len=scale_type_strlen) :: scale_type_p2c ! scale type for subgrid averaging of pfts to column character(len=scale_type_strlen) :: scale_type_c2l ! scale type for subgrid averaging of columns to landunits character(len=scale_type_strlen) :: scale_type_l2g ! scale type for subgrid averaging of landunits to gridcells @@ -4440,7 +4670,7 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, ! ! !USES: use clm_varpar , only : nlevgrnd, nlevsno, nlevlak, numrad, nlevdecomp_full, nlevcan, nvegwcs,nlevsoi - use clm_varpar , only : natpft_size, cft_size, maxpatch_glcmec, mxpft + use clm_varpar , only : natpft_size, cft_size, maxpatch_glcmec use landunit_varcon , only : max_lunit ! ! !ARGUMENTS: @@ -4471,8 +4701,8 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, integer :: p,c,l,g ! indices integer :: num2d ! size of second dimension (e.g. number of vertical levels) integer :: hpindex ! history buffer index - character(len=8) :: l_type1d ! 1d data type - character(len=8) :: l_type1d_out ! 1d output type + character(len=hist_dim_name_length) :: l_type1d ! 1d data type + character(len=hist_dim_name_length) :: l_type1d_out ! 1d output type character(len=scale_type_strlen) :: scale_type_p2c ! scale type for subgrid averaging of pfts to column character(len=scale_type_strlen) :: scale_type_c2l ! scale type for subgrid averaging of columns to landunits character(len=scale_type_strlen) :: scale_type_l2g ! scale type for subgrid averaging of landunits to gridcells @@ -4520,13 +4750,29 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, num2d = numrad case ('levdcmp') num2d = nlevdecomp_full - case ('levscls') + case ('fates_levscls') num2d = nlevsclass_ed - case ('levscpf') - num2d = nlevsclass_ed*mxpft - case('ltype') + case ('fates_levpft') + num2d = maxpft + case ('fates_levage') + num2d = nlevage_ed + case ('fates_levfuel') + num2d = nfsc + case ('fates_levcwdsc') + num2d = ncwd + case ('fates_levscpf') + num2d = nlevsclass_ed*maxpft + case ('fates_levscag') + num2d = nlevsclass_ed*nlevage_ed + case ('fates_levcan') + num2d = nclmax + case ('fates_levcnlf') + num2d = nlevleaf * nclmax + case ('fates_levcnlfpf') + num2d = nlevleaf * nclmax * numpft_ed + case ('ltype') num2d = max_lunit - case('natpft') + case ('natpft') num2d = natpft_size case('cft') if (cft_size > 0) then @@ -4537,23 +4783,11 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, call endrun() end if case ('glc_nec') - if (maxpatch_glcmec > 0) then - num2d = maxpatch_glcmec - else - write(iulog,*) trim(subname),' ERROR: 2d type =', trim(type2d), & - ' only valid for maxpatch_glcmec > 0' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + num2d = maxpatch_glcmec case ('elevclas') - if (maxpatch_glcmec > 0) then - ! add one because indexing starts at 0 (elevclas, unlike glc_nec, includes the - ! bare ground "elevation class") - num2d = maxpatch_glcmec + 1 - else - write(iulog,*) trim(subname),' ERROR: 2d type =', trim(type2d), & - ' only valid for maxpatch_glcmec > 0' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + ! add one because indexing starts at 0 (elevclas, unlike glc_nec, includes the + ! bare ground "elevation class") + num2d = maxpatch_glcmec + 1 case ('levsno') num2d = nlevsno case ('nlevcan') diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index 7184d1f16b..fdb2227eff 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -37,9 +37,8 @@ module initGridCellsMod public initGridcells ! initialize sub-grid gridcell mapping ! ! !PRIVATE MEMBER FUNCTIONS: - private set_cohort_decomp private set_landunit_veg_compete - private set_landunit_wet_ice_lake + private set_landunit_wet_lake private set_landunit_ice_mec private set_landunit_crop_noncompete private set_landunit_urban @@ -61,9 +60,9 @@ subroutine initGridcells(glc_behavior) use domainMod , only : ldomain use decompMod , only : get_proc_bounds, get_clump_bounds, get_proc_clumps use subgridWeightsMod , only : compute_higher_order_weights - use landunit_varcon , only : istsoil, istice, istwet, istdlak, istice_mec + use landunit_varcon , only : istsoil, istwet, istdlak, istice_mec use landunit_varcon , only : isturb_tbd, isturb_hd, isturb_md, istcrop - use clm_varctl , only : create_glacier_mec_landunit, use_ed + use clm_varctl , only : use_fates use shr_const_mod , only : SHR_CONST_PI ! ! !ARGUMENTS: @@ -167,33 +166,21 @@ subroutine initGridcells(glc_behavior) ! Determine lake, wetland and glacier landunits do gdc = bounds_clump%begg,bounds_clump%endg - call set_landunit_wet_ice_lake( & + call set_landunit_wet_lake( & ltype=istdlak, gi=gdc, li=li, ci=ci, pi=pi) end do do gdc = bounds_clump%begg,bounds_clump%endg - call set_landunit_wet_ice_lake( & + call set_landunit_wet_lake( & ltype=istwet, gi=gdc, li=li, ci=ci, pi=pi) end do do gdc = bounds_clump%begg,bounds_clump%endg - call set_landunit_wet_ice_lake( & - ltype=istice, gi=gdc, li=li, ci=ci, pi=pi) + call set_landunit_ice_mec( & + glc_behavior = glc_behavior, & + ltype=istice_mec, gi=gdc, li=li, ci=ci, pi=pi) end do - if (create_glacier_mec_landunit) then - do gdc = bounds_clump%begg,bounds_clump%endg - call set_landunit_ice_mec( & - glc_behavior = glc_behavior, & - ltype=istice_mec, gi=gdc, li=li, ci=ci, pi=pi) - end do - endif - - if ( use_ed ) then - ! cohort decomp - call set_cohort_decomp( bounds_clump=bounds_clump ) - end if - ! Ensure that we have set the expected number of patchs, cols and landunits for this clump SHR_ASSERT(li == bounds_clump%endl, errMsg(sourcefile, __LINE__)) SHR_ASSERT(ci == bounds_clump%endc, errMsg(sourcefile, __LINE__)) @@ -227,33 +214,6 @@ subroutine initGridcells(glc_behavior) end subroutine initGridcells - !------------------------------------------------------------------------ - subroutine set_cohort_decomp ( bounds_clump ) - ! - ! !DESCRIPTION: - ! Set gridcell decomposition for cohorts - ! - use EDTypesMod , only : cohorts_per_col - use EDVecCohortType , only : ed_vec_cohort - ! - ! !ARGUMENTS: - type(bounds_type), intent(in) :: bounds_clump - ! - ! !LOCAL VARIABLES: - integer c, ci - !------------------------------------------------------------------------ - - ci = bounds_clump%begc - - do c = bounds_clump%begCohort, bounds_clump%endCohort - - ed_vec_cohort%column(c) = ci - if ( mod(c, cohorts_per_col ) == 0 ) ci = ci + 1 - - end do - - end subroutine set_cohort_decomp - !------------------------------------------------------------------------ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) ! @@ -305,16 +265,15 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) end subroutine set_landunit_veg_compete !------------------------------------------------------------------------ - subroutine set_landunit_wet_ice_lake (ltype, gi, li, ci, pi) + subroutine set_landunit_wet_lake (ltype, gi, li, ci, pi) ! ! !DESCRIPTION: - ! Initialize weland, glacier and lake landunits + ! Initialize wetland and lake landunits ! ! !USES use clm_instur , only : wt_lunit - use landunit_varcon , only : istwet, istdlak, istice + use landunit_varcon , only : istwet, istdlak use subgridMod , only : subgrid_get_info_wetland, subgrid_get_info_lake - use subgridMod , only : subgrid_get_info_glacier use pftconMod , only : noveg ! @@ -340,12 +299,9 @@ subroutine set_landunit_wet_ice_lake (ltype, gi, li, ci, pi) else if (ltype == istdlak) then call subgrid_get_info_lake(gi, & npatches=npatches, ncols=ncols, nlunits=nlunits) - else if (ltype == istice) then - call subgrid_get_info_glacier(gi, & - npatches=npatches, ncols=ncols, nlunits=nlunits) else - write(iulog,*)' set_landunit_wet_ice_lake: ltype of ',ltype,' not valid' - write(iulog,*)' only istwet, istdlak and istice ltypes are valid' + write(iulog,*)' set_landunit_wet_lake: ltype of ',ltype,' not valid' + write(iulog,*)' only istwet and istdlak ltypes are valid' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -354,7 +310,7 @@ subroutine set_landunit_wet_ice_lake (ltype, gi, li, ci, pi) if (npatches > 0) then if (npatches /= 1) then - write(iulog,*)' set_landunit_wet_ice_lake: compete landunit must'// & + write(iulog,*)' set_landunit_wet_lake: compete landunit must'// & ' have one patch ' write(iulog,*)' current value of npatches=',npatches call endrun(msg=errMsg(sourcefile, __LINE__)) @@ -369,7 +325,7 @@ subroutine set_landunit_wet_ice_lake (ltype, gi, li, ci, pi) endif ! npatches > 0 - end subroutine set_landunit_wet_ice_lake + end subroutine set_landunit_wet_lake !----------------------------------------------------------------------- subroutine set_landunit_ice_mec(glc_behavior, ltype, gi, li, ci, pi) @@ -456,14 +412,15 @@ subroutine set_landunit_crop_noncompete (ltype, gi, li, ci, pi) ! ! Note about the ltype input argument: This provides the value for this landunit index ! (i.e., the crop landunit index). This may differ from the landunit's 'itype' value, - ! since itype is istsoil if we are running with create_crop_landunit but use_crop = false. + ! since itype is istsoil if we are running with create_crop_landunit but for + ! an older surface dataset that ! ! !USES use clm_instur , only : wt_lunit, wt_cft use landunit_varcon , only : istcrop, istsoil use subgridMod , only : subgrid_get_info_crop, crop_patch_exists use clm_varpar , only : maxpatch_pft, cft_lb, cft_ub - use clm_varctl , only : use_crop + use clm_varctl , only : create_crop_landunit ! ! !ARGUMENTS: integer , intent(in) :: ltype ! landunit type @@ -491,8 +448,12 @@ subroutine set_landunit_crop_noncompete (ltype, gi, li, ci, pi) ! Note that we cannot simply use the 'ltype' argument to set itype here, ! because ltype will always indicate istcrop - if ( use_crop )then - my_ltype = istcrop + if ( create_crop_landunit )then + my_ltype = ltype ! Will always be istcrop + if ( ltype /= istcrop )then + write(iulog,*)' create_crop_landunit on and ltype is not istcrop: ', ltype + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if else my_ltype = istsoil end if diff --git a/src/main/initSubgridMod.F90 b/src/main/initSubgridMod.F90 index efd3d61351..78e60e88f0 100644 --- a/src/main/initSubgridMod.F90 +++ b/src/main/initSubgridMod.F90 @@ -10,13 +10,14 @@ module initSubgridMod use shr_log_mod , only : errMsg => shr_log_errMsg use spmdMod , only : masterproc use abortutils , only : endrun - use clm_varctl , only : iulog, use_ed + use clm_varctl , only : iulog, use_fates use clm_varcon , only : namep, namec, namel use decompMod , only : bounds_type use GridcellType , only : grc use LandunitType , only : lun use ColumnType , only : col use PatchType , only : patch + use column_varcon , only : is_hydrologically_active ! ! !PUBLIC TYPES: implicit none @@ -417,6 +418,9 @@ subroutine add_column(ci, li, ctype, wtlunit, type_is_dynamic) col%wtlunit(ci) = wtlunit col%itype(ci) = ctype col%type_is_dynamic(ci) = l_type_is_dynamic + col%hydrologically_active(ci) = is_hydrologically_active( & + col_itype = ctype, & + lun_itype = lun%itype(li)) end subroutine add_column @@ -456,9 +460,9 @@ subroutine add_patch(pi, ci, ptype, wtcol) ! TODO (MV, 10-17-14): The following must be commented out because ! currently patch%itype is used in CanopyTemperatureMod to calculate - ! z0m(p) and displa(p) - and is still called even when ED is on + ! z0m(p) and displa(p) - and is still called even when fates is on - !if (.not. use_ed) then + !if (.not. use_fates) then patch%itype(pi) = ptype !end if diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index ce9a83f645..8c808aaf7d 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -18,7 +18,7 @@ module initVerticalMod use clm_varctl , only : fsurdat, iulog use clm_varctl , only : use_vancouver, use_mexicocity, use_vertsoilc, use_extralakelayers use clm_varctl , only : use_bedrock, soil_layerstruct - use clm_varctl , only : use_ed + use clm_varctl , only : use_fates use clm_varcon , only : zlak, dzlak, zsoi, dzsoi, zisoi, dzsoi_decomp, spval, ispval, grlnd use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, is_hydrologically_active use landunit_varcon , only : istdlak, istice_mec, istsoil @@ -364,7 +364,7 @@ subroutine initVertical(bounds, glc_behavior, snow_depth, thick_wall, thick_roof end if end if - if(use_ed)then + if(use_fates)then call ed_hist_scpfmaps end if @@ -803,8 +803,8 @@ logical function hasBedrock(col_itype, lun_itype) ! from the upper layers. ! ! !USES: - use landunit_varcon, only : istice, istice_mec, isturb_MIN, isturb_MAX - use column_varcon , only : icol_road_perv, is_hydrologically_active + use landunit_varcon, only : istice_mec, isturb_MIN, isturb_MAX + use column_varcon , only : icol_road_perv ! ! !ARGUMENTS: integer, intent(in) :: col_itype ! col%itype value @@ -827,7 +827,7 @@ logical function hasBedrock(col_itype, lun_itype) ! == istdlak - that way, hasBedrock(lake) would be more likely to get updated ! correctly if the lake logic changes. - if (lun_itype == istice .or. lun_itype == istice_mec) then + if (lun_itype == istice_mec) then hasBedrock = .false. else if (lun_itype >= isturb_MIN .and. lun_itype <= isturb_MAX) then if (col_itype == icol_road_perv) then diff --git a/src/main/init_hydrology.F90 b/src/main/init_hydrology.F90 index 25a279d0af..f03658c71a 100644 --- a/src/main/init_hydrology.F90 +++ b/src/main/init_hydrology.F90 @@ -29,6 +29,8 @@ subroutine init_hydrology( NLFilename ) call init_rootprof(NLFilename) call init_soilwater_movement + + call init_root_moist_stress ! remove due to circular dependency of nlfilename, read namlist ! in controlmod instead, as is done for canopyhydrology diff --git a/src/main/landunit_varcon.F90 b/src/main/landunit_varcon.F90 index d0600becc7..b6ddc7cf5c 100644 --- a/src/main/landunit_varcon.F90 +++ b/src/main/landunit_varcon.F90 @@ -18,7 +18,7 @@ module landunit_varcon integer, parameter, public :: istsoil = 1 !soil landunit type (natural vegetation) integer, parameter, public :: istcrop = 2 !crop landunit type - integer, parameter, public :: istice = 3 !land ice landunit type (glacier) + ! Landunit 3 currently unused (used to be non-multiple elevation class glacier type: istice) integer, parameter, public :: istice_mec = 4 !land ice (multiple elevation classes) landunit type integer, parameter, public :: istdlak = 5 !deep lake landunit type (now used for all lakes) integer, parameter, public :: istwet = 6 !wetland landunit type (swamp, marsh, etc.) @@ -108,6 +108,7 @@ subroutine set_landunit_names use shr_sys_mod, only : shr_sys_abort ! character(len=*), parameter :: not_set = 'NOT_SET' + character(len=*), parameter :: unused = 'UNUSED' character(len=*), parameter :: subname = 'set_landunit_names' !----------------------------------------------------------------------- @@ -115,7 +116,7 @@ subroutine set_landunit_names landunit_names(istsoil) = 'vegetated_or_bare_soil' landunit_names(istcrop) = 'crop' - landunit_names(istice) = 'landice' + landunit_names(istcrop+1) = unused landunit_names(istice_mec) = 'landice_multiple_elevation_classes' landunit_names(istdlak) = 'deep_lake' landunit_names(istwet) = 'wetland' diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index 7523a4d1b7..2a4a00d5cd 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -13,7 +13,7 @@ module lnd2atmMod use shr_fire_emis_mod , only : shr_fire_emis_mechcomps_n use clm_varpar , only : numrad, ndst, nlevgrnd !ndst = number of dust bins. use clm_varcon , only : rair, grav, cpair, hfus, tfrz, spval - use clm_varctl , only : iulog, use_lch4, use_voc + use clm_varctl , only : iulog, use_lch4 use seq_drydep_mod , only : n_drydep, drydep_method, DD_XLND use decompMod , only : bounds_type use subgridAveMod , only : p2g, c2g @@ -32,7 +32,12 @@ module lnd2atmMod use WaterFluxType , only : waterflux_type use WaterstateType , only : waterstate_type use IrrigationMod , only : irrigation_type + use glcBehaviorMod , only : glc_behavior_type + use glc2lndMod , only : glc2lnd_type + use ColumnType , only : col + use LandunitType , only : lun use GridcellType , only : grc + use landunit_varcon , only : istice_mec ! ! !PUBLIC TYPES: implicit none @@ -42,6 +47,10 @@ module lnd2atmMod public :: lnd2atm public :: lnd2atm_minimal + ! + ! !PRIVATE MEMBER FUNCTIONS: + private :: handle_ice_runoff + character(len=*), parameter, private :: sourcefile = & __FILE__ !------------------------------------------------------------------------ @@ -116,7 +125,8 @@ subroutine lnd2atm(bounds, & atm2lnd_inst, surfalb_inst, temperature_inst, frictionvel_inst, & waterstate_inst, waterflux_inst, irrigation_inst, energyflux_inst, & solarabs_inst, drydepvel_inst, & - vocemis_inst, fireemis_inst, dust_inst, ch4_inst, lnd2atm_inst, & + vocemis_inst, fireemis_inst, dust_inst, ch4_inst, glc_behavior, & + lnd2atm_inst, & net_carbon_exchange_grc) ! ! !DESCRIPTION: @@ -124,7 +134,6 @@ subroutine lnd2atm(bounds, & ! ! !USES: use ch4varcon , only : ch4offline - use ColumnType , only : col ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -133,7 +142,7 @@ subroutine lnd2atm(bounds, & type(temperature_type) , intent(in) :: temperature_inst type(frictionvel_type) , intent(in) :: frictionvel_inst type(waterstate_type) , intent(inout) :: waterstate_inst - type(waterflux_type) , intent(in) :: waterflux_inst + type(waterflux_type) , intent(inout) :: waterflux_inst type(irrigation_type) , intent(in) :: irrigation_inst type(energyflux_type) , intent(in) :: energyflux_inst type(solarabs_type) , intent(in) :: solarabs_inst @@ -142,12 +151,14 @@ subroutine lnd2atm(bounds, & type(fireemis_type) , intent(in) :: fireemis_inst type(dust_type) , intent(in) :: dust_inst type(ch4_type) , intent(in) :: ch4_inst + type(glc_behavior_type) , intent(in) :: glc_behavior type(lnd2atm_type) , intent(inout) :: lnd2atm_inst real(r8) , intent(in) :: net_carbon_exchange_grc( bounds%begg: ) ! net carbon exchange between land and atmosphere, positive for source (gC/m2/s) ! ! !LOCAL VARIABLES: integer :: c, g ! indices real(r8) :: qflx_ice_runoff_col(bounds%begc:bounds%endc) ! total column-level ice runoff + real(r8) :: eflx_sh_ice_to_liq_grc(bounds%begg:bounds%endg) ! sensible heat flux generated from the ice to liquid conversion, averaged to gridcell real(r8), parameter :: amC = 12.0_r8 ! Atomic mass number for Carbon real(r8), parameter :: amO = 16.0_r8 ! Atomic mass number for Oxygen real(r8), parameter :: amCO2 = amC + 2.0_r8*amO ! Atomic mass number for CO2 @@ -157,6 +168,12 @@ subroutine lnd2atm(bounds, & SHR_ASSERT_ALL((ubound(net_carbon_exchange_grc) == (/bounds%endg/)), errMsg(sourcefile, __LINE__)) + call handle_ice_runoff(bounds, waterflux_inst, glc_behavior, & + melt_non_icesheet_ice_runoff = lnd2atm_inst%params%melt_non_icesheet_ice_runoff, & + qflx_ice_runoff_col = qflx_ice_runoff_col(bounds%begc:bounds%endc), & + qflx_liq_from_ice_col = lnd2atm_inst%qflx_liq_from_ice_col(bounds%begc:bounds%endc), & + eflx_sh_ice_to_liq_col = lnd2atm_inst%eflx_sh_ice_to_liq_col(bounds%begc:bounds%endc)) + !---------------------------------------------------- ! lnd -> atm !---------------------------------------------------- @@ -218,9 +235,14 @@ subroutine lnd2atm(bounds, & energyflux_inst%eflx_sh_precip_conversion_col (bounds%begc:bounds%endc), & lnd2atm_inst%eflx_sh_precip_conversion_grc (bounds%begg:bounds%endg), & c2l_scale_type='urbanf', l2g_scale_type='unity') + call c2g( bounds, & + lnd2atm_inst%eflx_sh_ice_to_liq_col(bounds%begc:bounds%endc), & + eflx_sh_ice_to_liq_grc(bounds%begg:bounds%endg), & + c2l_scale_type='urbanf', l2g_scale_type='unity') do g = bounds%begg, bounds%endg lnd2atm_inst%eflx_sh_tot_grc(g) = lnd2atm_inst%eflx_sh_tot_grc(g) + & - lnd2atm_inst%eflx_sh_precip_conversion_grc(g) - & + lnd2atm_inst%eflx_sh_precip_conversion_grc(g) + & + eflx_sh_ice_to_liq_grc(g) - & energyflux_inst%eflx_dynbal_grc(g) enddo @@ -258,7 +280,7 @@ subroutine lnd2atm(bounds, & endif ! voc emission flux - if (use_voc .and. shr_megan_mechcomps_n>0) then + if (shr_megan_mechcomps_n>0) then call p2g(bounds, shr_megan_mechcomps_n, & vocemis_inst%vocflx_patch(bounds%begp:bounds%endp,:), & lnd2atm_inst%flxvoc_grc (bounds%begg:bounds%endg,:), & @@ -296,14 +318,6 @@ subroutine lnd2atm(bounds, & ! lnd -> rof !---------------------------------------------------- - call c2g( bounds, & - waterflux_inst%qflx_runoff_col (bounds%begc:bounds%endc), & - lnd2atm_inst%qflx_rofliq_grc (bounds%begg:bounds%endg), & - c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) - do g = bounds%begg, bounds%endg - lnd2atm_inst%qflx_rofliq_grc(g) = lnd2atm_inst%qflx_rofliq_grc(g) - waterflux_inst%qflx_liq_dynbal_grc(g) - enddo - call c2g( bounds, & waterflux_inst%qflx_surf_col (bounds%begc:bounds%endc), & lnd2atm_inst%qflx_rofliq_qsur_grc (bounds%begg:bounds%endg), & @@ -314,13 +328,36 @@ subroutine lnd2atm(bounds, & lnd2atm_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + do c = bounds%begc, bounds%endc + if (col%active(c)) then + ! It's not entirely appropriate to put qflx_liq_from_ice_col into + ! qflx_qrgwl_col, since this isn't necessarily just glaciers, wetlands and + ! lakes. But since we put the liquid portion of snow capping into + ! qflx_qrgwl_col, it seems reasonable to put qflx_liq_from_ice_col there as + ! well. + waterflux_inst%qflx_qrgwl_col(c) = waterflux_inst%qflx_qrgwl_col(c) + & + lnd2atm_inst%qflx_liq_from_ice_col(c) + + ! qflx_runoff is the sum of a number of terms, including qflx_qrgwl. Since we + ! are adjusting qflx_qrgwl above, we need to adjust qflx_runoff analogously. + waterflux_inst%qflx_runoff_col(c) = waterflux_inst%qflx_runoff_col(c) + & + lnd2atm_inst%qflx_liq_from_ice_col(c) + end if + end do + call c2g( bounds, & waterflux_inst%qflx_qrgwl_col (bounds%begc:bounds%endc), & lnd2atm_inst%qflx_rofliq_qgwl_grc (bounds%begg:bounds%endg), & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + call c2g( bounds, & + waterflux_inst%qflx_runoff_col (bounds%begc:bounds%endc), & + lnd2atm_inst%qflx_rofliq_grc (bounds%begg:bounds%endg), & + c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + do g = bounds%begg, bounds%endg lnd2atm_inst%qflx_rofliq_qgwl_grc(g) = lnd2atm_inst%qflx_rofliq_qgwl_grc(g) - waterflux_inst%qflx_liq_dynbal_grc(g) + lnd2atm_inst%qflx_rofliq_grc(g) = lnd2atm_inst%qflx_rofliq_grc(g) - waterflux_inst%qflx_liq_dynbal_grc(g) enddo call c2g( bounds, & @@ -338,12 +375,6 @@ subroutine lnd2atm(bounds, & lnd2atm_inst%qirrig_grc(bounds%begg:bounds%endg), & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) - do c = bounds%begc, bounds%endc - if (col%active(c)) then - qflx_ice_runoff_col(c) = waterflux_inst%qflx_ice_runoff_snwcp_col(c) + & - waterflux_inst%qflx_ice_runoff_xs_col(c) - end if - end do call c2g( bounds, & qflx_ice_runoff_col(bounds%begc:bounds%endc), & lnd2atm_inst%qflx_rofice_grc(bounds%begg:bounds%endg), & @@ -367,4 +398,94 @@ subroutine lnd2atm(bounds, & end subroutine lnd2atm + !----------------------------------------------------------------------- + subroutine handle_ice_runoff(bounds, waterflux_inst, glc_behavior, & + melt_non_icesheet_ice_runoff, & + qflx_ice_runoff_col, qflx_liq_from_ice_col, eflx_sh_ice_to_liq_col) + ! + ! !DESCRIPTION: + ! Take column-level ice runoff and divide it between (a) ice runoff, and (b) liquid + ! runoff with a compensating negative sensible heat flux. + ! + ! The rationale here is: Ice runoff is largely meant to represent a crude + ! parameterization of iceberg calving. Iceberg calving is mainly appropriate in + ! regions where an ice sheet terminates at the land-ocean boundary. Elsewhere, in + ! reality, we expect most ice runoff to flow downstream and melt before it reaches the + ! ocean. Furthermore, sending ice runoff directly to the ocean can lead to runaway sea + ! ice growth in some regions (around the Canadian archipelago, and possibly in more + ! wide-spread regions of the Arctic Ocean); melting this ice before it reaches the + ! ocean avoids this problem. + ! + ! If the river model were able to melt ice, then we might not need this routine. + ! + ! Note that this routine does NOT handle ice runoff generated via the dynamic + ! landunits adjustment fluxes (i.e., the fluxes that compensate for a difference in + ! ice content between the pre- and post-dynamic landunit areas). This is partly + ! because those gridcell-level dynamic landunits adjustment fluxes do not fit well + ! with this column-based infrastructure, and partly because either method of handling + ! these fluxes (i.e., sending an ice runoff or sending a liquid runoff with a + ! negative sensible heat flux) seems equally justifiable. + ! + ! !USES: + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + type(waterflux_type), intent(in) :: waterflux_inst + type(glc_behavior_type), intent(in) :: glc_behavior + logical, intent(in) :: melt_non_icesheet_ice_runoff + real(r8), intent(out) :: qflx_ice_runoff_col( bounds%begc: ) ! total column-level ice runoff (mm H2O /s) + real(r8), intent(out) :: qflx_liq_from_ice_col( bounds%begc: ) ! liquid runoff from converted ice runoff (mm H2O /s) + real(r8), intent(out) :: eflx_sh_ice_to_liq_col( bounds%begc: ) ! sensible heat flux generated from the ice to liquid conversion (W/m2) (+ to atm) + + ! + ! !LOCAL VARIABLES: + integer :: c, l, g + logical :: do_conversion + + character(len=*), parameter :: subname = 'handle_ice_runoff' + !----------------------------------------------------------------------- + + SHR_ASSERT_ALL((ubound(qflx_ice_runoff_col) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(qflx_liq_from_ice_col) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(eflx_sh_ice_to_liq_col) == (/bounds%endc/)), errMsg(sourcefile, __LINE__)) + + do c = bounds%begc, bounds%endc + if (col%active(c)) then + qflx_ice_runoff_col(c) = waterflux_inst%qflx_ice_runoff_snwcp_col(c) + & + waterflux_inst%qflx_ice_runoff_xs_col(c) + qflx_liq_from_ice_col(c) = 0._r8 + eflx_sh_ice_to_liq_col(c) = 0._r8 + end if + end do + + if (melt_non_icesheet_ice_runoff) then + do c = bounds%begc, bounds%endc + if (col%active(c)) then + l = col%landunit(c) + g = col%gridcell(c) + do_conversion = .false. + if (lun%itype(l) /= istice_mec) then + do_conversion = .true. + else ! istice_mec + if (glc_behavior%ice_runoff_melted_grc(g)) then + do_conversion = .true. + else + do_conversion = .false. + end if + end if + if (do_conversion) then + ! ice to liquid absorbs energy, so results in a negative heat flux to atm + ! Note that qflx_ice_runoff_col is in mm H2O/s, which is the same as kg + ! m-2 s-1, so we can simply multiply by hfus. + eflx_sh_ice_to_liq_col(c) = -qflx_ice_runoff_col(c) * hfus + qflx_liq_from_ice_col(c) = qflx_ice_runoff_col(c) + qflx_ice_runoff_col(c) = 0._r8 + end if + end if + end do + end if + + end subroutine handle_ice_runoff + + end module lnd2atmMod diff --git a/src/main/lnd2atmType.F90 b/src/main/lnd2atmType.F90 index d83fda5b57..023608a4a7 100644 --- a/src/main/lnd2atmType.F90 +++ b/src/main/lnd2atmType.F90 @@ -8,10 +8,11 @@ module lnd2atmType use shr_kind_mod , only : r8 => shr_kind_r8 use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) use shr_log_mod , only : errMsg => shr_log_errMsg + use abortutils , only : endrun use decompMod , only : bounds_type use clm_varpar , only : numrad, ndst, nlevgrnd !ndst = number of dust bins. use clm_varcon , only : spval - use clm_varctl , only : use_lch4 + use clm_varctl , only : iulog, use_lch4 use shr_megan_mod , only : shr_megan_mechcomps_n use shr_fire_emis_mod,only : shr_fire_emis_mechcomps_n use seq_drydep_mod, only : n_drydep, drydep_method, DD_XLND @@ -20,10 +21,17 @@ module lnd2atmType implicit none private + type, public :: lnd2atm_params_type + ! true => ice runoff generated from non-glacier columns and glacier columns outside + ! icesheet regions is converted to liquid, with an appropriate sensible heat flux + logical, public :: melt_non_icesheet_ice_runoff + end type lnd2atm_params_type + ! ---------------------------------------------------- ! land -> atmosphere variables structure !---------------------------------------------------- type, public :: lnd2atm_type + type(lnd2atm_params_type) :: params ! lnd->atm real(r8), pointer :: t_rad_grc (:) => null() ! radiative temperature (Kelvin) @@ -39,6 +47,7 @@ module lnd2atmType real(r8), pointer :: eflx_lh_tot_grc (:) => null() ! total latent HF (W/m**2) [+ to atm] real(r8), pointer :: eflx_sh_tot_grc (:) => null() ! total sensible HF (W/m**2) [+ to atm] real(r8), pointer :: eflx_sh_precip_conversion_grc(:) => null() ! sensible HF from precipitation conversion (W/m**2) [+ to atm] + real(r8), pointer :: eflx_sh_ice_to_liq_col(:) => null() ! sensible HF generated from conversion of ice runoff to liquid (W/m**2) [+ to atm] real(r8), pointer :: eflx_lwrad_out_grc (:) => null() ! IR (longwave) radiation (W/m**2) real(r8), pointer :: qflx_evap_tot_grc (:) => null() ! qflx_evap_soi + qflx_evap_can + qflx_tran_veg real(r8), pointer :: fsa_grc (:) => null() ! solar rad absorbed (total) (W/m**2) @@ -60,26 +69,59 @@ module lnd2atmType real(r8), pointer :: qflx_rofliq_h2osfc_grc (:) => null() ! rof liq -- surface water runoff component real(r8), pointer :: qflx_rofliq_drain_perched_grc (:) => null() ! rof liq -- perched water table runoff component real(r8), pointer :: qflx_rofice_grc (:) => null() ! rof ice forcing + real(r8), pointer :: qflx_liq_from_ice_col(:) => null() ! liquid runoff from converted ice runoff real(r8), pointer :: qirrig_grc (:) => null() ! irrigation flux contains procedure, public :: Init + procedure, private :: ReadNamelist procedure, private :: InitAllocate procedure, private :: InitHistory end type lnd2atm_type !------------------------------------------------------------------------ + interface lnd2atm_params_type + module procedure lnd2atm_params_constructor + end interface lnd2atm_params_type + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + !------------------------------------------------------------------------ + contains + !----------------------------------------------------------------------- + function lnd2atm_params_constructor(melt_non_icesheet_ice_runoff) & + result(params) + ! + ! !DESCRIPTION: + ! Creates a new instance of lnd2atm_params_type + ! + ! !ARGUMENTS: + type(lnd2atm_params_type) :: params ! function result + logical, intent(in) :: melt_non_icesheet_ice_runoff + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'lnd2atm_params_type' + !----------------------------------------------------------------------- + + params%melt_non_icesheet_ice_runoff = melt_non_icesheet_ice_runoff + + end function lnd2atm_params_constructor + + !------------------------------------------------------------------------ - subroutine Init(this, bounds) + subroutine Init(this, bounds, NLFilename) class(lnd2atm_type) :: this type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: NLFilename ! Namelist filename call this%InitAllocate(bounds) + call this%ReadNamelist(NLFilename) call this%InitHistory(bounds) end subroutine Init @@ -96,10 +138,12 @@ subroutine InitAllocate(this, bounds) ! ! !LOCAL VARIABLES: real(r8) :: ival = 0.0_r8 ! initial value + integer :: begc, endc integer :: begg, endg !------------------------------------------------------------------------ - begg = bounds%begg; endg= bounds%endg + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg allocate(this%t_rad_grc (begg:endg)) ; this%t_rad_grc (:) =ival allocate(this%t_ref2m_grc (begg:endg)) ; this%t_ref2m_grc (:) =ival @@ -114,6 +158,7 @@ subroutine InitAllocate(this, bounds) allocate(this%eflx_lwrad_out_grc (begg:endg)) ; this%eflx_lwrad_out_grc (:) =ival allocate(this%eflx_sh_tot_grc (begg:endg)) ; this%eflx_sh_tot_grc (:) =ival allocate(this%eflx_sh_precip_conversion_grc(begg:endg)) ; this%eflx_sh_precip_conversion_grc(:) = ival + allocate(this%eflx_sh_ice_to_liq_col(begc:endc)) ; this%eflx_sh_ice_to_liq_col(:) = ival allocate(this%eflx_lh_tot_grc (begg:endg)) ; this%eflx_lh_tot_grc (:) =ival allocate(this%qflx_evap_tot_grc (begg:endg)) ; this%qflx_evap_tot_grc (:) =ival allocate(this%fsa_grc (begg:endg)) ; this%fsa_grc (:) =ival @@ -130,6 +175,7 @@ subroutine InitAllocate(this, bounds) allocate(this%qflx_rofliq_h2osfc_grc (begg:endg)) ; this%qflx_rofliq_h2osfc_grc (:) =ival allocate(this%qflx_rofliq_drain_perched_grc (begg:endg)) ; this%qflx_rofliq_drain_perched_grc (:) =ival allocate(this%qflx_rofice_grc (begg:endg)) ; this%qflx_rofice_grc (:) =ival + allocate(this%qflx_liq_from_ice_col(begc:endc)) ; this%qflx_liq_from_ice_col(:) = ival allocate(this%qirrig_grc (begg:endg)) ; this%qirrig_grc (:) =ival if (shr_megan_mechcomps_n>0) then @@ -147,6 +193,69 @@ subroutine InitAllocate(this, bounds) end subroutine InitAllocate + !----------------------------------------------------------------------- + subroutine ReadNamelist(this, NLFilename) + ! + ! !DESCRIPTION: + ! Read the lnd2atm namelist + ! + ! !USES: + use fileutils , only : getavu, relavu, opnfil + use shr_nl_mod , only : shr_nl_find_group_name + use spmdMod , only : masterproc, mpicom + use shr_mpi_mod , only : shr_mpi_bcast + ! + ! !ARGUMENTS: + character(len=*), intent(in) :: NLFilename ! Namelist filename + class(lnd2atm_type), intent(inout) :: this + ! + ! !LOCAL VARIABLES: + + ! temporary variables corresponding to the components of lnd2atm_params_type + logical :: melt_non_icesheet_ice_runoff + + integer :: ierr ! error code + integer :: unitn ! unit for namelist file + character(len=*), parameter :: nmlname = 'lnd2atm_inparm' + + character(len=*), parameter :: subname = 'ReadNamelist' + !----------------------------------------------------------------------- + + namelist /lnd2atm_inparm/ melt_non_icesheet_ice_runoff + + ! Initialize namelist variables to defaults + melt_non_icesheet_ice_runoff = .false. + + if (masterproc) then + unitn = getavu() + write(iulog,*) 'Read in '//nmlname//' namelist' + call opnfil (NLFilename, unitn, 'F') + call shr_nl_find_group_name(unitn, nmlname, status=ierr) + if (ierr == 0) then + read(unitn, nml=lnd2atm_inparm, iostat=ierr) + if (ierr /= 0) then + call endrun(msg="ERROR reading "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + else + call endrun(msg="ERROR could NOT find "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + call relavu( unitn ) + end if + + call shr_mpi_bcast(melt_non_icesheet_ice_runoff, mpicom) + + if (masterproc) then + write(iulog,*) + write(iulog,*) nmlname, ' settings:' + write(iulog,nml=lnd2atm_inparm) + write(iulog,*) ' ' + end if + + this%params = lnd2atm_params_type( & + melt_non_icesheet_ice_runoff = melt_non_icesheet_ice_runoff) + + end subroutine ReadNamelist + !----------------------------------------------------------------------- subroutine InitHistory(this, bounds) ! @@ -158,21 +267,30 @@ subroutine InitHistory(this, bounds) type(bounds_type), intent(in) :: bounds ! ! !LOCAL VARIABLES: + integer :: begc, endc integer :: begg, endg !--------------------------------------------------------------------- - begg = bounds%begg; endg= bounds%endg + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg this%eflx_sh_tot_grc(begg:endg) = 0._r8 call hist_addfld1d (fname='FSH_TO_COUPLER', units='W/m^2', & avgflag='A', & - long_name='sensible heat sent to coupler (includes corrections for land use change and rain/snow conversion)', & + long_name='sensible heat sent to coupler & + &(includes corrections for land use change, rain/snow conversion and conversion of ice runoff to liquid)', & ptr_lnd=this%eflx_sh_tot_grc) - + + this%eflx_sh_ice_to_liq_col(begc:endc) = 0._r8 + call hist_addfld1d (fname='FSH_RUNOFF_ICE_TO_LIQ', units='W/m^2', & + avgflag='A', & + long_name='sensible heat flux generated from conversion of ice runoff to liquid', & + ptr_col=this%eflx_sh_ice_to_liq_col) + this%qflx_rofliq_grc(begg:endg) = 0._r8 call hist_addfld1d (fname='QRUNOFF_TO_COUPLER', units='mm/s', & avgflag='A', & - long_name='total liquid runoff sent to coupler (does not include QSNWCPICE) (includes corrections for land use change)', & + long_name='total liquid runoff sent to coupler (includes corrections for land use change)', & ptr_lnd=this%qflx_rofliq_grc) this%qflx_rofice_grc(begg:endg) = 0._r8 @@ -181,6 +299,12 @@ subroutine InitHistory(this, bounds) long_name='total ice runoff sent to coupler (includes corrections for land use change)', & ptr_lnd=this%qflx_rofice_grc) + this%qflx_liq_from_ice_col(begc:endc) = 0._r8 + call hist_addfld1d (fname='QRUNOFF_ICE_TO_LIQ', units='mm/s', & + avgflag='A', & + long_name='liquid runoff from converted ice runoff', & + ptr_col=this%qflx_liq_from_ice_col, default='inactive') + this%net_carbon_exchange_grc(begg:endg) = spval call hist_addfld1d(fname='FCO2', units='kgCO2/m2/s', & avgflag='A', & diff --git a/src/main/lnd2glcMod.F90 b/src/main/lnd2glcMod.F90 index 02ffbe0458..9de7eba3f3 100644 --- a/src/main/lnd2glcMod.F90 +++ b/src/main/lnd2glcMod.F90 @@ -120,28 +120,26 @@ subroutine InitHistory(this, bounds) begg = bounds%begg; endg = bounds%endg - if (maxpatch_glcmec > 0) then - this%qice_grc(begg:endg,0:maxpatch_glcmec) = spval - ! For this and the following fields, set up a pointer to the field simply for the - ! sake of changing the indexing, so that levels start with an index of 1, as is - ! assumed by histFileMod - so levels go 1:(nec+1) rather than 0:nec - data2dptr => this%qice_grc(:,0:maxpatch_glcmec) - call hist_addfld2d (fname='QICE_FORC', units='mm/s', type2d='elevclas', & - avgflag='A', long_name='qice forcing sent to GLC', & - ptr_lnd=data2dptr, default='inactive') - - this%tsrf_grc(begg:endg,0:maxpatch_glcmec) = spval - data2dptr => this%tsrf_grc(:,0:maxpatch_glcmec) - call hist_addfld2d (fname='TSRF_FORC', units='K', type2d='elevclas', & - avgflag='A', long_name='surface temperature sent to GLC', & - ptr_lnd=data2dptr, default='inactive') - - this%topo_grc(begg:endg,0:maxpatch_glcmec) = spval - data2dptr => this%topo_grc(:,0:maxpatch_glcmec) - call hist_addfld2d (fname='TOPO_FORC', units='m', type2d='elevclas', & - avgflag='A', long_name='topograephic height sent to GLC', & - ptr_lnd=data2dptr, default='inactive') - end if + this%qice_grc(begg:endg,0:maxpatch_glcmec) = spval + ! For this and the following fields, set up a pointer to the field simply for the + ! sake of changing the indexing, so that levels start with an index of 1, as is + ! assumed by histFileMod - so levels go 1:(nec+1) rather than 0:nec + data2dptr => this%qice_grc(:,0:maxpatch_glcmec) + call hist_addfld2d (fname='QICE_FORC', units='mm/s', type2d='elevclas', & + avgflag='A', long_name='qice forcing sent to GLC', & + ptr_lnd=data2dptr, default='inactive') + + this%tsrf_grc(begg:endg,0:maxpatch_glcmec) = spval + data2dptr => this%tsrf_grc(:,0:maxpatch_glcmec) + call hist_addfld2d (fname='TSRF_FORC', units='K', type2d='elevclas', & + avgflag='A', long_name='surface temperature sent to GLC', & + ptr_lnd=data2dptr, default='inactive') + + this%topo_grc(begg:endg,0:maxpatch_glcmec) = spval + data2dptr => this%topo_grc(:,0:maxpatch_glcmec) + call hist_addfld2d (fname='TOPO_FORC', units='m', type2d='elevclas', & + avgflag='A', long_name='topograephic height sent to GLC', & + ptr_lnd=data2dptr, default='inactive') end subroutine InitHistory diff --git a/src/main/ncdio_pio.F90.in b/src/main/ncdio_pio.F90.in index 180a1b98c3..6ee65a7e6e 100644 --- a/src/main/ncdio_pio.F90.in +++ b/src/main/ncdio_pio.F90.in @@ -23,7 +23,7 @@ module ncdio_pio use decompMod , only : get_clmlevel_gsize,get_clmlevel_gsmap use perf_mod , only : t_startf, t_stopf use fileutils , only : getavu, relavu - use mct_mod , only : mct_gsMap, mct_gsMap_lsize, mct_gsMap_gsize, mct_gsMap_OP + use mct_mod , only : mct_gsMap, mct_gsMap_lsize, mct_gsMap_gsize, mct_gsMap_orderedPoints use pio , only : file_desc_t, io_desc_t, iosystem_desc_t, pio_64bit_offset use pio , only : pio_bcast_error, pio_char, pio_clobber, pio_closefile, pio_createfile, pio_def_dim use pio , only : pio_def_var, pio_double, pio_enddef, pio_get_att, pio_get_var, pio_global, pio_initdecomp @@ -1604,7 +1604,6 @@ contains deallocate( idata ) #else call pio_seterrorhandling(ncid, PIO_BCAST_ERROR) - write(iulog,*) 'read: ', trim(varname) call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, data, status) #endif if ( status /= PIO_NOERR ) then @@ -2347,7 +2346,7 @@ contains gsmap_lsize = mct_gsmap_lsize(gsmap,mpicom) gsmap_gsize = mct_gsmap_gsize(gsmap) - call mct_gsmap_OP(gsmap,iam,gsmOP) + call mct_gsMap_orderedPoints(gsmap,iam,gsmOP) fullsize = 1 do n = 1,ndims diff --git a/src/main/ndepStreamMod.F90 b/src/main/ndepStreamMod.F90 index 6035614981..e4acd648b8 100644 --- a/src/main/ndepStreamMod.F90 +++ b/src/main/ndepStreamMod.F90 @@ -7,7 +7,7 @@ module ndepStreamMod ! interpolation. ! ! !USES - use shr_kind_mod, only: r8 => shr_kind_r8, CL => shr_kind_cl + use shr_kind_mod, only: r8 => shr_kind_r8, CL => shr_kind_cl use shr_strdata_mod, only: shr_strdata_type, shr_strdata_create use shr_strdata_mod, only: shr_strdata_print, shr_strdata_advance use mct_mod , only: mct_ggrid @@ -28,11 +28,14 @@ module ndepStreamMod public :: ndep_interp ! interpolates between two years of ndep file data public :: clm_domain_mct ! Sets up MCT domain for this resolution + ! !PRIVATE MEMBER FUNCTIONS: + private :: check_units ! Check the units and make sure they can be used ! ! PRIVATE TYPES - type(shr_strdata_type) :: sdat ! input data stream - integer :: stream_year_first_ndep ! first year in stream to use - integer :: stream_year_last_ndep ! last year in stream to use - integer :: model_year_align_ndep ! align stream_year_firstndep with + type(shr_strdata_type) :: sdat ! input data stream + integer :: stream_year_first_ndep ! first year in stream to use + integer :: stream_year_last_ndep ! last year in stream to use + integer :: model_year_align_ndep ! align stream_year_firstndep with + logical :: divide_by_secs_per_yr = .true. ! divide by the number of seconds per year character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -47,6 +50,7 @@ subroutine ndep_init(bounds, NLFilename) ! Initialize data stream information. ! ! Uses: + use shr_kind_mod , only : CS => shr_kind_cs use clm_varctl , only : inst_name use clm_time_manager , only : get_calendar use ncdio_pio , only : pio_subsystem @@ -66,16 +70,19 @@ subroutine ndep_init(bounds, NLFilename) type(mct_ggrid) :: dom_clm ! domain information character(len=CL) :: stream_fldFileName_ndep character(len=CL) :: ndepmapalgo = 'bilinear' + character(len=CS) :: ndep_taxmode = 'extend' + character(len=CL) :: ndep_varlist = 'NDEP_year' character(*), parameter :: shr_strdata_unset = 'NOT_SET' character(*), parameter :: subName = "('ndepdyn_init')" character(*), parameter :: F00 = "('(ndepdyn_init) ',4a)" !----------------------------------------------------------------------- - namelist /ndepdyn_nml/ & - stream_year_first_ndep, & - stream_year_last_ndep, & - model_year_align_ndep, & - ndepmapalgo, & + namelist /ndepdyn_nml/ & + stream_year_first_ndep, & + stream_year_last_ndep, & + model_year_align_ndep, & + ndepmapalgo, ndep_taxmode, & + ndep_varlist, & stream_fldFileName_ndep ! Default values for namelist @@ -101,10 +108,12 @@ subroutine ndep_init(bounds, NLFilename) call relavu( nu_nml ) endif - call shr_mpi_bcast(stream_year_first_ndep, mpicom) - call shr_mpi_bcast(stream_year_last_ndep, mpicom) - call shr_mpi_bcast(model_year_align_ndep, mpicom) + call shr_mpi_bcast(stream_year_first_ndep , mpicom) + call shr_mpi_bcast(stream_year_last_ndep , mpicom) + call shr_mpi_bcast(model_year_align_ndep , mpicom) call shr_mpi_bcast(stream_fldFileName_ndep, mpicom) + call shr_mpi_bcast(ndep_varlist , mpicom) + call shr_mpi_bcast(ndep_taxmode , mpicom) if (masterproc) then write(iulog,*) ' ' @@ -113,9 +122,14 @@ subroutine ndep_init(bounds, NLFilename) write(iulog,*) ' stream_year_last_ndep = ',stream_year_last_ndep write(iulog,*) ' model_year_align_ndep = ',model_year_align_ndep write(iulog,*) ' stream_fldFileName_ndep = ',stream_fldFileName_ndep + write(iulog,*) ' ndep_varList = ',ndep_varList + write(iulog,*) ' ndep_taxmode = ',ndep_taxmode write(iulog,*) ' ' endif + ! Read in units + call check_units( stream_fldFileName_ndep, ndep_varList ) + ! Set domain and create streams call clm_domain_mct (bounds, dom_clm) call shr_strdata_create(sdat,name="clmndep", & @@ -137,19 +151,68 @@ subroutine ndep_init(bounds, NLFilename) domMaskName='mask', & filePath='', & filename=(/trim(stream_fldFileName_ndep)/),& - fldListFile='NDEP_year', & - fldListModel='NDEP_year', & + fldListFile=ndep_varlist, & + fldListModel=ndep_varlist, & fillalgo='none', & mapalgo=ndepmapalgo, & calendar=get_calendar(), & - taxmode='extend' ) + taxmode=ndep_taxmode ) + if (masterproc) then call shr_strdata_print(sdat,'CLMNDEP data') endif end subroutine ndep_init + !================================================================ + subroutine check_units( stream_fldFileName_ndep, ndep_varList ) + !------------------------------------------------------------------- + ! Check that units are correct on the file and if need any conversion + use ncdio_pio , only : ncd_pio_openfile, ncd_inqvid, ncd_getatt, ncd_pio_closefile, ncd_nowrite + use ncdio_pio , only : file_desc_t, var_desc_t + use shr_kind_mod , only : CS => shr_kind_cs + use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_string_mod, only : shr_string_listGetName + implicit none + + !----------------------------------------------------------------------- + ! + ! Arguments + character(len=*), intent(IN) :: stream_fldFileName_ndep ! ndep filename + character(len=*), intent(IN) :: ndep_varList ! ndep variable list to examine + ! + ! Local variables + type(file_desc_t) :: ncid ! NetCDF filehandle for ndep file + type(var_desc_t) :: vardesc ! variable descriptor + integer :: varid ! variable index + logical :: readvar ! If variable was read + character(len=CS) :: ndepunits! ndep units + character(len=CS) :: fname ! ndep field name + !----------------------------------------------------------------------- + call ncd_pio_openfile( ncid, trim(stream_fldFileName_ndep), ncd_nowrite ) + call shr_string_listGetName( ndep_varList, 1, fname ) + call ncd_inqvid( ncid, fname, varid, vardesc, readvar=readvar ) + if ( readvar ) then + call ncd_getatt( ncid, varid, "units", ndepunits ) + else + call endrun(msg=' ERROR finding variable: '//trim(fname)//" in file: "// & + trim(stream_fldFileName_ndep)//errMsg(sourcefile, __LINE__)) + end if + call ncd_pio_closefile( ncid ) + + ! Now check to make sure they are correct + if ( trim(ndepunits) == "g(N)/m2/s" )then + divide_by_secs_per_yr = .false. + else if ( trim(ndepunits) == "g(N)/m2/yr" )then + divide_by_secs_per_yr = .true. + else + call endrun(msg=' ERROR in units for nitrogen deposition equal to: '//trim(ndepunits)//" not units expected"// & + errMsg(sourcefile, __LINE__)) + end if + + end subroutine check_units + !================================================================ subroutine ndep_interp(bounds, atm2lnd_inst) @@ -177,12 +240,20 @@ subroutine ndep_interp(bounds, atm2lnd_inst) call shr_strdata_advance(sdat, mcdate, sec, mpicom, 'ndepdyn') - ig = 0 - dayspyr = get_days_per_year( ) - do g = bounds%begg,bounds%endg - ig = ig+1 - atm2lnd_inst%forc_ndep_grc(g) = sdat%avs(1)%rAttr(1,ig) / (secspday * dayspyr) - end do + if ( divide_by_secs_per_yr )then + ig = 0 + dayspyr = get_days_per_year( ) + do g = bounds%begg,bounds%endg + ig = ig+1 + atm2lnd_inst%forc_ndep_grc(g) = sdat%avs(1)%rAttr(1,ig) / (secspday * dayspyr) + end do + else + ig = 0 + do g = bounds%begg,bounds%endg + ig = ig+1 + atm2lnd_inst%forc_ndep_grc(g) = sdat%avs(1)%rAttr(1,ig) + end do + end if end subroutine ndep_interp diff --git a/src/main/paramUtilMod.F90 b/src/main/paramUtilMod.F90 index 75a85e3e6c..96c95440e7 100644 --- a/src/main/paramUtilMod.F90 +++ b/src/main/paramUtilMod.F90 @@ -11,14 +11,22 @@ module paramUtilMod module procedure readNcdioScalar module procedure readNcdioArray1d module procedure readNcdioArray2d + module procedure readNcdioScalarCheckDimensions + module procedure readNcdioArray1dCheckDimensions + module procedure readNcdioArray2dCheckDimensions end interface public :: readNcdioScalar public :: readNcdioArray1d public :: readNcdioArray2d + public :: readNcdioScalarCheckDimensions + public :: readNcdioArray1dCheckDimensions + public :: readNcdioArray2dCheckDimensions public :: readNcdio + private :: checkDimensions + contains !----------------------------------------------------------------------- ! @@ -128,4 +136,156 @@ subroutine readNcdioArray2d(ncid, varName, callingName, retVal) end subroutine readNcdioArray2d !----------------------------------------------------------------------- + !----------------------------------------------------------------------- + ! + !----------------------------------------------------------------------- + subroutine readNcdioScalarCheckDimensions(ncid, varName, expected_numDims, expected_dimNames, & + callingName, retVal) + ! + ! read the netcdf file...generic, could be used for any parameter read + ! + use abortutils , only : endrun + use ncdio_pio , only : file_desc_t + + implicit none + + ! arguments + type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id + character(len=*), intent(in) :: varName ! variable we are reading + integer, intent(in) :: expected_numDims + character(len=*), intent(in) :: expected_dimNames(:) ! expected dimension name + character(len=*), intent(in) :: callingName ! calling routine + real(r8), intent(inout) :: retVal + + ! local vars + character(len=32) :: subname = 'readNcdio::' + character(len=100) :: errCode = ' - Error reading. Var: ' + + ! + ! netcdf read here + ! + call checkDimensions(ncid, varName, expected_numDims, expected_dimNames, subname) + call readNcdio(ncid, varName, callingName, retVal) + + end subroutine readNcdioScalarCheckDimensions + !----------------------------------------------------------------------- + + !----------------------------------------------------------------------- + ! + !----------------------------------------------------------------------- + subroutine readNcdioArray1dCheckDimensions(ncid, varName, expected_numDims, expected_dimNames, & + callingName, retVal) + ! + ! read the netcdf file...generic, could be used for any parameter read + ! + use abortutils , only : endrun + use ncdio_pio , only : file_desc_t + + implicit none + + ! arguments + type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id + character(len=*), intent(in) :: varName ! variable we are reading + integer, intent(in) :: expected_numDims + character(len=*), intent(in) :: expected_dimNames(:) ! expected dimension name + character(len=*), intent(in) :: callingName ! calling routine + real(r8), intent(inout) :: retVal( 1: ) + + ! local vars + character(len=32) :: subname = 'readNcdio::' + character(len=100) :: errCode = ' - Error reading. Var: ' + ! + ! netcdf read here + ! + call checkDimensions(ncid, varName, expected_numDims, expected_dimNames, subname) + call readNcdio(ncid, varName, callingName, retVal) + + end subroutine readNcdioArray1dCheckDimensions + !----------------------------------------------------------------------- + + !----------------------------------------------------------------------- + ! + !----------------------------------------------------------------------- + subroutine readNcdioArray2dCheckDimensions(ncid, varName, expected_numDims, expected_dimNames, & + callingName, retVal) + ! + ! read the netcdf file...generic, could be used for any parameter read + ! + use abortutils , only : endrun + use ncdio_pio , only : file_desc_t + + implicit none + + ! arguments + type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id + character(len=*), intent(in) :: varName ! variable we are reading + integer, intent(in) :: expected_numDims + character(len=*), intent(in) :: expected_dimNames(:) ! expected dimension name + character(len=*), intent(in) :: callingName ! calling routine + real(r8), intent(inout) :: retVal(1:, : ) + + ! local vars + character(len=32) :: subname = 'readNcdio::' + character(len=100) :: errCode = ' - Error reading. Var: ' + ! + ! netcdf read here + ! + call checkDimensions(ncid, varName, expected_numDims, expected_dimNames, subname) + call readNcdio(ncid, varName, callingName, retVal) + + end subroutine readNcdioArray2dCheckDimensions + !----------------------------------------------------------------------- + + !----------------------------------------------------------------------- + ! + !----------------------------------------------------------------------- + subroutine checkDimensions(ncid, varName, expected_numDims, expected_dimNames, callingName) + ! + ! Assert that the expected number of dimensions and dimension + ! names for a variable match the actual names on the file. + ! + use abortutils , only : endrun + use ncdio_pio , only : file_desc_t, var_desc_t, check_var, ncd_inqvdname, ncd_inqvdims + + implicit none + + ! arguments + type(file_desc_t),intent(inout) :: ncid ! pio netCDF file id + character(len=*), intent(in) :: varName ! variable we are reading + integer, intent(in) :: expected_numDims ! number of expected dimensions on the variable + character(len=*), intent(in) :: expected_dimNames(:) ! expected dimension names + character(len=*), intent(in) :: callingName ! calling routine + integer :: error_num + + ! local vars + character(len=32) :: subname = 'checkDimensions::' + type(Var_desc_t) :: var_desc ! variable descriptor + logical :: readvar ! whether the variable was found + character(len=100) :: received_dimName + integer :: d, num_dims + character(len=256) :: msg + + call check_var(ncid, varName, var_desc, readvar) + if (readvar) then + call ncd_inqvdims(ncid, num_dims, var_desc) + if (num_dims /= expected_numDims) then + write(msg, *) trim(callingName)//trim(subname)//trim(varname)//":: expected number of dimensions = ", & + expected_numDims, " num dimensions received from file = ", num_dims + call endrun(msg) + end if + do d = 1, num_dims + received_dimName = '' + call ncd_inqvdname(ncid, varname=trim(varName), dimnum=d, dname=received_dimName, err_code=error_num) + if (trim(expected_dimNames(d)) /= trim(received_dimName)) then + write(msg, *) trim(callingName)//trim(subname)//trim(varname)//":: dimension ", d, & + " expected dimension name '"//trim(expected_dimNames(d))//& + "' dimension name received from file '"//trim(received_dimName)//"'." + call endrun(msg) + end if + end do + end if + + end subroutine checkDimensions + !----------------------------------------------------------------------- + end module paramUtilMod diff --git a/src/main/pftconMod.F90 b/src/main/pftconMod.F90 index db2e358480..0efa2053eb 100644 --- a/src/main/pftconMod.F90 +++ b/src/main/pftconMod.F90 @@ -176,6 +176,8 @@ module pftconMod real(r8), allocatable :: grnfill (:) ! parameter used in CNPhenology integer , allocatable :: mxmat (:) ! parameter used in CNPhenology real(r8), allocatable :: mbbopt (:) ! Ball-Berry equation slope used in Photosynthesis + real(r8), allocatable :: medlynslope (:) ! Medlyn equation slope used in Photosynthesis + real(r8), allocatable :: medlynintercept(:) ! Medlyn equation intercept used in Photosynthesis integer , allocatable :: mnNHplantdate (:) ! minimum planting date for NorthHemisphere (YYYYMMDD) integer , allocatable :: mxNHplantdate (:) ! maximum planting date for NorthHemisphere (YYYYMMDD) integer , allocatable :: mnSHplantdate (:) ! minimum planting date for SouthHemisphere (YYYYMMDD) @@ -382,6 +384,8 @@ subroutine InitAllocate (this) allocate( this%lfemerg (0:mxpft) ) allocate( this%grnfill (0:mxpft) ) allocate( this%mbbopt (0:mxpft) ) + allocate( this%medlynslope (0:mxpft) ) + allocate( this%medlynintercept(0:mxpft) ) allocate( this%mxmat (0:mxpft) ) allocate( this%mnNHplantdate (0:mxpft) ) allocate( this%mxNHplantdate (0:mxpft) ) @@ -470,9 +474,9 @@ subroutine InitRead(this) use fileutils , only : getfil use ncdio_pio , only : ncd_io, ncd_pio_closefile, ncd_pio_openfile, file_desc_t use ncdio_pio , only : ncd_inqdid, ncd_inqdlen - use clm_varctl , only : paramfile, use_ed, use_flexibleCN, use_dynroot + use clm_varctl , only : paramfile, use_fates, use_flexibleCN, use_dynroot use spmdMod , only : masterproc - use EDPftvarcon , only : EDpftconrd + use CLMFatesParamInterfaceMod, only : FatesReadPFTs ! ! !ARGUMENTS: class(pftcon_type) :: this @@ -799,7 +803,7 @@ subroutine InitRead(this) if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) call ncd_io('manunitro', this%manunitro, 'read', ncid, readvar=readv, posNOTonfile=.true.) - if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(__FILE__, __LINE__)) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) call ncd_io('fleafcn', this%fleafcn, 'read', ncid, readvar=readv, posNOTonfile=.true.) if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) @@ -893,6 +897,12 @@ subroutine InitRead(this) call ncd_io('mbbopt', this%mbbopt, 'read', ncid, readvar=readv) if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + call ncd_io('medlynslope', this%medlynslope, 'read', ncid, readvar=readv) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + + call ncd_io('medlynintercept', this%medlynintercept, 'read', ncid, readvar=readv) + if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) + call ncd_io('mxmat', this%mxmat, 'read', ncid, readvar=readv) if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) @@ -985,13 +995,6 @@ subroutine InitRead(this) if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__)) end if - ! - ! ED variables - ! - if ( use_ed ) then - ! The following sets the module variable EDpftcon_inst in EDPftcon - call EDpftconrd ( ncid ) - endif ! ! Dynamic Root variables for crops ! @@ -1002,8 +1005,10 @@ subroutine InitRead(this) call ncd_pio_closefile(ncid) + call FatesReadPFTs() + do i = 0, mxpft - if (.not. use_ed)then + if (.not. use_fates)then if ( trim(adjustl(pftname(i))) /= trim(expected_pftnames(i)) )then write(iulog,*)'pftconrd: pftname is NOT what is expected, name = ', & trim(pftname(i)), ', expected name = ', trim(expected_pftnames(i)) @@ -1103,11 +1108,11 @@ subroutine InitRead(this) this%fcur(:) = this%fcurdv(:) end if ! - ! Do some error checking, but not if ED is on. + ! Do some error checking, but not if fates is on. ! ! FIX(SPM,032414) double check if some of these should be on... - if( .not. use_ed ) then + if( .not. use_fates ) then if ( npcropmax /= mxpft )then call endrun(msg=' ERROR: npcropmax is NOT the last value'//errMsg(sourcefile, __LINE__)) end if @@ -1294,6 +1299,8 @@ subroutine Clean(this) deallocate( this%lfemerg) deallocate( this%grnfill) deallocate( this%mbbopt) + deallocate( this%medlynslope) + deallocate( this%medlynintercept) deallocate( this%mxmat) deallocate( this%mnNHplantdate) deallocate( this%mxNHplantdate) @@ -1370,6 +1377,5 @@ subroutine Clean(this) end subroutine Clean - end module pftconMod diff --git a/src/main/readParamsMod.F90 b/src/main/readParamsMod.F90 index 5f16421700..f5776c2605 100644 --- a/src/main/readParamsMod.F90 +++ b/src/main/readParamsMod.F90 @@ -7,7 +7,7 @@ module readParamsMod ! well defined functionality (eg. ED). ! ! ! USES: - use clm_varctl , only : paramfile, iulog, use_ed, use_cn + use clm_varctl , only : paramfile, iulog, use_fates, use_cn use spmdMod , only : masterproc use fileutils , only : getfil use ncdio_pio , only : ncd_pio_closefile, ncd_pio_openfile @@ -17,6 +17,7 @@ module readParamsMod private ! public :: readParameters + !----------------------------------------------------------------------- contains @@ -25,9 +26,6 @@ module readParamsMod subroutine readParameters (nutrient_competition_method, photosyns_inst) ! ! ! USES: - use EDSharedParamsMod , only : EDParamsReadShared - use EDParamsMod , only : EDParamsRead - use SFParamsMod , only : SFParamsRead use CNSharedParamsMod , only : CNParamsReadShared use CNGapMortalityMod , only : readCNGapMortParams => readParams use CNMRespMod , only : readCNMRespParams => readParams @@ -45,6 +43,8 @@ subroutine readParameters (nutrient_competition_method, photosyns_inst) use NutrientCompetitionMethodMod , only : nutrient_competition_method_type use clm_varctl, only : NLFilename_in use PhotosynthesisMod , only : photosyns_type + + use CLMFatesParamInterfaceMod , only : FatesReadParameters ! ! !ARGUMENTS: type(photosyns_type) , intent(in) :: photosyns_inst @@ -67,15 +67,6 @@ subroutine readParameters (nutrient_competition_method, photosyns_inst) call ncd_inqdid(ncid,'pft',dimid) call ncd_inqdlen(ncid,dimid,npft) - ! - ! Ecosystem Dynamics model - ! - if (use_ed) then - call EDParamsReadShared(ncid) - call EDParamsRead(ncid) - call SFParamsRead(ncid) - end if - ! ! Above ground biogeochemistry... ! @@ -90,7 +81,7 @@ subroutine readParameters (nutrient_competition_method, photosyns_inst) ! ! Soil biogeochemistry... ! - if (use_cn .or. use_ed) then + if (use_cn .or. use_fates) then call readSoilBiogeochemCompetitionParams(ncid) call readSoilBiogeochemDecompBgcParams(ncid) call readSoilBiogeochemDecompCnParams(ncid) @@ -113,6 +104,8 @@ subroutine readParameters (nutrient_competition_method, photosyns_inst) ! call ncd_pio_closefile(ncid) + call FatesReadParameters() + end subroutine readParameters end module readParamsMod diff --git a/src/main/restFileMod.F90 b/src/main/restFileMod.F90 index c16d20b3bc..9f6510dfa6 100644 --- a/src/main/restFileMod.F90 +++ b/src/main/restFileMod.F90 @@ -17,7 +17,7 @@ module restFileMod use accumulMod , only : accumulRest use clm_instMod , only : clm_instRest use histFileMod , only : hist_restart_ncd - use clm_varctl , only : create_glacier_mec_landunit, iulog, use_ed, use_hydrstress + use clm_varctl , only : iulog, use_fates, use_hydrstress use clm_varctl , only : create_crop_landunit, irrigate use clm_varcon , only : nameg, namel, namec, namep, nameCohort use ncdio_pio , only : file_desc_t, ncd_pio_createfile, ncd_pio_openfile, ncd_global @@ -528,9 +528,7 @@ subroutine restFile_dimset( ncid ) call ncd_defdim(ncid , 'vegwcs' , nvegwcs , dimid) end if call ncd_defdim(ncid , 'string_length', 64 , dimid) - if (create_glacier_mec_landunit) then - call ncd_defdim(ncid , 'glc_nec', maxpatch_glcmec, dimid) - end if + call ncd_defdim(ncid , 'glc_nec', maxpatch_glcmec, dimid) ! Define global attributes @@ -552,7 +550,12 @@ subroutine restFile_dimset( ncid ) call restFile_add_flag_metadata(ncid, create_crop_landunit, 'create_crop_landunit') call restFile_add_flag_metadata(ncid, irrigate, 'irrigate') - call restFile_add_flag_metadata(ncid, create_glacier_mec_landunit, 'created_glacier_mec_landunits') + ! BACKWARDS_COMPATIBILITY(wjs, 2017-12-13) created_glacier_mec_landunits is always + ! true now. However, we can't remove the read of this field from init_interp until we + ! can reliably assume that all initial conditions files that might be used in + ! init_interp have this flag .true. So until then, we write the flag with a + ! hard-coded .true. value. + call restFile_add_flag_metadata(ncid, .true., 'created_glacier_mec_landunits') call restFile_add_ipft_metadata(ncid) call restFile_add_icol_metadata(ncid) @@ -708,7 +711,7 @@ subroutine restFile_dimcheck( ncid ) call check_dim(ncid, namel, numl, msg=msg) call check_dim(ncid, namec, numc, msg=msg) call check_dim(ncid, namep, nump, msg=msg) - if ( use_ed ) call check_dim(ncid, nameCohort , numCohort, msg=msg) + if ( use_fates ) call check_dim(ncid, nameCohort , numCohort, msg=msg) end if call check_dim(ncid, 'levsno' , nlevsno, & msg = 'You can deal with this mismatch by rerunning with ' // & diff --git a/src/main/subgridAveMod.F90 b/src/main/subgridAveMod.F90 index 799d492639..3375add2e8 100644 --- a/src/main/subgridAveMod.F90 +++ b/src/main/subgridAveMod.F90 @@ -61,7 +61,21 @@ module subgridAveMod ! !PRIVATE MEMBER FUNCTIONS: private :: build_scale_l2g private :: create_scale_l2g_lookup - + + ! Note about the urban scaling types used for c2l_scale_type (urbanf / urbans), from + ! Bill Sacks and Keith Oleson: These names originally meant to distinguish between + ! fluxes and states. However, that isn't the right distinction. In general, urbanf + ! should be used for variables that are expressed as something-per-m^2 ('extensive' + ! state or flux variables), whereas urbans should be used for variables that are not + ! expressed as per-m^2 ('intensive' state variables; an example is temperature). The + ! urbanf scaling converts from per-m^2 of vertical wall area to per-m^2 of ground area. + ! One way to think about this is: In the extreme case of a near-infinite canyon_hwr due + ! to massively tall walls, do you want a near-infinite multiplier for the walls for the + ! variable in question? If so, you want urbanf; if not, you want urbans. + ! + ! However, there may be some special cases, including some hydrology variables that + ! don't apply for urban walls. + ! WJS (10-14-11): TODO: ! ! - I believe that scale_p2c, scale_c2l and scale_l2g should be included in the sumwt @@ -114,7 +128,7 @@ subroutine p2c_1d (bounds, parr, carr, p2c_scale_type) scale_p2c(p) = 1.0_r8 end do else - write(iulog,*)'p2c_2d error: scale type ',p2c_scale_type,' not supported' + write(iulog,*)'p2c_1d error: scale type ',p2c_scale_type,' not supported' call endrun(msg=errMsg(sourcefile, __LINE__)) end if @@ -281,13 +295,13 @@ subroutine p2l_1d (bounds, parr, larr, p2c_scale_type, c2l_scale_type) real(r8), intent(in) :: parr( bounds%begp: ) ! input column array real(r8), intent(out) :: larr( bounds%begl: ) ! output landunit array character(len=*), intent(in) :: p2c_scale_type ! scale factor type for averaging - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) ! ! !LOCAL VARIABLES: integer :: p,c,l,index ! indices logical :: found ! temporary for error check real(r8) :: sumwt(bounds%begl:bounds%endl) ! sum of weights - real(r8) :: scale_p2c(bounds%begc:bounds%endc) ! scale factor for patch->column mapping + real(r8) :: scale_p2c(bounds%begp:bounds%endp) ! scale factor for patch->column mapping real(r8) :: scale_c2l(bounds%begc:bounds%endc) ! scale factor for column->landunit mapping !------------------------------------------------------------------------ @@ -389,7 +403,7 @@ subroutine p2l_2d(bounds, num2d, parr, larr, p2c_scale_type, c2l_scale_type) real(r8), intent(in) :: parr( bounds%begp: , 1: ) ! input patch array real(r8), intent(out) :: larr( bounds%begl: , 1: ) ! output gridcell array character(len=*), intent(in) :: p2c_scale_type ! scale factor type for averaging - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) ! ! !LOCAL VARIABLES: integer :: j,p,c,l,index ! indices @@ -498,7 +512,7 @@ subroutine p2g_1d(bounds, parr, garr, p2c_scale_type, c2l_scale_type, l2g_scale_ real(r8), intent(in) :: parr( bounds%begp: ) ! input patch array real(r8), intent(out) :: garr( bounds%begg: ) ! output gridcell array character(len=*), intent(in) :: p2c_scale_type ! scale factor type for averaging - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging ! ! !LOCAL VARIABLES: @@ -614,7 +628,7 @@ subroutine p2g_2d(bounds, num2d, parr, garr, p2c_scale_type, c2l_scale_type, l2g real(r8), intent(in) :: parr( bounds%begp: , 1: ) ! input patch array real(r8), intent(out) :: garr( bounds%begg: , 1: ) ! output gridcell array character(len=*), intent(in) :: p2c_scale_type ! scale factor type for averaging - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging ! ! !LOCAL VARIABLES: @@ -728,7 +742,7 @@ subroutine c2l_1d (bounds, carr, larr, c2l_scale_type) type(bounds_type), intent(in) :: bounds real(r8), intent(in) :: carr( bounds%begc: ) ! input column array real(r8), intent(out) :: larr( bounds%begl: ) ! output landunit array - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) ! ! !LOCAL VARIABLES: integer :: c,l,index ! indices @@ -824,7 +838,7 @@ subroutine c2l_2d (bounds, num2d, carr, larr, c2l_scale_type) integer , intent(in) :: num2d ! size of second dimension real(r8), intent(in) :: carr( bounds%begc: , 1: ) ! input column array real(r8), intent(out) :: larr( bounds%begl: , 1: ) ! output landunit array - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) ! ! !LOCAL VARIABLES: integer :: j,l,c,index ! indices @@ -921,7 +935,7 @@ subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type) type(bounds_type), intent(in) :: bounds real(r8), intent(in) :: carr( bounds%begc: ) ! input column array real(r8), intent(out) :: garr( bounds%begg: ) ! output gridcell array - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging ! ! !LOCAL VARIABLES: @@ -1023,7 +1037,7 @@ subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type) integer , intent(in) :: num2d ! size of second dimension real(r8), intent(in) :: carr( bounds%begc: , 1: ) ! input column array real(r8), intent(out) :: garr( bounds%begg: , 1: ) ! output gridcell array - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging ! ! !LOCAL VARIABLES: @@ -1251,6 +1265,11 @@ subroutine build_scale_l2g(bounds, l2g_scale_type, scale_l2g) SHR_ASSERT_ALL((ubound(scale_l2g) == (/bounds%endl/)), errMsg(sourcefile, __LINE__)) + ! TODO(wjs, 2017-03-09) If this routine is a performance problem (which it may be, + ! because I think it's called a lot), then a simple optimization would be to treat + ! l2g_scale_type = 'unity' specially, rather than using the more general-purpose code + ! for this special case. + call create_scale_l2g_lookup(l2g_scale_type, scale_lookup) do l = bounds%begl,bounds%endl @@ -1267,7 +1286,7 @@ subroutine create_scale_l2g_lookup(l2g_scale_type, scale_lookup) ! each landunit type depending on l2g_scale_type ! ! !USES: - use landunit_varcon, only : istsoil, istcrop, istice, istice_mec, istdlak + use landunit_varcon, only : istsoil, istcrop, istice_mec, istdlak use landunit_varcon, only : isturb_MIN, isturb_MAX, max_lunit ! ! !ARGUMENTS: @@ -1308,7 +1327,6 @@ subroutine create_scale_l2g_lookup(l2g_scale_type, scale_lookup) scale_lookup(istsoil) = 1.0_r8 scale_lookup(istcrop) = 1.0_r8 else if (l2g_scale_type == 'ice') then - scale_lookup(istice) = 1.0_r8 scale_lookup(istice_mec) = 1.0_r8 else if (l2g_scale_type == 'nonurb') then scale_lookup(:) = 1.0_r8 diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 1e1b1f964a..f2af26c242 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -17,7 +17,7 @@ module subgridMod use clm_varctl , only : iulog use clm_instur , only : wt_lunit, urban_valid, wt_cft use glcBehaviorMod , only : glc_behavior_type - use EDtypesMod, only : cohorts_per_col + use FatesInterfaceMod, only : fates_maxElementsPerSite implicit none private @@ -33,7 +33,6 @@ module subgridMod public :: subgrid_get_info_urban_md public :: subgrid_get_info_lake public :: subgrid_get_info_wetland - public :: subgrid_get_info_glacier public :: subgrid_get_info_glacier_mec public :: subgrid_get_info_crop public :: crop_patch_exists ! returns true if the given crop patch should be created in memory @@ -101,9 +100,6 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & call subgrid_get_info_wetland(gi, npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() - call subgrid_get_info_glacier(gi, npatches_temp, ncols_temp, nlunits_temp) - call accumulate_counters() - call subgrid_get_info_glacier_mec(gi, atm_topo, glc_behavior, & npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() @@ -170,13 +166,13 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) ! ------------------------------------------------------------------------- ! Number of cohorts is set here - ! ED cohorts (via FATES) populate all natural vegetation columns. + ! fates cohorts (via FATES) populate all natural vegetation columns. ! Current implementations mostly assume that only one column contains ! natural vegetation, which is synonomous with the soil column. ! For restart output however, we will allocate the cohort vector space ! based on all columns. ! ------------------------------------------------------------------------- - ncohorts = ncols*cohorts_per_col + ncohorts = ncols*fates_maxElementsPerSite end subroutine subgrid_get_info_natveg @@ -353,43 +349,6 @@ subroutine subgrid_get_info_wetland(gi, npatches, ncols, nlunits) end subroutine subgrid_get_info_wetland !----------------------------------------------------------------------- - subroutine subgrid_get_info_glacier(gi, npatches, ncols, nlunits) - ! - ! !DESCRIPTION: - ! Obtain properties for glacier landunit in this grid cell - ! - ! !USES: - use landunit_varcon, only : istice - ! - ! !ARGUMENTS: - integer, intent(in) :: gi ! grid cell index - integer, intent(out) :: npatches ! number of glacier patches in this grid cell - integer, intent(out) :: ncols ! number of glacier columns in this grid cell - integer, intent(out) :: nlunits ! number of glacier landunits in this grid cell - ! - ! !LOCAL VARIABLES: - - character(len=*), parameter :: subname = 'subgrid_get_info_glacier' - !----------------------------------------------------------------------- - - ! We currently do NOT allow the glacier landunit to expand via dynamic landunits, so - ! we only need to allocate space for it where its weight is currently non-zero. (If we - ! have dynamic glacier area, we will be using glacier_mec landunits rather than - ! glacier landunits.) - - if (wt_lunit(gi, istice) > 0.0_r8) then - npatches = 1 - ncols = 1 - nlunits = 1 - else - npatches = 0 - ncols = 0 - nlunits = 0 - end if - - end subroutine subgrid_get_info_glacier - - !----------------------------------------------------------------------- subroutine subgrid_get_info_glacier_mec(gi, atm_topo, glc_behavior, npatches, ncols, nlunits) ! ! !DESCRIPTION: diff --git a/src/main/subgridRestMod.F90 b/src/main/subgridRestMod.F90 index 625fead397..7dd82dfda5 100644 --- a/src/main/subgridRestMod.F90 +++ b/src/main/subgridRestMod.F90 @@ -595,7 +595,7 @@ logical function do_check_weights() ! Return true if we should check weights ! ! !USES: - use clm_varctl, only : nsrest, nsrContinue, use_cndv, use_ed + use clm_varctl, only : nsrest, nsrContinue, use_cndv, use_fates use dynSubgridControlMod, only : get_do_transient_pfts ! ! !ARGUMENTS: @@ -620,8 +620,8 @@ logical function do_check_weights() ! Don't check weights for a cndv case, because the weights will almost certainly ! differ from the surface dataset in this case do_check_weights = .false. - else if (use_ed) then - ! Don't check weights for a ed case, because the weights will almost certainly + else if (use_fates) then + ! Don't check weights for a fates case, because the weights will almost certainly ! differ from the surface dataset in this case do_check_weights = .false. else diff --git a/src/main/subgridWeightsMod.F90 b/src/main/subgridWeightsMod.F90 index 149173fa2a..89717b1f0d 100644 --- a/src/main/subgridWeightsMod.F90 +++ b/src/main/subgridWeightsMod.F90 @@ -92,7 +92,7 @@ module subgridWeightsMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun - use clm_varctl , only : iulog, all_active, use_ed + use clm_varctl , only : iulog, all_active, use_fates use clm_varcon , only : nameg, namel, namec, namep use decompMod , only : bounds_type use GridcellType , only : grc @@ -194,22 +194,21 @@ subroutine init_subgrid_weights_mod(bounds) avgflag='A', long_name='% of each landunit on grid cell', & ptr_lnd=subgrid_weights_diagnostics%pct_landunit) - call hist_addfld2d (fname='PCT_NAT_PFT', units='%', type2d='natpft', & - avgflag='A', long_name='% of each PFT on the natural vegetation (i.e., soil) landunit', & - ptr_lnd=subgrid_weights_diagnostics%pct_nat_pft) - + if(.not.use_fates) then + call hist_addfld2d (fname='PCT_NAT_PFT', units='%', type2d='natpft', & + avgflag='A', long_name='% of each PFT on the natural vegetation (i.e., soil) landunit', & + ptr_lnd=subgrid_weights_diagnostics%pct_nat_pft) + end if + if (cft_size > 0) then call hist_addfld2d (fname='PCT_CFT', units='%', type2d='cft', & avgflag='A', long_name='% of each crop on the crop landunit', & ptr_lnd=subgrid_weights_diagnostics%pct_cft) end if - if (maxpatch_glcmec > 0) then - call hist_addfld2d (fname='PCT_GLC_MEC', units='%', type2d='glc_nec', & - avgflag='A', long_name='% of each GLC elevation class on the glc_mec landunit', & - ptr_lnd=subgrid_weights_diagnostics%pct_glc_mec) - end if - + call hist_addfld2d (fname='PCT_GLC_MEC', units='%', type2d='glc_nec', & + avgflag='A', long_name='% of each GLC elevation class on the glc_mec landunit', & + ptr_lnd=subgrid_weights_diagnostics%pct_glc_mec) end subroutine init_subgrid_weights_mod @@ -302,7 +301,7 @@ logical function is_active_l(l, glc_behavior) ! Determine whether the given landunit is active ! ! !USES: - use landunit_varcon, only : istsoil, istice, istice_mec + use landunit_varcon, only : istsoil, istice_mec ! ! !ARGUMENTS: implicit none @@ -354,21 +353,7 @@ logical function is_active_l(l, glc_behavior) ! would remain at its cold start initialization values, which would be a Bad ! Thing. Ensuring that all vegetated points within the icemask are active gets ! around this problem - as well as having other benefits, as noted above.) - ! - ! However, we do NOT include a virtual vegetated column in grid cells that are 100% - ! standard (non-mec) glacier. This is for performance reasons: for FV 0.9x1.25, - ! excluding these virtual vegetated columns (mostly over Antarctica) leads to a ~ - ! 6% performance improvement (the performance improvement is much less for ne30, - ! though). In such grid cells, we do not need the forcing to CISM (because if we - ! needed forcing to CISM, we'd be using an istice_mec point rather than plain - ! istice). Furthermore, standard glacier landunits cannot retreat (only istice_mec - ! points can retreat, due to coupling with CISM), so we don't need to worry about - ! the glacier retreating in this grid cell, exposing new natural veg area. The - ! only thing that could happen is the growth of some special landunit - e.g., crop - ! - in this grid cell, due to dynamic landunits. We'll live with the fact that - ! initialization of the new crop landunit will be initialized in an un-ideal way - ! in this rare situation. - if (lun%itype(l) == istsoil .and. .not. is_gcell_all_ltypeX(g, istice)) then + if (lun%itype(l) == istsoil) then is_active_l = .true. end if @@ -748,14 +733,13 @@ subroutine set_subgrid_diagnostic_fields(bounds) call set_pct_landunit_diagnostics(bounds) - ! Note: (MV, 10-17-14): The following has an use_ed if-block around it since + ! Note: (MV, 10-17-14): The following has an use_fates if-block around it since ! the pct_pft_diagnostics referens to patch%itype(p) which is not used by ED ! Note: (SPM, 10-20-15): If this isn't set then debug mode with intel and ! yellowstone will fail when trying to write pct_nat_pft since it contains ! all NaN's. - call set_pct_pft_diagnostics(bounds) - + call set_pct_glc_mec_diagnostics(bounds) end subroutine set_subgrid_diagnostic_fields @@ -804,7 +788,6 @@ subroutine set_pct_glc_mec_diagnostics(bounds) ! !USES: use landunit_varcon, only : istice_mec use column_varcon, only : col_itype_to_icemec_class - use clm_varpar, only : maxpatch_glcmec ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -816,18 +799,16 @@ subroutine set_pct_glc_mec_diagnostics(bounds) character(len=*), parameter :: subname = 'set_pct_glc_mec_diagnostics' !----------------------------------------------------------------------- - if (maxpatch_glcmec > 0) then - subgrid_weights_diagnostics%pct_glc_mec(bounds%begg:bounds%endg, :) = 0._r8 - - do c = bounds%begc, bounds%endc - g = col%gridcell(c) - l = col%landunit(c) - if (lun%itype(l) == istice_mec) then - icemec_class = col_itype_to_icemec_class(col%itype(c)) - subgrid_weights_diagnostics%pct_glc_mec(g, icemec_class) = col%wtlunit(c) * 100._r8 - end if - end do - end if + subgrid_weights_diagnostics%pct_glc_mec(bounds%begg:bounds%endg, :) = 0._r8 + + do c = bounds%begc, bounds%endc + g = col%gridcell(c) + l = col%landunit(c) + if (lun%itype(l) == istice_mec) then + icemec_class = col_itype_to_icemec_class(col%itype(c)) + subgrid_weights_diagnostics%pct_glc_mec(g, icemec_class) = col%wtlunit(c) * 100._r8 + end if + end do end subroutine set_pct_glc_mec_diagnostics @@ -864,7 +845,7 @@ subroutine set_pct_pft_diagnostics(bounds) g = patch%gridcell(p) l = patch%landunit(p) ptype = patch%itype(p) - if (lun%itype(l) == istsoil) then + if (lun%itype(l) == istsoil .and. (.not.use_fates) ) then ptype_1indexing = ptype + (1 - natpft_lb) subgrid_weights_diagnostics%pct_nat_pft(g, ptype_1indexing) = patch%wtlunit(p) * 100._r8 else if (lun%itype(l) == istcrop) then diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 66c7629af4..0743c78cd2 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -6,6 +6,7 @@ module surfrdMod ! subgrid weights ! ! !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 @@ -13,7 +14,7 @@ module surfrdMod use landunit_varcon , only : numurbl use clm_varcon , only : grlnd use clm_varctl , only : iulog, scmlat, scmlon, single_column - use clm_varctl , only : create_glacier_mec_landunit, use_cndv, use_crop + use clm_varctl , only : use_cndv, use_crop use surfrdUtilsMod , only : check_sums_equal_1, collapse_crop_types use ncdio_pio , only : file_desc_t, var_desc_t, ncd_pio_openfile, ncd_pio_closefile use ncdio_pio , only : ncd_io, check_var, ncd_inqfdims, check_dim, ncd_inqdid @@ -30,9 +31,11 @@ module surfrdMod public :: surfrd_get_data ! Read surface dataset and determine subgrid weights ! ! !PRIVATE MEMBER FUNCTIONS: - private :: surfrd_special - private :: surfrd_veg_all - private :: surfrd_veg_dgvm + private :: surfrd_special ! Read the special landunits + private :: surfrd_veg_all ! Read all of the vegetated landunits + private :: surfrd_veg_dgvm ! Read vegetated landunits for DGVM mode + private :: surfrd_pftformat ! Read crop pfts in file format where they are part of the vegetated land unit + private :: surfrd_cftformat ! Read crop pfts in file format where they are on their own landunit ! ! !PRIVATE DATA MEMBERS: ! default multiplication factor for epsilon for error checks @@ -335,6 +338,7 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat) endif endif + wt_lunit(:,:) = 0._r8 topo_glc_mec(:,:) = 0._r8 ! Read surface data @@ -443,7 +447,7 @@ subroutine surfrd_special(begg, endg, ncid, ns) ! ! !USES: use clm_varpar , only : maxpatch_glcmec, nlevurb - use landunit_varcon , only : isturb_MIN, isturb_MAX, istdlak, istwet, istice, istice_mec + use landunit_varcon , only : isturb_MIN, isturb_MAX, istdlak, istwet, istice_mec use clm_instur , only : wt_lunit, urban_valid, wt_glc_mec, topo_glc_mec use UrbanParamsType , only : CheckUrban ! @@ -465,7 +469,6 @@ subroutine surfrd_special(begg, endg, ncid, ns) real(r8),pointer :: pctwet(:) ! percent of grid cell is wetland real(r8),pointer :: pcturb(:,:) ! percent of grid cell is urbanized integer ,pointer :: urban_region_id(:) - real(r8),pointer :: pctglc_mec_tot(:) ! percent of grid cell is glacier (sum over classes) real(r8),pointer :: pcturb_tot(:) ! percent of grid cell is urban (sum over density classes) real(r8),pointer :: pctspec(:) ! percent of spec lunits wrt gcell integer :: dens_index ! urban density index @@ -480,7 +483,6 @@ subroutine surfrd_special(begg, endg, ncid, ns) allocate(pcturb(begg:endg,numurbl)) allocate(pcturb_tot(begg:endg)) allocate(urban_region_id(begg:endg)) - allocate(pctglc_mec_tot(begg:endg)) allocate(pctspec(begg:endg)) call check_dim(ncid, 'nlevsoi', nlevsoifl) @@ -532,37 +534,25 @@ subroutine surfrd_special(begg, endg, ncid, ns) enddo enddo - if (create_glacier_mec_landunit) then ! call ncd_io_gs_int2d + ! Read glacier info - call check_dim(ncid, 'nglcec', maxpatch_glcmec ) - call check_dim(ncid, 'nglcecp1', maxpatch_glcmec+1 ) - - call ncd_io(ncid=ncid, varname='PCT_GLC_MEC', flag='read', data=wt_glc_mec, & - dim1name=grlnd, readvar=readvar) - if (.not. readvar) call endrun( msg=' ERROR: PCT_GLC_MEC NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - - wt_glc_mec(:,:) = wt_glc_mec(:,:) / 100._r8 - call check_sums_equal_1(wt_glc_mec, begg, 'wt_glc_mec', subname) - - call ncd_io(ncid=ncid, varname='TOPO_GLC_MEC', flag='read', data=topo_glc_mec, & - dim1name=grlnd, readvar=readvar) - if (.not. readvar) call endrun( msg=' ERROR: TOPO_GLC_MEC NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - - topo_glc_mec(:,:) = max(topo_glc_mec(:,:), 0._r8) + call check_dim(ncid, 'nglcec', maxpatch_glcmec ) + call check_dim(ncid, 'nglcecp1', maxpatch_glcmec+1 ) + call ncd_io(ncid=ncid, varname='PCT_GLC_MEC', flag='read', data=wt_glc_mec, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( msg=' ERROR: PCT_GLC_MEC NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - ! Put glacier area into the GLC_MEC landunit rather than the simple glacier landunit - pctglc_mec_tot(:) = pctgla(:) - pctgla(:) = 0._r8 + wt_glc_mec(:,:) = wt_glc_mec(:,:) / 100._r8 + call check_sums_equal_1(wt_glc_mec, begg, 'wt_glc_mec', subname) - pctspec = pctwet + pctlak + pcturb_tot + pctglc_mec_tot + call ncd_io(ncid=ncid, varname='TOPO_GLC_MEC', flag='read', data=topo_glc_mec, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( msg=' ERROR: TOPO_GLC_MEC NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - else + topo_glc_mec(:,:) = max(topo_glc_mec(:,:), 0._r8) - pctglc_mec_tot(:) = 0._r8 - pctspec = pctwet + pctlak + pcturb_tot + pctgla - - endif + pctspec = pctwet + pctlak + pcturb_tot + pctgla ! Error check: glacier, lake, wetland, urban sum must be less than 100 @@ -588,9 +578,7 @@ subroutine surfrd_special(begg, endg, ncid, ns) wt_lunit(nl,istwet) = pctwet(nl)/100._r8 - wt_lunit(nl,istice) = pctgla(nl)/100._r8 - - wt_lunit(nl,istice_mec) = pctglc_mec_tot(nl)/100._r8 + wt_lunit(nl,istice_mec) = pctgla(nl)/100._r8 do n = isturb_MIN, isturb_MAX dens_index = n - isturb_MIN + 1 @@ -601,53 +589,149 @@ subroutine surfrd_special(begg, endg, ncid, ns) call CheckUrban(begg, endg, pcturb(begg:endg,:), subname) - deallocate(pctgla,pctlak,pctwet,pcturb,pcturb_tot,urban_region_id,pctglc_mec_tot,pctspec) + deallocate(pctgla,pctlak,pctwet,pcturb,pcturb_tot,urban_region_id,pctspec) end subroutine surfrd_special - !----------------------------------------------------------------------- +!----------------------------------------------------------------------- + subroutine surfrd_cftformat( ncid, begg, endg, wt_cft, cftsize, natpft_size ) + ! + ! !DESCRIPTION: + ! Handle generic crop types for file format where they are on their own + ! crop landunit and read in as Crop Function Types. + ! !USES: + use clm_instur , only : fert_cft, wt_nat_patch + use clm_varpar , only : cft_size, cft_lb, natpft_lb + ! !ARGUMENTS: + implicit none + type(file_desc_t), intent(inout) :: ncid ! netcdf id + integer , intent(in) :: begg, endg + integer , intent(in) :: cftsize ! CFT size + real(r8), pointer, intent(inout) :: wt_cft(:,:) ! CFT weights + integer , intent(in) :: natpft_size ! natural PFT size + ! + ! !LOCAL VARIABLES: + logical :: readvar ! is variable on dataset + real(r8),pointer :: array2D(:,:) ! local array + character(len=32) :: subname = 'surfrd_cftformat'! subroutine name +!----------------------------------------------------------------------- + SHR_ASSERT_ALL((lbound(wt_cft) == (/begg, cft_lb/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(wt_cft, dim=1) == (/endg/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(wt_cft, dim=2) >= (/cftsize+1-cft_lb/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(wt_nat_patch) >= (/endg,natpft_size-1+natpft_lb/)), errMsg(sourcefile, __LINE__)) + + call check_dim(ncid, 'cft', cftsize) + call check_dim(ncid, 'natpft', natpft_size) + + call ncd_io(ncid=ncid, varname='PCT_CFT', flag='read', data=wt_cft, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( msg=' ERROR: PCT_CFT NOT on surfdata file'//errMsg(sourcefile, __LINE__)) + + if ( cft_size > 0 )then + call ncd_io(ncid=ncid, varname='CONST_FERTNITRO_CFT', flag='read', data=fert_cft, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if ( masterproc ) & + write(iulog,*) ' WARNING: CONST_FERTNITRO_CFT NOT on surfdata file zero out' + fert_cft = 0.0_r8 + end if + else + fert_cft = 0.0_r8 + end if + + allocate( array2D(begg:endg,1:natpft_size) ) + call ncd_io(ncid=ncid, varname='PCT_NAT_PFT', flag='read', data=array2D, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( msg=' ERROR: PCT_NAT_PFT NOT on surfdata file'//errMsg(sourcefile, __LINE__)) + wt_nat_patch(begg:,natpft_lb:natpft_size-1+natpft_lb) = array2D(begg:,:) + deallocate( array2D ) + + end subroutine surfrd_cftformat + +!----------------------------------------------------------------------- + subroutine surfrd_pftformat( begg, endg, ncid ) + ! + ! !DESCRIPTION: + ! Handle generic crop types for file format where they are part of the + ! natural vegetation landunit. + ! !USES: + use clm_instur , only : fert_cft, wt_nat_patch + use clm_varpar , only : natpft_size, cft_size, natpft_lb + ! !ARGUMENTS: + implicit none + integer, intent(in) :: begg, endg + type(file_desc_t), intent(inout) :: ncid ! netcdf id + ! + ! !LOCAL VARIABLES: + logical :: cft_dim_exists ! does the dimension 'cft' exist on the dataset? + integer :: dimid ! netCDF id's + logical :: readvar ! is variable on dataset + character(len=32) :: subname = 'surfrd_pftformat'! subroutine name +!----------------------------------------------------------------------- + SHR_ASSERT_ALL((ubound(wt_nat_patch) == (/endg, natpft_size-1+natpft_lb/)), errMsg(sourcefile, __LINE__)) + + call check_dim(ncid, 'natpft', natpft_size) + ! If cft_size == 0, then we expect to be running with a surface dataset + ! that does + ! NOT have a PCT_CFT array (or CONST_FERTNITRO_CFT array), and thus does not have a 'cft' dimension. + ! Make sure + ! that's the case. + call ncd_inqdid(ncid, 'cft', dimid, cft_dim_exists) + if (cft_dim_exists) then + call endrun( msg= ' ERROR: unexpectedly found cft dimension on dataset when cft_size=0'// & + ' (if the surface dataset has a separate crop landunit, then the code'// & + ' must also have a separate crop landunit, and vice versa)'//& + errMsg(sourcefile, __LINE__)) + end if + call ncd_io(ncid=ncid, varname='CONST_FERTNITRO_CFT', flag='read', data=fert_cft, & + dim1name=grlnd, readvar=readvar) + if (readvar) then + call endrun( msg= ' ERROR: unexpectedly found CONST_FERTNITRO_CFT on dataset when cft_size=0'// & + ' (if the surface dataset has a separate crop landunit, then the code'// & + ' must also have a separate crop landunit, and vice versa)'//& + errMsg(sourcefile, __LINE__)) + end if + fert_cft = 0.0_r8 + + call ncd_io(ncid=ncid, varname='PCT_NAT_PFT', flag='read', data=wt_nat_patch, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( msg=' ERROR: PCT_NAT_PFT NOT on surfdata file'//errMsg(sourcefile, __LINE__)) + + end subroutine surfrd_pftformat + +!----------------------------------------------------------------------- subroutine surfrd_veg_all(begg, endg, ncid, ns) ! ! !DESCRIPTION: ! Determine weight arrays for non-dynamic landuse mode ! ! !USES: - use clm_varpar , only : natpft_lb, natpft_ub, natpft_size, cft_size + use clm_varctl , only : create_crop_landunit, use_fates + use clm_varpar , only : natpft_lb, natpft_ub, natpft_size, cft_size, cft_lb use clm_instur , only : wt_lunit, wt_nat_patch, wt_cft, fert_cft use landunit_varcon , only : istsoil, istcrop + use surfrdUtilsMod , only : convert_cft_to_pft ! ! !ARGUMENTS: + implicit none integer, intent(in) :: begg, endg type(file_desc_t),intent(inout) :: ncid ! netcdf id integer ,intent(in) :: ns ! domain size ! ! !LOCAL VARIABLES: - integer :: nl, m ! index - integer :: dimid,varid ! netCDF id's - integer :: ier ! error status - logical :: readvar ! is variable on dataset - logical :: cft_dim_exists ! does the dimension 'cft' exist on the dataset? - real(r8),pointer :: arrayl(:) ! local array + integer :: dimid ! netCDF id's + integer :: cftsize ! size of CFT's + logical :: readvar ! is variable on dataset + logical :: cft_dim_exists ! does the dimension 'cft' exist on the dataset? + real(r8),pointer :: arrayl(:) ! local array + real(r8),pointer :: array2D(:,:) ! local 2D array character(len=32) :: subname = 'surfrd_veg_all' ! subroutine name !----------------------------------------------------------------------- - + ! + ! Read in variables that are handled the same for all formats + ! + ! Check dimension size call check_dim(ncid, 'lsmpft', numpft+1) - call check_dim(ncid, 'natpft', natpft_size) - - if (cft_size > 0) then - call check_dim(ncid, 'cft', cft_size) - else - ! If cft_size == 0, then we expect to be running with a surface dataset that does - ! NOT have a PCT_CFT array, and thus does not have a 'cft' dimension. Make sure - ! that's the case. - call ncd_inqdid(ncid, 'cft', dimid, cft_dim_exists) - if (cft_dim_exists) then - call endrun( msg= ' ERROR: unexpectedly found cft dimension on dataset when cft_size=0'// & - ' (if the surface dataset has a separate crop landunit, then the code'// & - ' must also have a separate crop landunit, and vice versa)'//& - errMsg(sourcefile, __LINE__)) - end if - end if ! This temporary array is needed because ncd_io expects a pointer, so we can't ! directly pass wt_lunit(begg:endg,istsoil) @@ -656,48 +740,56 @@ subroutine surfrd_veg_all(begg, endg, ncid, ns) call ncd_io(ncid=ncid, varname='PCT_NATVEG', flag='read', data=arrayl, & dim1name=grlnd, readvar=readvar) if (.not. readvar) call endrun( msg=' ERROR: PCT_NATVEG NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - wt_lunit(begg:endg,istsoil) = arrayl(begg:endg) / 100._r8 + wt_lunit(begg:endg,istsoil) = arrayl(begg:endg) call ncd_io(ncid=ncid, varname='PCT_CROP', flag='read', data=arrayl, & dim1name=grlnd, readvar=readvar) if (.not. readvar) call endrun( msg=' ERROR: PCT_CROP NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - wt_lunit(begg:endg,istcrop) = arrayl(begg:endg) / 100._r8 + wt_lunit(begg:endg,istcrop) = arrayl(begg:endg) deallocate(arrayl) - call ncd_io(ncid=ncid, varname='PCT_NAT_PFT', flag='read', data=wt_nat_patch, & - dim1name=grlnd, readvar=readvar) - if (.not. readvar) call endrun( msg=' ERROR: PCT_NAT_PFT NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - wt_nat_patch(begg:endg,:) = wt_nat_patch(begg:endg,:) / 100._r8 - call check_sums_equal_1(wt_nat_patch, begg, 'wt_nat_patch', subname) - - if (cft_size > 0) then - call ncd_io(ncid=ncid, varname='PCT_CFT', flag='read', data=wt_cft, & - dim1name=grlnd, readvar=readvar) - if (.not. readvar) call endrun( msg=' ERROR: PCT_CFT NOT on surfdata file'//errMsg(sourcefile, __LINE__)) - wt_cft(begg:endg,:) = wt_cft(begg:endg,:) / 100._r8 - call check_sums_equal_1(wt_cft, begg, 'wt_cft', subname) - - call ncd_io(ncid=ncid, varname='CONST_FERTNITRO_CFT', flag='read', data=fert_cft, & - dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if ( masterproc ) & - write(iulog,*) ' WARNING: CONST_FERTNITRO_CFT NOT on surfdata file zero out' - fert_cft = 0.0_r8 + ! Check the file format for CFT's and handle accordingly + call ncd_inqdid(ncid, 'cft', dimid, cft_dim_exists) + if ( cft_dim_exists .and. create_crop_landunit )then + call surfrd_cftformat( ncid, begg, endg, wt_cft, cft_size, natpft_size ) ! Format where CFT's is read in a seperate landunit + else if ( (.not. cft_dim_exists) .and. (.not. create_crop_landunit) )then + if ( masterproc ) write(iulog,*) "WARNING: The PFT format is an unsupported format that will be removed in th future!" + call surfrd_pftformat( begg, endg, ncid ) ! Format where crop is part of the natural veg. landunit + else if ( cft_dim_exists .and. .not. create_crop_landunit )then + if ( masterproc ) write(iulog,*) "WARNING: New CFT-based format surface datasets should be run with create_crop_landunit=T" + if ( use_fates ) then + if ( masterproc ) write(iulog,*) "WARNING: When fates is on we allow new CFT based surface datasets ", & + "to be used with create_crop_land FALSE" + cftsize = 2 + allocate(array2D(begg:endg,cft_lb:cftsize-1+cft_lb)) + call surfrd_cftformat( ncid, begg, endg, array2D, cftsize, natpft_size-cftsize ) ! Read crops in as CFT's + call convert_cft_to_pft( begg, endg, cftsize, array2D ) ! Convert from CFT to natural veg. landunit + deallocate(array2D) + else + call endrun( msg=' ERROR: New format surface datasets require create_crop_landunit TRUE'//errMsg(sourcefile, __LINE__)) end if + end if - else - ! If cft_size == 0, and thus we aren't reading PCT_CFT, then make sure PCT_CROP is - ! 0 everywhere (PCT_CROP > 0 anywhere requires that we have a PCT_CFT array) - if (any(wt_lunit(begg:endg,istcrop) > 0._r8)) then - call endrun( msg=' ERROR: if PCT_CROP > 0 anywhere, then cft_size must be > 0'// & + ! Do some checking + + if ( (cft_size == 0) .and. any(wt_lunit(begg:endg,istcrop) > 0._r8) ) then + call endrun( msg=' ERROR: if PCT_CROP > 0 anywhere, then cft_size must be > 0'// & ' (if the surface dataset has a separate crop landunit, then the code'// & ' must also have a separate crop landunit, and vice versa)'//& errMsg(sourcefile, __LINE__)) - end if end if + ! Convert from percent to fraction, check sums of nat vegetation add to 1 + if ( cft_size > 0 )then + wt_cft(begg:endg,:) = wt_cft(begg:endg,:) / 100._r8 + call check_sums_equal_1(wt_cft, begg, 'wt_cft', subname) + end if + wt_lunit(begg:endg,istsoil) = wt_lunit(begg:endg,istsoil) / 100._r8 + wt_lunit(begg:endg,istcrop) = wt_lunit(begg:endg,istcrop) / 100._r8 + wt_nat_patch(begg:endg,:) = wt_nat_patch(begg:endg,:) / 100._r8 + call check_sums_equal_1(wt_nat_patch, begg, 'wt_nat_patch', subname) - + ! Collapse crop landunits down when prognostic crops are on if (use_crop) then call collapse_crop_types(wt_cft(begg:endg, :), fert_cft(begg:endg, :), begg, endg, verbose=.true.) end if diff --git a/src/main/surfrdUtilsMod.F90 b/src/main/surfrdUtilsMod.F90 index 8e5e229e1e..45fbf9ebe1 100644 --- a/src/main/surfrdUtilsMod.F90 +++ b/src/main/surfrdUtilsMod.F90 @@ -19,6 +19,8 @@ module surfrdUtilsMod ! ! !PUBLIC MEMBER FUNCTIONS: public :: check_sums_equal_1 ! Confirm that sum(arr(n,:)) == 1 for all n + public :: renormalize ! Renormalize an array + public :: convert_cft_to_pft ! Conversion of crop CFT to natural veg PFT:w public :: collapse_crop_types ! Collapse unused crop types into types used in this run character(len=*), parameter, private :: sourcefile = & @@ -29,7 +31,7 @@ module surfrdUtilsMod contains !----------------------------------------------------------------------- - subroutine check_sums_equal_1(arr, lb, name, caller) + subroutine check_sums_equal_1(arr, lb, name, caller, ier) ! ! !DESCRIPTION: ! Confirm that sum(arr(n,:)) == 1 for all n. If this isn't true for any n, abort with a message. @@ -39,14 +41,16 @@ subroutine check_sums_equal_1(arr, lb, name, caller) real(r8) , intent(in) :: arr(lb:,:) ! array to check character(len=*), intent(in) :: name ! name of array character(len=*), intent(in) :: caller ! identifier of caller, for more meaningful error messages + integer, optional, intent(out):: ier ! Return an error code rather than abort ! ! !LOCAL VARIABLES: logical :: found integer :: nl integer :: nindx - real(r8), parameter :: eps = 1.e-14_r8 + real(r8), parameter :: eps = 1.e-13_r8 !----------------------------------------------------------------------- + if( present(ier) ) ier = 0 found = .false. do nl = lbound(arr, 1), ubound(arr, 1) @@ -60,11 +64,81 @@ subroutine check_sums_equal_1(arr, lb, name, caller) if (found) then write(iulog,*) trim(caller), ' ERROR: sum of ', trim(name), ' not 1.0 at nl=', nindx write(iulog,*) 'sum is: ', sum(arr(nindx,:)) - call endrun(msg=errMsg(sourcefile, __LINE__)) + if( present(ier) ) then + ier = -10 + else + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if end if end subroutine check_sums_equal_1 + !----------------------------------------------------------------------- + subroutine renormalize(arr, lb, normal) + ! + ! !DESCRIPTION: + ! Re normalize an array so that it sums to the input value + ! + ! !ARGUMENTS: + integer , intent(in) :: lb ! lower bound of the first dimension of arr + real(r8) , intent(inout) :: arr(lb:,:) ! array to check + real(r8) , intent(in) :: normal ! normal to sum to + ! + ! !LOCAL VARIABLES: + integer :: nl ! Array index + real(r8) :: arr_sum ! sum of array + real(r8) :: ratio ! ratio to multiply by + !----------------------------------------------------------------------- + + do nl = lbound(arr, 1), ubound(arr, 1) + arr_sum = sum(arr(nl,:)) + if ( arr_sum /= 0.0_r8 )then + ratio = normal / arr_sum + arr(nl,:) = arr(nl,:) * ratio + end if + end do + + end subroutine renormalize + +!----------------------------------------------------------------------- + subroutine convert_cft_to_pft( begg, endg, cftsize, wt_cft ) + ! + ! !DESCRIPTION: + ! Convert generic crop types that were read in as seperate CFT's on + ! a crop landunit, and put them on the vegetated landunit. + ! !USES: + use clm_instur , only : wt_lunit, wt_nat_patch, fert_cft + use clm_varpar , only : cft_size, natpft_size + use pftconMod , only : nc3crop + use landunit_varcon , only : istsoil, istcrop + ! !ARGUMENTS: + implicit none + integer , intent(in) :: begg, endg + integer , intent(in) :: cftsize ! CFT size + real(r8) , intent(inout) :: wt_cft(begg:,:) ! CFT weights + ! + ! !LOCAL VARIABLES: + integer :: g ! index +!----------------------------------------------------------------------- + SHR_ASSERT_ALL((ubound(wt_cft) == (/endg, cftsize/)), errMsg(sourcefile, __LINE__)) + SHR_ASSERT_ALL((ubound(wt_nat_patch) == (/endg, nc3crop+cftsize-1/)), errMsg(sourcefile, __LINE__)) + + do g = begg, endg + if ( wt_lunit(g,istcrop) > 0.0_r8 )then + ! Move CFT over to PFT and do weighted average of the crop and soil parts + wt_nat_patch(g,:) = wt_nat_patch(g,:) * wt_lunit(g,istsoil) + wt_cft(g,:) = wt_cft(g,:) * wt_lunit(g,istcrop) + wt_nat_patch(g,nc3crop:) = wt_cft(g,:) ! Add crop CFT's to end of natural veg PFT's + wt_lunit(g,istsoil) = (wt_lunit(g,istsoil) + wt_lunit(g,istcrop)) ! Add crop landunit to soil landunit + wt_nat_patch(g,:) = wt_nat_patch(g,:) / wt_lunit(g,istsoil) + wt_lunit(g,istcrop) = 0.0_r8 ! Zero out crop CFT's + else + wt_nat_patch(g,nc3crop:) = 0.0_r8 ! Make sure generic crops are zeroed out + end if + end do + + end subroutine convert_cft_to_pft + !----------------------------------------------------------------------- subroutine collapse_crop_types(wt_cft, fert_cft, begg, endg, verbose) ! diff --git a/src/main/test/CMakeLists.txt b/src/main/test/CMakeLists.txt index 4c006e2824..2aa80fd5d7 100644 --- a/src/main/test/CMakeLists.txt +++ b/src/main/test/CMakeLists.txt @@ -1,4 +1,6 @@ add_subdirectory(subgridWeights_test) +add_subdirectory(accumul_test) +add_subdirectory(surfrdUtils_test) add_subdirectory(atm2lnd_test) add_subdirectory(clm_glclnd_test) add_subdirectory(glcBehavior_test) diff --git a/src/main/test/accumul_test/CMakeLists.txt b/src/main/test/accumul_test/CMakeLists.txt new file mode 100644 index 0000000000..105ef0dac1 --- /dev/null +++ b/src/main/test/accumul_test/CMakeLists.txt @@ -0,0 +1,7 @@ +set(pfunit_sources + test_accumul.pf) + +create_pFUnit_test(accumul test_accumul_exe + "${pfunit_sources}" "") + +target_link_libraries(test_accumul_exe clm csm_share esmf_wrf_timemgr) \ No newline at end of file diff --git a/src/main/test/accumul_test/test_accumul.pf b/src/main/test/accumul_test/test_accumul.pf new file mode 100644 index 0000000000..8e08cff77d --- /dev/null +++ b/src/main/test/accumul_test/test_accumul.pf @@ -0,0 +1,720 @@ +module test_accumul + + ! Tests of accumulMod + + use pfunit_mod + use accumulMod + use unittestSubgridMod + use unittestSimpleSubgridSetupsMod, only : setup_single_veg_patch + use shr_kind_mod , only : r8 => shr_kind_r8 + use clm_varcon, only : spval + use PatchType, only : patch + + implicit none + + @TestCase + type, extends(TestCase) :: TestAccumul + contains + procedure :: setUp + procedure :: tearDown + procedure :: init_sl_patch_field + procedure :: init_ml_patch_field + procedure :: update_and_extract_sl_patch_field + procedure :: update_and_extract_ml_patch_field + end type TestAccumul + + real(r8), parameter :: tol = 1.e-13_r8 + +contains + + ! ======================================================================== + ! Helper routines + ! ======================================================================== + + subroutine setUp(this) + class(TestAccumul), intent(inout) :: this + end subroutine setUp + + subroutine tearDown(this) + class(TestAccumul), intent(inout) :: this + + call clean_accum_fields + end subroutine tearDown + + subroutine init_sl_patch_field(this, name, accum_type, accum_period, init_value) + ! Call init_accum_field for a single-level patch field + class(TestAccumul), intent(in) :: this + character(len=*), intent(in) :: name + character(len=*), intent(in) :: accum_type ! timeavg, runmean, runaccum + integer, intent(in) :: accum_period + real(r8), intent(in), optional :: init_value ! if absent, use 0 + + real(r8) :: l_init_value + + if (present(init_value)) then + l_init_value = init_value + else + l_init_value = 0._r8 + end if + + call init_accum_field(& + name = name, & + units = 'none', & + desc = 'no desc', & + accum_type = accum_type, & + accum_period = accum_period, & + numlev = 1, & + subgrid_type = 'pft', & + init_value = l_init_value) + end subroutine init_sl_patch_field + + subroutine init_ml_patch_field(this, name, accum_type, accum_period, nlev, init_value) + ! Call init_accum_field for a multi-level patch field + class(TestAccumul), intent(in) :: this + character(len=*), intent(in) :: name + character(len=*), intent(in) :: accum_type ! timeavg, runmean, runaccum + integer, intent(in) :: accum_period + integer, intent(in) :: nlev + real(r8), intent(in), optional :: init_value ! if absent, use 0 + + real(r8) :: l_init_value + + if (present(init_value)) then + l_init_value = init_value + else + l_init_value = 0._r8 + end if + + call init_accum_field(& + name = name, & + units = 'none', & + desc = 'no desc', & + accum_type = accum_type, & + accum_period = accum_period, & + numlev = nlev, & + subgrid_type = 'pft', & + init_value = l_init_value, & + type2d = 'irrelevant') ! type2d just needed for restart + end subroutine init_ml_patch_field + + subroutine update_and_extract_sl_patch_field(this, fieldname, values, val_output, & + pactive, timestep_start) + ! Calls update_accum_field once for each value in 'values', assuming that the values + ! come once per timestep. For the first call, all input values are set equal to + ! values(1); for the second call, all input values are set equal to values(2); etc. + ! + ! After all update calls are done, calls extract_accum_field to extract the final + ! value from bounds%begp into val_output. This assumes the timestep at extraction is + ! size(values) (or size(values)+(timestep_start-1), if timestep_start is present). + ! + ! If pactive is present, then it should be an array of the same size as 'values', + ! specifying whether the patch at bounds%begp is active in each time step. If this is + ! absent, then this patch is assumed to be active for all time steps. + ! + ! This version is for a single-level (1-d) field. + class(TestAccumul), intent(inout) :: this + character(len=*), intent(in) :: fieldname + real(r8), intent(in) :: values(:) + real(r8), intent(out) :: val_output + logical, optional, intent(in) :: pactive(:) + + ! If present, this specifies the starting nstep value. If absent, we start with 1. + integer, optional, intent(in) :: timestep_start + + integer :: n_timesteps + integer :: timestep + integer :: timestep_offset + real(r8), pointer :: vals_input(:) + real(r8), pointer :: vals_output(:) + logical, allocatable :: l_pactive(:) ! local version of pactive + + n_timesteps = size(values) + if (present(pactive)) then + @assertEqual(n_timesteps, size(pactive)) + end if + + allocate(l_pactive(n_timesteps)) + if (present(pactive)) then + l_pactive(:) = pactive(:) + else + l_pactive(:) = .true. + end if + + if (present(timestep_start)) then + timestep_offset = timestep_start - 1 + else + timestep_offset = 0 + end if + + allocate(vals_input(bounds%begp:bounds%endp)) + allocate(vals_output(bounds%begp:bounds%endp)) + do timestep = 1, n_timesteps + vals_input(:) = values(timestep) + patch%active(bounds%begp) = l_pactive(timestep) + call update_accum_field(fieldname, vals_input, timestep+timestep_offset) + end do + call extract_accum_field(fieldname, vals_output, n_timesteps+timestep_offset) + val_output = vals_output(bounds%begp) + + deallocate(vals_input) + deallocate(vals_output) + + end subroutine update_and_extract_sl_patch_field + + subroutine update_and_extract_ml_patch_field(this, fieldname, values, val_output, pactive) + ! Calls update_accum_field once for each value in 'values', assuming that the values + ! come once per timestep. For the first call, the input values in all patches are set + ! equal to values(:,1); for the second call, the input values in all patches are set + ! equal to values(:,2); etc. Thus, 'values' specifies different values for each level + ! and time, but assumes the same values in each patch (if there is more than one + ! patch). + ! + ! After all update calls are done, calls extract_accum_field to extract the final + ! value from bounds%begp into this%vals_output. This assumes the timestep at + ! extraction is size(values,2). + ! + ! If pactive is present, then it should be an array of the same size as the second + ! dimension of 'values', specifying whether the patch at bounds%begp is active in each + ! time step. If this is absent, then this patch is assumed to be active for all time + ! steps. + ! + ! This version is for a multi-level (2-d) field. + class(TestAccumul), intent(inout) :: this + character(len=*), intent(in) :: fieldname + real(r8), intent(in) :: values(:,:) ! [level, time] + real(r8), intent(out) :: val_output(:) ! [level] + logical, optional, intent(in) :: pactive(:) + + integer :: n_timesteps + integer :: timestep + integer :: n_levels + integer :: level + real(r8), pointer :: vals_input(:,:) + real(r8), pointer :: vals_output(:,:) + logical, allocatable :: l_pactive(:) ! local version of pactive + + n_levels = size(values,1) + n_timesteps = size(values,2) + + @assertEqual(n_levels, size(val_output)) + if (present(pactive)) then + @assertEqual(n_timesteps, size(pactive)) + end if + + allocate(l_pactive(n_timesteps)) + if (present(pactive)) then + l_pactive(:) = pactive(:) + else + l_pactive(:) = .true. + end if + + allocate(vals_input(bounds%begp:bounds%endp, n_levels)) + allocate(vals_output(bounds%begp:bounds%endp, n_levels)) + do timestep = 1, n_timesteps + do level = 1, n_levels + vals_input(:,level) = values(level,timestep) + end do + patch%active(bounds%begp) = l_pactive(timestep) + call update_accum_field(fieldname, vals_input, timestep) + end do + call extract_accum_field(fieldname, vals_output, n_timesteps) + val_output(:) = vals_output(bounds%begp,:) + + deallocate(vals_input) + deallocate(vals_output) + + end subroutine update_and_extract_ml_patch_field + + ! ======================================================================== + ! Begin tests + ! ======================================================================== + + ! ------------------------------------------------------------------------ + ! Tests of timeavg + ! ------------------------------------------------------------------------ + + @Test + subroutine timeavg_basic(this) + ! Test basic operation of timeavg field + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(accum_period) = [11._r8, 12._r8, 13._r8] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='timeavg', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output) + + ! Verify + expected = sum(values)/accum_period + @assertEqual(expected, val_output, tolerance=tol) + end subroutine timeavg_basic + + @Test + subroutine timeavg_wrongTime(this) + ! Test a timeavg field when it's the wrong time for producing an average + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(2) = [11._r8, 12._r8] + real(r8) :: val_output + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='timeavg', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output) + + ! Verify + @assertEqual(spval, val_output) + end subroutine timeavg_wrongTime + + @Test + subroutine timeavg_onlyLatestPeriod(this) + ! If we go through multiple periods, the values from earlier periods should have no + ! impact on the final result. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(accum_period*2) = & + [11._r8, 12._r8, 13._r8, 21._r8, 22._r8, 23._r8] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='timeavg', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output) + + ! Verify + expected = sum(values(accum_period+1:2*accum_period))/accum_period + @assertEqual(expected, val_output, tolerance=tol) + end subroutine timeavg_onlyLatestPeriod + + @Test + subroutine timeavg_newlyActive(this) + ! For timeavg: If a point becomes active in the middle of a period, then it should + ! give the average value just over the time steps when it was active. + ! + ! This may or may not be the ideal behavior; we can change this if some other + ! behavior would be better in this situation. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(accum_period*2) = & + [11._r8, 12._r8, 13._r8, 21._r8, 22._r8, 23._r8] + logical, parameter :: pactive(accum_period*2) = & + [.false., .false., .false., .false., .true., .true.] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='timeavg', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output, pactive=pactive) + + ! Verify + expected = sum(values(5:6))/2._r8 + @assertEqual(expected, val_output, tolerance=tol) + end subroutine timeavg_newlyActive + + @Test + subroutine timeavg_veryNewlyActive(this) + ! For timeavg: If a point just became active in this time step, and this is the time + ! when we'd usually get time averages, then the time average for this point should + ! just be this time step's value. + ! + ! This may or may not be the ideal behavior; we can change this if some other + ! behavior would be better in this situation. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(accum_period) = [11._r8, 12._r8, 13._r8] + logical, parameter :: pactive(accum_period) = [.false., .false., .true.] + real(r8) :: val_output + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='timeavg', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output, pactive=pactive) + + ! Verify + @assertEqual(values(accum_period), val_output, tolerance=tol) + end subroutine timeavg_veryNewlyActive + + @Test + subroutine timeavg_activeInactiveActive(this) + ! Test timeavg with a point that starts active, becomes inactive, then later becomes + ! active again. Test spans two periods. The point is inactive during the reset time + ! step. The final average should be the average of the time steps when it was active. + ! In particular, it should not be reset. + ! + ! This may or may not be the ideal behavior; we can change this if some other + ! behavior would be better in this situation. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(accum_period*2) = & + [11._r8, 102._r8, 193._r8, 210._r8, 272._r8, 234._r8] + logical, parameter :: pactive(accum_period*2) = & + [.true., .true., .false., .false., .true., .true.] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='timeavg', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output, pactive=pactive) + + ! Verify + expected = (values(1) + values(2) + values(5) + values(6))/4._r8 + @assertEqual(expected, val_output, tolerance=tol) + end subroutine timeavg_activeInactiveActive + + @Test + subroutine timeavg_multiLevel(this) + ! Make sure that multi-level timeavg works right + ! + ! Note that we currently do not have multi-level tests of the other accum types. + ! Because of the way the code is structured, this is okay: the same multi-level code + ! is used regardless of the accum method. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values_lev1(accum_period*2) = & + [11._r8, 12._r8, 13._r8, 21._r8, 22._r8, 23._r8] + real(r8), parameter :: values_lev2(accum_period*2) = & + [111._r8, 112._r8, 113._r8, 121._r8, 122._r8, 123._r8] + real(r8) :: values(2, accum_period*2) + real(r8) :: val_output(2) + real(r8) :: expected_lev1, expected_lev2 + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_ml_patch_field(name=fieldname, accum_type='timeavg', & + accum_period = accum_period, nlev=2) + values(1,:) = values_lev1 + values(2,:) = values_lev2 + + ! Exercise + call this%update_and_extract_ml_patch_field(fieldname, values, val_output) + + ! Verify + expected_lev1 = sum(values_lev1(4:6))/accum_period + expected_lev2 = sum(values_lev2(4:6))/accum_period + @assertEqual(expected_lev1, val_output(1), tolerance=tol) + @assertEqual(expected_lev2, val_output(2), tolerance=tol) + end subroutine timeavg_multiLevel + + ! ------------------------------------------------------------------------ + ! Tests of runmean + ! ------------------------------------------------------------------------ + + @Test + subroutine runmean_oneStep(this) + ! For runmean, after one time step, value should be equal to the value in that time + ! step. The initial value should be irrelevant. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: my_value = 11._r8 + real(r8) :: val_output + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runmean', & + accum_period = accum_period, init_value = 1000._r8) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, [my_value], val_output) + + ! Verify + @assertEqual(my_value, val_output, tolerance=tol) + end subroutine runmean_oneStep + + @Test + subroutine runmean_beforePeriod(this) + ! Test runmean accumulation before accum_period is reached + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 4 + real(r8), parameter :: values(3) = [11._r8, 22._r8, 43._r8] + real(r8) :: val_output + real(r8) :: expected_ts1, expected_ts2, expected_ts3 + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runmean', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output) + + ! Verify + expected_ts1 = values(1) + expected_ts2 = (expected_ts1 + values(2))/2._r8 + expected_ts3 = (2._r8 * expected_ts2 + values(3)) / 3._r8 + @assertEqual(expected_ts3, val_output, tolerance=tol) + end subroutine runmean_beforePeriod + + @Test + subroutine runmean_afterPeriod(this) + ! Test runmean accumulation after accum_period is reached + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(5) = [11._r8, 22._r8, 43._r8, 110._r8, 17._r8] + real(r8) :: val_output + real(r8) :: expected_ts1, expected_ts2, expected_ts3, expected_ts4, expected_ts5 + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runmean', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output) + + ! Verify + expected_ts1 = values(1) + expected_ts2 = (expected_ts1 + values(2))/2._r8 + expected_ts3 = (2._r8 * expected_ts2 + values(3)) / 3._r8 + expected_ts4 = (2._r8 * expected_ts3 + values(4)) / 3._r8 + expected_ts5 = (2._r8 * expected_ts4 + values(5)) / 3._r8 + @assertEqual(expected_ts5, val_output, tolerance=tol) + end subroutine runmean_afterPeriod + + @Test + subroutine runmean_newlyActive(this) + ! For runmean: If a point recently became active, its running mean should only + ! consider values from when it was active. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(7) = [1._r8, 2._r8, 11._r8, 22._r8, 43._r8, 110._r8, 17._r8] + logical, parameter :: pactive(7) = [.false., .false., .true., .true., .true., .true., .true.] + real(r8) :: val_output + real(r8) :: expected_ts3, expected_ts4, expected_ts5, expected_ts6, expected_ts7 + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runmean', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output, pactive=pactive) + + ! Verify + expected_ts3 = values(3) + expected_ts4 = (expected_ts3 + values(4))/2._r8 + expected_ts5 = (2._r8 * expected_ts4 + values(5)) / 3._r8 + expected_ts6 = (2._r8 * expected_ts5 + values(6)) / 3._r8 + expected_ts7 = (2._r8 * expected_ts6 + values(7)) / 3._r8 + @assertEqual(expected_ts7, val_output, tolerance=tol) + end subroutine runmean_newlyActive + + @Test + subroutine runmean_activeInactiveActive(this) + ! Test runmean with a point that starts active, becomes inactive, then later becomes + ! active again. Should ignore values in the inactive steps. Also, should continue + ! where it left off - i.e., including the values accumulated when it was first + ! active. This may or may not be the ideal behavior; we can change this if some other + ! behavior would be better in this situation. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 + real(r8), parameter :: values(7) = [1._r8, 2._r8, 11._r8, 22._r8, 43._r8, 110._r8, 17._r8] + logical, parameter :: pactive(7) = [.true., .true., .false., .false., .true., .true., .true.] + real(r8) :: val_output + real(r8) :: expected_ts1, expected_ts2, expected_ts5, expected_ts6, expected_ts7 + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runmean', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output, pactive=pactive) + + ! Verify + expected_ts1 = values(1) + expected_ts2 = (expected_ts1 + values(2))/2._r8 + expected_ts5 = (2._r8 * expected_ts2 + values(5)) / 3._r8 + expected_ts6 = (2._r8 * expected_ts5 + values(6)) / 3._r8 + expected_ts7 = (2._r8 * expected_ts6 + values(7)) / 3._r8 + @assertEqual(expected_ts7, val_output, tolerance=tol) + end subroutine runmean_activeInactiveActive + + ! ------------------------------------------------------------------------ + ! Tests of runaccum + ! ------------------------------------------------------------------------ + + @Test + subroutine runaccum_basic(this) + ! Test basic operation of runaccum field + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 ! irrelevant for this type + real(r8), parameter :: values(4) = [11._r8, 12._r8, 13._r8, 24._r8] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runaccum', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output) + + ! Verify + expected = sum(values) + @assertEqual(expected, val_output, tolerance=tol) + end subroutine runaccum_basic + + @Test + subroutine runaccum_reset(this) + ! Test resetting of runaccum field + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 ! irrelevant for this type + real(r8), parameter :: values(5) = [11._r8, 12._r8, accumResetVal, 13._r8, 24._r8] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runaccum', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output) + + ! Verify + expected = sum(values(4:5)) + @assertEqual(expected, val_output, tolerance=tol) + end subroutine runaccum_reset + + @Test + subroutine runaccum_newlyActive(this) + ! For runaccum: If a point becomes active between accumulation resets, then it should + ! just give the accumulated amount since it became active. + ! + ! This may or may not be the ideal behavior; we can change this if some other + ! behavior would be better in this situation. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 ! irrelevant for this type + real(r8), parameter :: values(5) = [11._r8, accumResetVal, 12._r8, 13._r8, 24._r8] + logical, parameter :: pactive(5) = [.false., .false., .false., .true., .true.] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runaccum', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output, pactive=pactive) + + ! Verify + expected = sum(values(4:5)) + @assertEqual(expected, val_output, tolerance=tol) + end subroutine runaccum_newlyActive + + @Test + subroutine runaccum_activeInactiveActive(this) + ! Test runaccum with a point that starts active, becomes inactive, then later becomes + ! active again. + ! + ! Should ignore values and accumResetVal in the inactive steps. + ! + ! Also, should continue where it left off - i.e., including the values accumulated + ! when it was first active. This may or may not be the ideal behavior; we can change + ! this if some other behavior would be better in this situation. + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname = 'foo' + integer, parameter :: accum_period = 3 ! irrelevant for this type + real(r8), parameter :: values(5) = [11._r8, accumResetVal, 12._r8, 17._r8, 24._r8] + logical, parameter :: pactive(5) = [.true., .false., .false., .true., .true.] + real(r8) :: val_output + real(r8) :: expected + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname, accum_type='runaccum', & + accum_period = accum_period) + + ! Exercise + call this%update_and_extract_sl_patch_field(fieldname, values, val_output, pactive=pactive) + + ! Verify + expected = values(1) + values(4) + values(5) + @assertEqual(expected, val_output, tolerance=tol) + end subroutine runaccum_activeInactiveActive + + ! ------------------------------------------------------------------------ + ! Tests of multiple fields + ! ------------------------------------------------------------------------ + + @Test + subroutine multipleFields(this) + class(TestAccumul), intent(inout) :: this + character(len=*), parameter :: fieldname1 = 'foo' + character(len=*), parameter :: fieldname2 = 'bar' + integer, parameter :: accum_period = 2 ! same for both, for simplicity + real(r8), parameter :: values1(2) = [11._r8, 12._r8] + real(r8), parameter :: values2(2) = [111._r8, 112._r8] + integer :: timestep + real(r8) :: val_output1, val_output2 + real(r8) :: expected1, expected2 + + ! Setup + call setup_single_veg_patch(pft_type=1) + call this%init_sl_patch_field(name=fieldname1, accum_type='timeavg', & + accum_period = accum_period) + call this%init_sl_patch_field(name=fieldname2, accum_type='runaccum', & + accum_period = accum_period) + + ! Exercise + ! + ! In order to possibly catch more bugs, and to more closely replicate the structure of + ! the production code: rather than doing a single update and extract for each field, + ! we first do an update and extract for time1, then do an update and extract for + ! time2. + do timestep = 1, 2 + call this%update_and_extract_sl_patch_field(fieldname1, values1(timestep:timestep), val_output1, & + timestep_start=timestep) + call this%update_and_extract_sl_patch_field(fieldname2, values2(timestep:timestep), val_output2, & + timestep_start=timestep) + end do + + ! Verify + expected1 = sum(values1)/2._r8 + expected2 = sum(values2) + @assertEqual(expected1, val_output1, tolerance=tol) + @assertEqual(expected2, val_output2, tolerance=tol) + end subroutine multipleFields + +end module test_accumul diff --git a/src/main/test/filter_test/test_filter_col.pf b/src/main/test/filter_test/test_filter_col.pf index 5b01404730..24eab882ab 100644 --- a/src/main/test/filter_test/test_filter_col.pf +++ b/src/main/test/filter_test/test_filter_col.pf @@ -441,4 +441,36 @@ contains @assertTrue(filter == expected) end subroutine grcflagsLtypes_ltypeNotPresent + ! ------------------------------------------------------------------------ + ! Tests of col_filter_from_filter_and_logical_array + ! ------------------------------------------------------------------------ + + @Test + subroutine filterAndLogicalArray_multiple_points(this) + ! Test col_filter_from_filter_and_logical_array with multiple points, with various + ! combinations of inside and outside the filter, and inside and outside the logical + ! array + class(TestFilterCol), intent(inout) :: this + + ! Final filter should be set where both of the following are true: + logical, parameter :: logical_orig(6) = [.false., .true., .false., .true., .false., .true.] + logical, parameter :: logical_new (6) = [.false., .false., .false., .true., .true., .true.] + + type(filter_col_type) :: filter_orig + type(filter_col_type) :: filter_new + type(filter_col_type) :: expected + + call setup_ncells_single_veg_patch(ncells = 6, pft_type = 1) + filter_orig = col_filter_from_logical_array(bounds, logical_orig) + expected = col_filter_from_index_array(bounds, [bounds%begc+3, bounds%begc+5]) + + filter_new = col_filter_from_filter_and_logical_array(& + bounds = bounds, & + num_orig = filter_orig%num, & + filter_orig = filter_orig%indices, & + logical_col = logical_new) + + @assertTrue(filter_new == expected) + end subroutine filterAndLogicalArray_multiple_points + end module test_filter_col diff --git a/src/main/test/glcBehavior_test/test_glcBehavior.pf b/src/main/test/glcBehavior_test/test_glcBehavior.pf index 16c622cafa..2badce817c 100644 --- a/src/main/test/glcBehavior_test/test_glcBehavior.pf +++ b/src/main/test/glcBehavior_test/test_glcBehavior.pf @@ -61,7 +61,8 @@ contains call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & glacier_region_map = [0], & glacier_region_behavior_str = ['multiple'], & - glacier_region_melt_behavior_str = ['replaced_by_ice']) + glacier_region_melt_behavior_str = ['replaced_by_ice'], & + glacier_region_ice_runoff_behavior_str = ['remains_ice']) @assertFalse(glc_behavior%has_virtual_columns_grc(bounds%begg)) @assertFalse(glc_behavior%get_collapse_to_atm_topo(bounds%begg)) @@ -79,7 +80,8 @@ contains call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & glacier_region_map = [0], & glacier_region_behavior_str = ['virtual'], & - glacier_region_melt_behavior_str = ['replaced_by_ice']) + glacier_region_melt_behavior_str = ['replaced_by_ice'], & + glacier_region_ice_runoff_behavior_str = ['remains_ice']) @assertTrue(glc_behavior%has_virtual_columns_grc(bounds%begg)) @assertFalse(glc_behavior%get_collapse_to_atm_topo(bounds%begg)) @@ -97,7 +99,8 @@ contains call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & glacier_region_map = [0], & glacier_region_behavior_str = ['single_at_atm_topo'], & - glacier_region_melt_behavior_str = ['replaced_by_ice']) + glacier_region_melt_behavior_str = ['replaced_by_ice'], & + glacier_region_ice_runoff_behavior_str = ['remains_ice']) @assertFalse(glc_behavior%has_virtual_columns_grc(bounds%begg)) @assertTrue(glc_behavior%get_collapse_to_atm_topo(bounds%begg)) @@ -115,7 +118,8 @@ contains call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & glacier_region_map = [0], & glacier_region_behavior_str = ['single_at_atm_topo'], & - glacier_region_melt_behavior_str = ['replaced_by_ice']) + glacier_region_melt_behavior_str = ['replaced_by_ice'], & + glacier_region_ice_runoff_behavior_str = ['remains_ice']) @assertTrue(glc_behavior%melt_replaced_by_ice_grc(bounds%begg)) end subroutine init_replaced_behaviorIsCorrect @@ -131,11 +135,46 @@ contains call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & glacier_region_map = [0], & glacier_region_behavior_str = ['single_at_atm_topo'], & - glacier_region_melt_behavior_str = ['remains_in_place']) + glacier_region_melt_behavior_str = ['remains_in_place'], & + glacier_region_ice_runoff_behavior_str = ['remains_ice']) @assertFalse(glc_behavior%melt_replaced_by_ice_grc(bounds%begg)) end subroutine init_remains_behaviorIsCorrect + @Test + subroutine init_remainsIce_behaviorIsCorrect(this) + ! Make sure ice runoff behavior is correct for 'remains_ice' + class(TestGlcBehavior), intent(inout) :: this + type(glc_behavior_type) :: glc_behavior + + call setup_single_veg_patch(0) + + call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & + glacier_region_map = [0], & + glacier_region_behavior_str = ['single_at_atm_topo'], & + glacier_region_melt_behavior_str = ['replaced_by_ice'], & + glacier_region_ice_runoff_behavior_str = ['remains_ice']) + + @assertFalse(glc_behavior%ice_runoff_melted_grc(bounds%begg)) + end subroutine init_remainsIce_behaviorIsCorrect + + @Test + subroutine init_melted_behaviorIsCorrect(this) + ! Make sure ice runoff behavior is correct for 'melted' + class(TestGlcBehavior), intent(inout) :: this + type(glc_behavior_type) :: glc_behavior + + call setup_single_veg_patch(0) + + call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & + glacier_region_map = [0], & + glacier_region_behavior_str = ['single_at_atm_topo'], & + glacier_region_melt_behavior_str = ['replaced_by_ice'], & + glacier_region_ice_runoff_behavior_str = ['melted']) + + @assertTrue(glc_behavior%ice_runoff_melted_grc(bounds%begg)) + end subroutine init_melted_behaviorIsCorrect + @Test subroutine init_multipleGridCells(this) class(TestGlcBehavior), intent(inout) :: this @@ -146,7 +185,8 @@ contains call glc_behavior%InitFromInputs(bounds%begg, bounds%endg, & glacier_region_map = [0, 1, 0], & glacier_region_behavior_str = ['multiple', 'virtual '], & - glacier_region_melt_behavior_str = ['replaced_by_ice ', 'remains_in_place']) + glacier_region_melt_behavior_str = ['replaced_by_ice ', 'remains_in_place'], & + glacier_region_ice_runoff_behavior_str = ['remains_ice', 'melted ']) @assertFalse(glc_behavior%has_virtual_columns_grc(bounds%begg)) @assertTrue(glc_behavior%has_virtual_columns_grc(bounds%begg + 1)) @@ -155,6 +195,10 @@ contains @assertTrue(glc_behavior%melt_replaced_by_ice_grc(bounds%begg)) @assertFalse(glc_behavior%melt_replaced_by_ice_grc(bounds%begg + 1)) @assertTrue(glc_behavior%melt_replaced_by_ice_grc(bounds%begg + 2)) + + @assertFalse(glc_behavior%ice_runoff_melted_grc(bounds%begg)) + @assertTrue(glc_behavior%ice_runoff_melted_grc(bounds%begg + 1)) + @assertFalse(glc_behavior%ice_runoff_melted_grc(bounds%begg + 2)) end subroutine init_multipleGridCells ! ------------------------------------------------------------------------ diff --git a/src/main/test/surfrdUtils_test/CMakeLists.txt b/src/main/test/surfrdUtils_test/CMakeLists.txt new file mode 100644 index 0000000000..4139bf6faa --- /dev/null +++ b/src/main/test/surfrdUtils_test/CMakeLists.txt @@ -0,0 +1,4 @@ +create_pFUnit_test(surfrdUtils test_surfrdUtils_exe + "test_surfrdUtils.pf" "") + +target_link_libraries(test_surfrdUtils_exe clm csm_share) diff --git a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf new file mode 100644 index 0000000000..ba9d5cced1 --- /dev/null +++ b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf @@ -0,0 +1,217 @@ +module test_surfrdUtils + + ! Tests of surfrdUtilsMod + + use pfunit_mod + use surfrdUtilsMod + use shr_kind_mod, only : r8 => shr_kind_r8 + + implicit none + save + + real(r8), parameter :: tol = 1.e-14_r8 + +contains + + @Test + subroutine test_convert_cft_to_pft_with_zerocft() + use clm_instur , only : wt_lunit, wt_nat_patch, fert_cft + use pftconMod , only : pftcon, nc3crop, ndllf_evr_tmp_tree, nc3irrig + use pftconMod , only : nbrdlf_evr_shrub, nc4_grass, noveg + use landunit_varcon , only : istsoil, istcrop, max_lunit + use clm_varpar , only : natpft_size, cft_size, numveg + implicit none + integer, parameter :: begg = 2, endg = 3, cftsize = 2 + real(r8) :: wt_cft(begg:endg,cftsize) + real(r8), allocatable :: wtpft(:,:) + + ! Set relevant pftcon values to defaults; these should be overridden by individual + ! tests where they matter + call pftcon%InitForTesting() + wt_cft(begg:,1) = 0.0_r8 + wt_cft(begg:,2) = 0.0_r8 + allocate( wt_lunit(begg:endg,max_lunit) ) + wt_lunit(begg:,:) = 0.00_r8 + wt_lunit(begg:,istsoil) = 100.00_r8 + wt_lunit(begg:,istcrop) = 0.00_r8 + call check_sums_equal_1( (wt_lunit/100.0_r8), begg, "test_check_sums_add_to_1", & + "should not trigger an error") + natpft_size = numveg + cft_size = 0 + noveg = 0 + nc3crop = 15 + nc3irrig = nc3crop + 1 + ndllf_evr_tmp_tree = 1 + nbrdlf_evr_shrub = 9 + nc4_grass = 14 + allocate( wt_nat_patch(begg:endg,0:natpft_size) ) + allocate( wtpft (begg:endg,0:natpft_size) ) + wt_nat_patch(begg:,:) = 0.00_r8 + wt_nat_patch(begg:,noveg) = 5.00_r8 + wt_nat_patch(begg:,ndllf_evr_tmp_tree) = 70.00_r8 + wt_nat_patch(begg:,nbrdlf_evr_shrub) = 20.00_r8 + wt_nat_patch(begg:,nc4_grass) = 5.00_r8 + wtpft = wt_nat_patch/100.0_r8 + call check_sums_equal_1( wtpft, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + wt_nat_patch(begg:,nc3crop:) = -100000.00_r8 ! set crop PFT's to junk, make sure can handle it + ! Convert + call convert_cft_to_pft( begg, endg, cftsize, wt_cft ) + wt_nat_patch(begg:,:) = wt_nat_patch(begg:,:) / 100.00_r8 + wt_lunit(begg:,:) = wt_lunit(begg:,:) / 100.00_r8 + ! Now check that are correct now + call check_sums_equal_1( wt_lunit, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + call check_sums_equal_1( wt_nat_patch, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + @assertEqual(wtpft,wt_nat_patch) + @assertEqual(wt_lunit(begg:,istsoil),(/1.00_r8,1.00_r8/)) + deallocate( wt_nat_patch ) + deallocate( wtpft ) + + call pftcon%clean() + end subroutine test_convert_cft_to_pft_with_zerocft + + @Test + subroutine test_convert_cft_to_pft() + use clm_instur , only : wt_lunit, wt_nat_patch, fert_cft + use pftconMod , only : pftcon, nc3crop, ndllf_evr_tmp_tree, nc3irrig + use landunit_varcon , only : istsoil, istcrop, max_lunit + use clm_varpar , only : natpft_size, cft_size, numveg + + implicit none + integer, parameter :: begg = 2, endg = 3, cftsize = 2 + real(r8) :: wt_cft(begg:endg,cftsize) + + ! Set relevant pftcon values to defaults; these should be overridden by individual + ! tests where they matter + call pftcon%InitForTesting() + wt_cft(begg:,1) = 25.0_r8 + wt_cft(begg:,2) = 75.0_r8 + call check_sums_equal_1( (wt_cft/100.0_r8), begg, "test_check_sums_add_to_1", & + "should not trigger an error") + allocate( wt_lunit(begg:endg,max_lunit) ) + wt_lunit(begg:,:) = 00.00_r8 + wt_lunit(begg:,istsoil) = 25.00_r8 + wt_lunit(begg:,istcrop) = 75.00_r8 + call check_sums_equal_1( (wt_lunit/100.0_r8), begg, "test_check_sums_add_to_1", & + "should not trigger an error") + natpft_size = numveg + cft_size = 0 + nc3crop = 15 + nc3irrig = nc3crop + 1 + ndllf_evr_tmp_tree = 1 + allocate( wt_nat_patch(begg:endg,0:natpft_size) ) + wt_nat_patch(begg:,:) = 0.00_r8 + wt_nat_patch(begg:,ndllf_evr_tmp_tree) = 100.00_r8 + call check_sums_equal_1( (wt_nat_patch/100.0_r8), begg, "test_check_sums_add_to_1", & + "should not trigger an error") + ! Convert + wt_nat_patch(begg:,nc3crop:) = -100000.00_r8 ! set crop PFT's to junk, make sure can handle it + call convert_cft_to_pft( begg, endg, cftsize, wt_cft ) + wt_nat_patch(begg:,:) = wt_nat_patch(begg:,:) / 100.00_r8 + wt_lunit(begg:,:) = wt_lunit(begg:,:) / 100.00_r8 + ! Now check that are correct now + call check_sums_equal_1( wt_lunit, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + call check_sums_equal_1( wt_nat_patch, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + @assertEqual(wt_lunit(begg:,istsoil), (/1.00_r8,1.00_r8/)) + @assertEqual(wt_nat_patch(begg:,ndllf_evr_tmp_tree),(/0.25_r8,0.25_r8/)) + @assertEqual(wt_nat_patch(begg:,nc3crop), (/0.1875_r8,0.1875_r8/)) + @assertEqual(wt_nat_patch(begg:,nc3irrig), (/0.5625_r8,0.5625_r8/)) + + call pftcon%clean() + end subroutine test_convert_cft_to_pft + + @Test + subroutine test_check_sums_add_to_1() + implicit none + integer, parameter :: lb = 10, ub = 12, lb2 = 1, ub2 = 3 + real(r8) :: array(lb:ub,lb2:ub2) + + ! Create an array that sums to one, then copy it twice and + ! make one element off by less than tol and one off by more than tol + ! they should all work this way + array(lb,lb2) = 0.75d00 + array(lb,lb2+1) = 0.20d00 + array(lb,lb2+2) = 0.05d00 + array(lb+1,:) = array(lb,:) + array(lb+1,lb2+2) = array(lb+1,lb2+2) - tol + array(lb+2,:) = array(lb,:) + array(lb+1,lb2+2) = array(lb+1,lb2+2) + tol + call check_sums_equal_1( array, lb, "test_check_sums_add_to_1", & + "should not trigger an error") + end subroutine test_check_sums_add_to_1 + + @Test + subroutine test_check_sums_add_to_1_fail() + implicit none + integer, parameter :: lb = 10, ub = 12, lb2 = 1, ub2 = 3 + real(r8) :: array(lb:ub,lb2:ub2) + real(r8), parameter :: eps = 2.e-13 + integer :: ier + + ! Create an array that sums to one, then copy it twice and + ! then make the last element of the last one off by small + ! value that should trigger an error + array(lb,lb2) = 0.75d00 + array(lb,lb2+1) = 0.20d00 + array(lb,lb2+2) = 0.05d00 + array(lb+1,:) = array(lb,:) + array(lb+1,lb2+2) = array(lb+1,lb2+2) - tol + array(lb+2,:) = array(lb,:) + array(lb+1,lb2+2) = array(lb+1,lb2+2) + eps + call check_sums_equal_1( array, lb, "test_check_sums_add_to_1_fail", & + "should trigger an error", ier) + @assertEqual(ier,-10) + end subroutine test_check_sums_add_to_1_fail + @Test + subroutine test_renormalize + implicit none + integer, parameter :: lb = 10, ub = 12, lb2 = 1, ub2 = 3 + real(r8) :: array(lb:ub,lb2:ub2) + real(r8) :: expected(lb:ub,lb2:ub2) + integer :: ier + + ! Start with an array that sums to 1 within the tolerance + array(lb,lb2) = 0.75d00 + array(lb,lb2+1) = 0.20d00 + array(lb,lb2+2) = 0.05d00 + array(lb+1,:) = array(lb,:) + array(lb+1,lb2+2) = array(lb+1,lb2+2) - tol + array(lb+2,:) = array(lb,:) + array(lb+1,lb2+2) = array(lb+1,lb2+2) + tol + ! Add to the first element of each column a 1 which means the expected + ! result is half of the starting array + array(:,lb2) = array(:,lb2) + 1.0d00 + expected(:,:) = array(:,:) / 2.0d00 + ! Make the normalized result 100, so multiply the expected result by 100 + expected(:,:) = expected(:,:)*100.0d00 + call renormalize(array, lb, 100.0d00) + @assertEqual(array, expected, tolerance=tol) + ! divide by 100 and should add to one + array = array / 100.0d00 + call check_sums_equal_1( array, lb, "test_check_sums_add_to_1", & + "should not trigger an error") + ! Call again returning error code, make sure error code is zero + call check_sums_equal_1( array, lb, "test_check_sums_add_to_1", & + "should not trigger an error", ier) + @assertEqual(ier,0) + end subroutine test_renormalize + + @Test + subroutine test_renormalize_zero + implicit none + integer, parameter :: lb = 10, ub = 12, lb2 = 1, ub2 = 3 + real(r8) :: array(lb:ub,lb2:ub2) + real(r8) :: expected(lb:ub,lb2:ub2) + + ! An array that sums to zero will remain zeroed out + array(:,:) = 0.0d00 + expected(:,:) = array + call renormalize(array, lb, 100.0d00) + @assertEqual(array, expected, tolerance=tol) + end subroutine test_renormalize_zero + +end module test_surfrdUtils diff --git a/src/main/test/topo_test/test_topo.pf b/src/main/test/topo_test/test_topo.pf index 8bf871a83f..b89ee72db8 100644 --- a/src/main/test/topo_test/test_topo.pf +++ b/src/main/test/topo_test/test_topo.pf @@ -12,13 +12,14 @@ module test_topo use filterColMod use clm_instur, only : topo_glc_mec use clm_varpar, only : maxpatch_glcmec - use clm_varctl, only : create_glacier_mec_landunit + use clm_varctl, only : glc_do_dynglacier use landunit_varcon, only : istice_mec use glc2lndMod, only : glc2lnd_type use glcBehaviorMod, only : glc_behavior_type use unittestFilterBuilderMod use ColumnType, only : col use column_varcon, only : col_itype_to_icemec_class + use domainMod, only : ldomain implicit none @@ -26,7 +27,8 @@ module test_topo type, extends(TestCase) :: TestTopo logical :: topo_glc_mec_allocated = .false. logical :: glc2lnd_allocated = .false. - + logical :: ldomain_frac_allocated = .false. + ! These are in TestTopo so they can be cleaned type(glc2lnd_type) :: glc2lnd_inst type(topo_type) :: topo @@ -49,7 +51,7 @@ contains subroutine setUp(this) class(TestTopo), intent(inout) :: this - create_glacier_mec_landunit = .true. + glc_do_dynglacier = .true. call this%setup_glc_mec() end subroutine setUp @@ -57,6 +59,9 @@ contains class(TestTopo), intent(inout) :: this call unittest_subgrid_teardown() + if (this%ldomain_frac_allocated) then + deallocate(ldomain%frac) + end if call teardown_elevation_classes() call this%topo%Clean() if (this%topo_glc_mec_allocated) then @@ -97,14 +102,16 @@ contains this%topo_glc_mec_allocated = .true. end subroutine setup_glc_mec - subroutine init_glc2lnd(this, glc_behavior, icemask_grc) + subroutine init_glc2lnd(this, glc_behavior, topo_grc, icemask_grc) class(TestTopo), intent(inout) :: this type(glc_behavior_type), intent(in) :: glc_behavior + real(r8), intent(in) :: topo_grc(:, 0: ) ! [gridcell, elevclass] array of topo values real(r8), intent(in) :: icemask_grc(:) ! gridcell-level array of icemask values call this%glc2lnd_inst%Init(bounds, glc_behavior) - this%glc2lnd_inst%icemask_grc(:) = icemask_grc(:) this%glc2lnd_allocated = .true. + call this%glc2lnd_inst%for_test_set_glc2lnd_fields_directly(bounds, & + topo = topo_grc, icemask = icemask_grc) end subroutine init_glc2lnd subroutine do_UpdateTopo(this, glc_behavior, icemask_grc, atm_topo_grc, glc_topo) @@ -127,15 +134,25 @@ contains ! if glc_topo isn't given, then glc2lnd_inst%topo_grc will have this value everywhere real(r8), parameter :: glc_topo_default = 17._r8 + real(r8), allocatable :: glc_topo_grc(:,:) ! [gridcell, elevclass] + real(r8), allocatable :: atm_topo(:) type(filter_col_type) :: filter_icemecc - call this%init_glc2lnd(glc_behavior, icemask_grc) + allocate(ldomain%frac(bounds%begg:bounds%endg)) + this%ldomain_frac_allocated = .true. + ldomain%frac(bounds%begg:bounds%endg) = 1._r8 + + allocate(glc_topo_grc(bounds%begg:bounds%endg, 0:maxpatch_glcmec)) if (present(glc_topo)) then - this%glc2lnd_inst%topo_grc(:,:) = glc_topo + glc_topo_grc(:,:) = glc_topo else - this%glc2lnd_inst%topo_grc(:,:) = glc_topo_default + glc_topo_grc(:,:) = glc_topo_default end if + call this%init_glc2lnd( & + glc_behavior=glc_behavior, & + topo_grc = glc_topo_grc, & + icemask_grc=icemask_grc) filter_icemecc = col_filter_from_ltypes(bounds, [istice_mec], include_inactive = .false.) diff --git a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 index c9a402d67a..5d169527c5 100644 --- a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 @@ -4,14 +4,14 @@ module SoilBiogeochemCarbonFluxType use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use decompMod , only : bounds_type use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools, nlevcan - use clm_varpar , only : nlevdecomp_full, nlevgrnd, nlevdecomp + use clm_varpar , only : nlevdecomp_full, nlevgrnd, nlevdecomp, nlevsoi use clm_varcon , only : spval, ispval, dzsoi_decomp use landunit_varcon , only : istsoil, istcrop, istdlak use ch4varcon , only : allowlakeprod use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con use ColumnType , only : col use LandunitType , only : lun - use clm_varctl , only : use_ed + use clm_varctl , only : use_fates ! ! !PUBLIC TYPES: @@ -133,7 +133,7 @@ subroutine InitAllocate(this, bounds) allocate(this%somhr_col (begc:endc)) ; this%somhr_col (:) = nan allocate(this%soilc_change_col (begc:endc)) ; this%soilc_change_col (:) = nan - if ( use_ed ) then + if ( use_fates ) then ! initialize these variables to be zero rather than a bad number since they are not zeroed every timestep (due to a need for them to persist) allocate(this%FATES_c_to_litr_lab_c_col(begc:endc,1:nlevdecomp_full)) @@ -204,20 +204,11 @@ subroutine InitHistory(this, bounds, carbon_type) call hist_addfld1d (fname='LITTERC_HR', units='gC/m^2/s', & avgflag='A', long_name='litter C heterotrophic respiration', & ptr_col=this%lithr_col) - call hist_addfld1d (fname='LITHR', units='gC/m^2/s', & - avgflag='A', long_name='litter heterotrophic respiration', & - ptr_col=this%lithr_col) this%somhr_col(begc:endc) = spval call hist_addfld1d (fname='SOILC_HR', units='gC/m^2/s', & avgflag='A', long_name='soil C heterotrophic respiration', & ptr_col=this%somhr_col) - call hist_addfld1d (fname='SOMHR', units='gC/m^2/s', & - avgflag='A', long_name='soil organic matter heterotrophic respiration', & - ptr_col=this%somhr_col) - call hist_addfld1d (fname='SOILC_LOSS', units='gC/m^2/s', & - avgflag='A', long_name='soil C loss', & - ptr_col=this%somhr_col) if (hist_wrtch4diag) then this%fphr_col(begc:endc,1:nlevgrnd) = spval @@ -268,7 +259,7 @@ subroutine InitHistory(this, bounds, carbon_type) trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_donor_pool(l))) call hist_addfld1d (fname=fieldname, units='gC/m^2/s', & avgflag='A', long_name=longname, & - ptr_col=data1dptr) + ptr_col=data1dptr, default='inactive') endif !-- transfer fluxes (none from terminal pool, if present) @@ -281,7 +272,7 @@ subroutine InitHistory(this, bounds, carbon_type) ' C to '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_receiver_pool(l)))//' C' call hist_addfld1d (fname=fieldname, units='gC/m^2/s', & avgflag='A', long_name=longname, & - ptr_col=data1dptr) + ptr_col=data1dptr, default='inactive') endif ! output the vertically resolved fluxes @@ -330,21 +321,23 @@ subroutine InitHistory(this, bounds, carbon_type) end do - this%t_scalar_col(begc:endc,:) = spval - call hist_addfld_decomp (fname='T_SCALAR', units='unitless', type2d='levdcmp', & - avgflag='A', long_name='temperature inhibition of decomposition', & - ptr_col=this%t_scalar_col) - - this%w_scalar_col(begc:endc,:) = spval - call hist_addfld_decomp (fname='W_SCALAR', units='unitless', type2d='levdcmp', & - avgflag='A', long_name='Moisture (dryness) inhibition of decomposition', & - ptr_col=this%w_scalar_col) - - this%o_scalar_col(begc:endc,:) = spval - call hist_addfld_decomp (fname='O_SCALAR', units='unitless', type2d='levdcmp', & - avgflag='A', long_name='fraction by which decomposition is reduced due to anoxia', & - ptr_col=this%o_scalar_col) - + if ( nlevdecomp_full > 1 ) then + data2dptr => this%t_scalar_col(begc:endc,1:nlevsoi) + call hist_addfld_decomp (fname='T_SCALAR', units='unitless', type2d='levsoi', & + avgflag='A', long_name='temperature inhibition of decomposition', & + ptr_col=data2dptr) + + data2dptr => this%w_scalar_col(begc:endc,1:nlevsoi) + call hist_addfld_decomp (fname='W_SCALAR', units='unitless', type2d='levsoi', & + avgflag='A', long_name='Moisture (dryness) inhibition of decomposition', & + ptr_col=data2dptr) + + data2dptr => this%o_scalar_col(begc:endc,1:nlevsoi) + call hist_addfld_decomp (fname='O_SCALAR', units='unitless', type2d='levsoi', & + avgflag='A', long_name='fraction by which decomposition is reduced due to anoxia', & + ptr_col=data2dptr) + end if + this%som_c_leached_col(begc:endc) = spval call hist_addfld1d (fname='SOM_C_LEACHED', units='gC/m^2/s', & avgflag='A', long_name='total flux of C from SOM pools due to leaching', & @@ -359,7 +352,7 @@ subroutine InitHistory(this, bounds, carbon_type) longname = trim(decomp_cascade_con%decomp_pool_name_long(k))//' C leaching loss' call hist_addfld1d (fname=fieldname, units='gC/m^2/s', & avgflag='A', long_name=longname, & - ptr_col=data1dptr)!, default='inactive') + ptr_col=data1dptr, default='inactive') data2dptr => this%decomp_cpools_transport_tendency_col(:,:,k) fieldname = trim(decomp_cascade_con%decomp_pool_name_history(k))//'C_TNDNCY_VERT_TRANSPORT' @@ -371,10 +364,10 @@ subroutine InitHistory(this, bounds, carbon_type) end do if ( nlevdecomp_full > 1 ) then - this%hr_vr_col(begc:endc,:) = spval - call hist_addfld2d (fname='HR_vr', units='gC/m^3/s', type2d='levdcmp', & + data2dptr => this%hr_vr_col(begc:endc,1:nlevsoi) + call hist_addfld2d (fname='HR_vr', units='gC/m^3/s', type2d='levsoi', & avgflag='A', long_name='total vertically resolved heterotrophic respiration', & - ptr_col=this%hr_vr_col) + ptr_col=data2dptr) endif end if @@ -391,12 +384,12 @@ subroutine InitHistory(this, bounds, carbon_type) ptr_col=this%hr_col) this%lithr_col(begc:endc) = spval - call hist_addfld1d (fname='C13_LITHR', units='gC13/m^2/s', & + call hist_addfld1d (fname='C13_LITTERC_HR', units='gC13/m^2/s', & avgflag='A', long_name='C13 fine root C litterfall to litter 3 C', & ptr_col=this%lithr_col) this%somhr_col(begc:endc) = spval - call hist_addfld1d (fname='C13_SOMHR', units='gC13/m^2/s', & + call hist_addfld1d (fname='C13_SOILC_HR', units='gC13/m^2/s', & avgflag='A', long_name='C13 soil organic matter heterotrophic respiration', & ptr_col=this%somhr_col) @@ -461,12 +454,12 @@ subroutine InitHistory(this, bounds, carbon_type) ptr_col=this%hr_col) this%lithr_col(begc:endc) = spval - call hist_addfld1d (fname='C14_LITHR', units='gC14/m^2/s', & - avgflag='A', long_name='C14 fine root C litterfall to litter 3 C', & + call hist_addfld1d (fname='C14_LITTERC_HR', units='gC14/m^2/s', & + avgflag='A', long_name='C14 litter carbon heterotrophic respiration', & ptr_col=this%lithr_col) this%somhr_col(begc:endc) = spval - call hist_addfld1d (fname='C14_SOMHR', units='gC14/m^2/s', & + call hist_addfld1d (fname='C14_SOILC_HR', units='gC14/m^2/s', & avgflag='A', long_name='C14 soil organic matter heterotrophic respiration', & ptr_col=this%somhr_col) @@ -536,7 +529,7 @@ subroutine InitHistory(this, bounds, carbon_type) end do - if ( use_ed ) then + if ( use_fates ) then call hist_addfld_decomp(fname='FATES_c_to_litr_lab_c', units='gC/m^3/s', type2d='levdcmp', & avgflag='A', long_name='litter labile carbon flux from FATES to BGC', & @@ -610,7 +603,7 @@ subroutine Restart(this, bounds, ncid, flag) ! if FATES is enabled, need to restart the variables used to transfer from FATES to CLM as they ! are persistent between daily FATES dynamics calls and half-hourly CLM timesteps ! - if ( use_ed ) then + if ( use_fates ) then if (use_vertsoilc) then ptr2d => this%FATES_c_to_litr_lab_c_col @@ -714,7 +707,7 @@ subroutine SetValues ( this, num_column, filter_column, value_column) this%soilc_change_col(i) = value_column end do - ! NOTE: do not zero the ED to BGC C flux variables since they need to persist from the daily ED timestep s to the half-hourly BGC timesteps. I.e. FATES_c_to_litr_lab_c_col, FATES_c_to_litr_cel_c_col, FATES_c_to_litr_lig_c_col + ! NOTE: do not zero the fates to BGC C flux variables since they need to persist from the daily fates timestep s to the half-hourly BGC timesteps. I.e. FATES_c_to_litr_lab_c_col, FATES_c_to_litr_cel_c_col, FATES_c_to_litr_lig_c_col end subroutine SetValues diff --git a/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 b/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 index 8764121bda..78be5efd44 100644 --- a/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCarbonStateType.F90 @@ -5,9 +5,9 @@ module SoilBiogeochemCarbonStateType use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools, nlevcan - use clm_varpar , only : nlevdecomp_full, nlevdecomp + use clm_varpar , only : nlevdecomp_full, nlevdecomp, nlevsoi use clm_varcon , only : spval, ispval, dzsoi_decomp, zisoi, zsoi, c3_r2 - use clm_varctl , only : iulog, use_vertsoilc, spinup_state, use_ed + use clm_varctl , only : iulog, use_vertsoilc, spinup_state, use_fates use landunit_varcon , only : istcrop, istsoil use abortutils , only : endrun use spmdMod , only : masterproc @@ -37,6 +37,8 @@ module SoilBiogeochemCarbonStateType real(r8), pointer :: decomp_cpools_1m_col (:,:) ! (gC/m2) Diagnostic: decomposing (litter, cwd, soil) c pools to 1 meter real(r8), pointer :: decomp_cpools_col (:,:) ! (gC/m2) decomposing (litter, cwd, soil) c pools real(r8), pointer :: dyn_cbal_adjustments_col (:) ! (gC/m2) adjustments to each column made in this timestep via dynamic column area adjustments (note: this variable only makes sense at the column-level: it is meaningless if averaged to the gridcell-level) + integer :: restart_file_spinup_state ! spinup state as read from restart file, for determining whether to enter or exit spinup mode. + real(r8) :: totvegcthresh ! threshold for total vegetation carbon to zero out decomposition pools contains @@ -44,11 +46,13 @@ module SoilBiogeochemCarbonStateType procedure , public :: SetValues procedure , public :: Restart procedure , public :: Summary + procedure , public :: SetTotVgCThresh procedure , public :: DynamicColumnAdjustments ! adjust state variables when column areas change procedure , private :: InitAllocate procedure , private :: InitHistory procedure , private :: InitCold + end type soilbiogeochem_carbonstate_type character(len=*), parameter, private :: sourcefile = & @@ -66,6 +70,7 @@ subroutine Init(this, bounds, carbon_type, ratio, c12_soilbiogeochem_carbonstate real(r8) , intent(in) :: ratio type(soilbiogeochem_carbonstate_type) , intent(in), optional :: c12_soilbiogeochem_carbonstate_inst + this%totvegcthresh = nan call this%InitAllocate ( bounds) call this%InitHistory ( bounds, carbon_type ) if (present(c12_soilbiogeochem_carbonstate_inst)) then @@ -99,7 +104,7 @@ subroutine InitAllocate(this, bounds) this%decomp_cpools_vr_col(:,:,:)= nan allocate(this%ctrunc_col (begc :endc)) ; this%ctrunc_col (:) = nan - if ( .not. use_ed ) then + if ( .not. use_fates ) then allocate(this%cwdc_col (begc :endc)) ; this%cwdc_col (:) = nan endif allocate(this%totlitc_col (begc :endc)) ; this%totlitc_col (:) = nan @@ -108,6 +113,8 @@ subroutine InitAllocate(this, bounds) allocate(this%totsomc_1m_col (begc :endc)) ; this%totsomc_1m_col (:) = nan allocate(this%dyn_cbal_adjustments_col (begc:endc)) ; this%dyn_cbal_adjustments_col (:) = nan + this%restart_file_spinup_state = huge(1) + end subroutine InitAllocate !------------------------------------------------------------------------ @@ -141,10 +148,10 @@ subroutine InitHistory(this, bounds, carbon_type) this%decomp_cpools_col(begc:endc,:) = spval do l = 1, ndecomp_pools if ( nlevdecomp_full > 1 ) then - data2dptr => this%decomp_cpools_vr_col(:,:,l) + data2dptr => this%decomp_cpools_vr_col(:,1:nlevsoi,l) fieldname = trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_vr' longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' C (vertically resolved)' - call hist_addfld2d (fname=fieldname, units='gC/m^3', type2d='levdcmp', & + call hist_addfld2d (fname=fieldname, units='gC/m^3', type2d='levsoi', & avgflag='A', long_name=longname, & ptr_col=data2dptr) endif @@ -162,14 +169,11 @@ subroutine InitHistory(this, bounds, carbon_type) longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' C to 1 meter' call hist_addfld1d (fname=fieldname, units='gC/m^2', & avgflag='A', long_name=longname, & - ptr_col=data1dptr, default = 'inactive') + ptr_col=data1dptr, default='inactive') endif end do this%totlitc_col(begc:endc) = spval - call hist_addfld1d (fname='LITTERC', units='gC/m^2', & - avgflag='A', long_name='litter C', & - ptr_col=this%totlitc_col) call hist_addfld1d (fname='TOTLITC', units='gC/m^2', & avgflag='A', long_name='total litter carbon', & ptr_col=this%totlitc_col) @@ -178,9 +182,6 @@ subroutine InitHistory(this, bounds, carbon_type) call hist_addfld1d (fname='TOTSOMC', units='gC/m^2', & avgflag='A', long_name='total soil organic matter carbon', & ptr_col=this%totsomc_col) - call hist_addfld1d (fname='SOILC', units='gC/m^2', & - avgflag='A', long_name='soil C', & - ptr_col=this%totsomc_col) if ( nlevdecomp_full > 1 ) then this%totlitc_1m_col(begc:endc) = spval @@ -199,7 +200,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%ctrunc_col(begc:endc) = spval call hist_addfld1d (fname='COL_CTRUNC', units='gC/m^2', & avgflag='A', long_name='column-level sink for C truncation', & - ptr_col=this%ctrunc_col) + ptr_col=this%ctrunc_col, default='inactive') this%dyn_cbal_adjustments_col(begc:endc) = spval call hist_addfld1d (fname='DYN_COL_SOIL_ADJUSTMENTS_C', units='gC/m^2', & @@ -219,12 +220,12 @@ subroutine InitHistory(this, bounds, carbon_type) this%decomp_cpools_vr_col(begc:endc,:,:) = spval do l = 1, ndecomp_pools if ( nlevdecomp_full > 1 ) then - data2dptr => this%decomp_cpools_vr_col(:,:,l) + data2dptr => this%decomp_cpools_vr_col(:,1:nlevsoi,l) fieldname = 'C13_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_vr' longname = 'C13 '//trim(decomp_cascade_con%decomp_pool_name_history(l))//' C (vertically resolved)' - call hist_addfld2d (fname=fieldname, units='gC13/m^3', type2d='levdcmp', & + call hist_addfld2d (fname=fieldname, units='gC13/m^3', type2d='levsoi', & avgflag='A', long_name=longname, & - ptr_col=data2dptr) + ptr_col=data2dptr, default='inactive') endif data1dptr => this%decomp_cpools_col(:,l) @@ -262,7 +263,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%ctrunc_col(begc:endc) = spval call hist_addfld1d (fname='C13_COL_CTRUNC', units='gC13/m^2', & avgflag='A', long_name='C13 column-level sink for C truncation', & - ptr_col=this%ctrunc_col) + ptr_col=this%ctrunc_col, default='inactive') this%dyn_cbal_adjustments_col(begc:endc) = spval call hist_addfld1d (fname='C13_DYN_COL_SOIL_ADJUSTMENTS_C', units='gC13/m^2', & @@ -281,11 +282,11 @@ subroutine InitHistory(this, bounds, carbon_type) this%decomp_cpools_vr_col(begc:endc,:,:) = spval do l = 1, ndecomp_pools if ( nlevdecomp_full > 1 ) then - data2dptr => this%decomp_cpools_vr_col(:,:,l) + data2dptr => this%decomp_cpools_vr_col(:,1:nlevsoi,l) fieldname = 'C14_'//trim(decomp_cascade_con%decomp_pool_name_history(l))//'C_vr' longname = 'C14 '//trim(decomp_cascade_con%decomp_pool_name_history(l))//' C (vertically resolved)' - call hist_addfld2d (fname=fieldname, units='gC14/m^3', type2d='levdcmp', & - avgflag='A', long_name=longname, ptr_col=data2dptr) + call hist_addfld2d (fname=fieldname, units='gC14/m^3', type2d='levsoi', & + avgflag='A', long_name=longname, ptr_col=data2dptr, default='inactive') endif data1dptr => this%decomp_cpools_col(:,l) @@ -328,7 +329,7 @@ subroutine InitHistory(this, bounds, carbon_type) this%ctrunc_col(begc:endc) = spval call hist_addfld1d (fname='C14_COL_CTRUNC', units='gC14/m^2', & avgflag='A', long_name='C14 column-level sink for C truncation', & - ptr_col=this%ctrunc_col) + ptr_col=this%ctrunc_col, default='inactive') this%dyn_cbal_adjustments_col(begc:endc) = spval call hist_addfld1d (fname='C14_DYN_COL_SOIL_ADJUSTMENTS_C', units='gC14/m^2', & @@ -371,7 +372,7 @@ subroutine InitCold(this, bounds, ratio, c12_soilbiogeochem_carbonstate_inst) do j = 1, nlevdecomp do k = 1, ndecomp_pools - if (zsoi(j) < 0.3 ) then !! only initialize upper soil column + if (zsoi(j) < decomp_cascade_con%initial_stock_soildepth ) then !! only initialize upper soil column this%decomp_cpools_vr_col(c,j,k) = decomp_cascade_con%initial_stock(k) else this%decomp_cpools_vr_col(c,j,k) = 0._r8 @@ -414,7 +415,7 @@ subroutine InitCold(this, bounds, ratio, c12_soilbiogeochem_carbonstate_inst) endif end if - if ( .not. use_ed ) then + if ( .not. use_fates ) then if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then if (present(c12_soilbiogeochem_carbonstate_inst)) then this%cwdc_col(c) = c12_soilbiogeochem_carbonstate_inst%cwdc_col(c) * ratio @@ -451,16 +452,16 @@ subroutine InitCold(this, bounds, ratio, c12_soilbiogeochem_carbonstate_inst) end subroutine InitCold !----------------------------------------------------------------------- - subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_carbonstate_inst ) + subroutine Restart ( this, bounds, ncid, flag, carbon_type, totvegc_col, c12_soilbiogeochem_carbonstate_inst ) ! ! !DESCRIPTION: ! Read/write CN restart data for carbon state ! ! !USES: - use shr_infnan_mod , only : isnan => shr_infnan_isnan, nan => shr_infnan_nan, assignment(=) - use clm_time_manager , only : is_restart, get_nstep - use shr_const_mod , only : SHR_CONST_PDB - use clm_varcon , only : c14ratio + use shr_infnan_mod , only : isnan => shr_infnan_isnan, nan => shr_infnan_nan, assignment(=) + use clm_time_manager , only : is_restart, get_nstep + use shr_const_mod , only : SHR_CONST_PDB + use clm_varcon , only : c14ratio use restUtilMod use ncdio_pio ! @@ -470,7 +471,10 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_ type(file_desc_t) , intent(inout) :: ncid ! netcdf id character(len=*) , intent(in) :: flag !'read' or 'write' character(len=3) , intent(in) :: carbon_type ! 'c12' or 'c13' or 'c14' + real(r8) , intent(in) :: totvegc_col(bounds%begc:bounds%endc) ! (gC/m2) total + ! vegetation carbon type(soilbiogeochem_carbonstate_type) , intent(in), optional :: c12_soilbiogeochem_carbonstate_inst + ! ! !LOCAL VARIABLES: integer :: i,j,k,l,c @@ -482,8 +486,6 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_ integer :: idata logical :: exit_spinup = .false. logical :: enter_spinup = .false. - ! spinup state as read from restart file, for determining whether to enter or exit spinup mode. - integer :: restart_file_spinup_state ! flags for comparing the model and restart decomposition cascades integer :: decomp_cascade_state, restart_file_decomp_cascade_state !------------------------------------------------------------------------ @@ -629,28 +631,24 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_ ! Spinup state !-------------------------------- - if (carbon_type == 'c12') then - if (flag == 'write') then - idata = spinup_state - end if - call restartvar(ncid=ncid, flag=flag, varname='spinup_state', xtype=ncd_int, & + + if (carbon_type == 'c12') then + if (flag == 'write') idata = spinup_state + call restartvar(ncid=ncid, flag=flag, varname='spinup_state', xtype=ncd_int, & long_name='Spinup state of the model that wrote this restart file: ' & // ' 0 = normal model mode, 1 = AD spinup', units='', & interpinic_flag='copy', readvar=readvar, data=idata) - if (flag == 'read') then - if (readvar) then - restart_file_spinup_state = idata - else - ! assume, for sake of backwards compatibility, that if spinup_state is not in - ! the restart file then current model state is the same as prior model state - restart_file_spinup_state = spinup_state - if ( masterproc ) then - write(iulog,*) ' CNRest: WARNING! Restart file does not contain info ' & - // ' on spinup state used to generate the restart file. ' - write(iulog,*) ' Assuming the same as current setting: ', spinup_state + if (flag == 'read') then + if (readvar) then + this%restart_file_spinup_state = idata + else + call endrun(msg=' CNRest: spinup_state was not on the restart file and is required' // & + errMsg(sourcefile, __LINE__)) end if end if - end if + else + this%restart_file_spinup_state = c12_soilbiogeochem_carbonstate_inst%restart_file_spinup_state + endif ! now compare the model and restart file spinup states, and either take the ! model into spinup mode or out of it if they are not identical @@ -660,12 +658,12 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_ ! by the associated AD factor. ! only allow this to occur on first timestep of model run. - if (flag == 'read' .and. spinup_state /= restart_file_spinup_state ) then - if (spinup_state == 0 .and. restart_file_spinup_state >= 1 ) then - if ( masterproc ) write(iulog,*) ' CNRest: taking SOM pools out of AD spinup mode' + if (flag == 'read' .and. spinup_state /= this%restart_file_spinup_state ) then + if (spinup_state == 0 .and. this%restart_file_spinup_state >= 1 ) then + if ( masterproc ) write(iulog,*) ' CNRest: taking ',carbon_type,' SOM pools out of AD spinup mode' exit_spinup = .true. - else if (spinup_state >= 1 .and. restart_file_spinup_state == 0 ) then - if ( masterproc ) write(iulog,*) ' CNRest: taking SOM pools into AD spinup mode' + else if (spinup_state >= 1 .and. this%restart_file_spinup_state == 0 ) then + if ( masterproc ) write(iulog,*) ' CNRest: taking ',carbon_type,' SOM pools into AD spinup mode' enter_spinup = .true. else call endrun(msg=' CNRest: error in entering/exiting spinup. spinup_state ' & @@ -676,6 +674,10 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_ call endrun(msg=' CNRest: error in entering/exiting spinup - should occur only when nstep = 1'//& errMsg(sourcefile, __LINE__)) endif + if ( exit_spinup .and. isnan(this%totvegcthresh) )then + call endrun(msg=' CNRest: error in exit spinup - totvegcthresh was not set with SetTotVgCThresh'//& + errMsg(sourcefile, __LINE__)) + end if do k = 1, ndecomp_pools if ( exit_spinup ) then m = decomp_cascade_con%spinup_factor(k) @@ -683,10 +685,18 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_ m = 1. / decomp_cascade_con%spinup_factor(k) end if do c = bounds%begc, bounds%endc + l = col%landunit(c) do j = 1, nlevdecomp_full if ( abs(m - 1._r8) .gt. 0.000001_r8 .and. exit_spinup) then this%decomp_cpools_vr_col(c,j,k) = this%decomp_cpools_vr_col(c,j,k) * m * & get_spinup_latitude_term(grc%latdeg(col%gridcell(c))) + ! If there is no vegetation carbon, implying that all vegetation has died, then + ! reset decomp pools to near zero during exit_spinup to avoid very + ! large and inert soil carbon stocks; note that only pools with spinup factor > 1 + ! will be affected, which means that total SOMC and LITC pools will not be set to 0. + if (totvegc_col(c) <= this%totvegcthresh .and. lun%itype(l) /= istcrop) then + this%decomp_cpools_vr_col(c,j,k) = 0.0_r8 + endif elseif ( abs(m - 1._r8) .gt. 0.000001_r8 .and. enter_spinup) then this%decomp_cpools_vr_col(c,j,k) = this%decomp_cpools_vr_col(c,j,k) * m / & get_spinup_latitude_term(grc%latdeg(col%gridcell(c))) @@ -697,7 +707,6 @@ subroutine Restart ( this, bounds, ncid, flag, carbon_type, c12_soilbiogeochem_ end do end do end if - end if end subroutine Restart @@ -719,7 +728,7 @@ subroutine SetValues ( this, num_column, filter_column, value_column) do fi = 1,num_column i = filter_column(fi) - if ( .not. use_ed ) then + if ( .not. use_fates ) then this%cwdc_col(i) = value_column end if this%ctrunc_col(i) = value_column @@ -899,7 +908,7 @@ subroutine Summary(this, bounds, num_allc, filter_allc) end do ! coarse woody debris carbon - if (.not. use_ed ) then + if (.not. use_fates ) then do fc = 1,num_allc c = filter_allc(fc) this%cwdc_col(c) = 0._r8 @@ -917,8 +926,23 @@ subroutine Summary(this, bounds, num_allc, filter_allc) end subroutine Summary + !------------------------------------------------------------------------ + subroutine SetTotVgCThresh(this, totvegcthresh) + + class(soilbiogeochem_carbonstate_type) :: this + real(r8) , intent(in) :: totvegcthresh + + if ( totvegcthresh <= 0.0_r8 )then + call endrun(msg=' ERROR totvegcthresh is zero or negative and should be > 0'//& + errMsg(sourcefile, __LINE__)) + end if + this%totvegcthresh = totvegcthresh + + end subroutine SetTotVgCThresh + + !----------------------------------------------------------------------- - subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) + subroutine DynamicColumnAdjustments(this, bounds, clump_index, column_state_updater) ! ! !DESCRIPTION: ! Adjust state variables when column areas change due to dynamic landuse @@ -929,6 +953,11 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) ! !ARGUMENTS: class(soilbiogeochem_carbonstate_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer , intent(in) :: clump_index + type(column_state_updater_type) , intent(in) :: column_state_updater ! ! !LOCAL VARIABLES: @@ -949,6 +978,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) do j = 1, nlevdecomp call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%decomp_cpools_vr_col(begc:endc, j, l), & adjustment = adjustment_one_level(begc:endc)) this%dyn_cbal_adjustments_col(begc:endc) = & @@ -960,6 +990,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) do j = 1, nlevdecomp call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%ctrunc_vr_col(begc:endc, j), & adjustment = adjustment_one_level(begc:endc)) this%dyn_cbal_adjustments_col(begc:endc) = & diff --git a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 index 5bbfab64d9..0094cfb561 100644 --- a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 @@ -775,7 +775,10 @@ subroutine SoilBiogeochemCompetition (bounds, num_soilc, filter_soilc,num_soilp, sminn_to_plant_fun_no3_vr(c,j),smin_no3_to_plant_vr(c,j) call endrun("too much NO3 uptake predicted by FUN") end if - if ((sminn_to_plant_fun_nh4_vr(c,j)-smin_nh4_to_plant_vr(c,j)).gt.0.0000000000001_r8) then +!KO if ((sminn_to_plant_fun_nh4_vr(c,j)-smin_nh4_to_plant_vr(c,j)).gt.0.0000000000001_r8) then +!KO + if ((sminn_to_plant_fun_nh4_vr(c,j)-smin_nh4_to_plant_vr(c,j)).gt.0.0000001_r8) then +!KO write(iulog,*) 'problem with limitations on nh4 uptake', & sminn_to_plant_fun_nh4_vr(c,j),smin_nh4_to_plant_vr(c,j) call endrun("too much NH4 uptake predicted by FUN") diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 index 2777a5e1e4..f5be1aad37 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeBGCMod.F90 @@ -11,7 +11,7 @@ module SoilBiogeochemDecompCascadeBGCMod use shr_log_mod , only : errMsg => shr_log_errMsg use clm_varpar , only : nlevsoi, nlevgrnd, nlevdecomp, ndecomp_cascade_transitions, ndecomp_pools use clm_varpar , only : i_met_lit, i_cel_lit, i_lig_lit, i_cwd - use clm_varctl , only : iulog, spinup_state, anoxia, use_lch4, use_vertsoilc, use_ed + use clm_varctl , only : iulog, spinup_state, anoxia, use_lch4, use_vertsoilc, use_fates use clm_varcon , only : zsoi use decompMod , only : bounds_type use spmdMod , only : masterproc @@ -27,7 +27,7 @@ module SoilBiogeochemDecompCascadeBGCMod use ColumnType , only : col use GridcellType , only : grc use SoilBiogeochemStateType , only : get_spinup_latitude_term - use EDCLMLinkMod , only : cwd_fcel_ed, cwd_flig_ed + ! implicit none private @@ -84,6 +84,7 @@ module SoilBiogeochemDecompCascadeBGCMod real(r8) :: maxpsi_bgc !maximum soil water potential for heterotrophic resp real(r8) :: initial_Cstocks(nsompools) ! Initial Carbon stocks for a cold-start + real(r8) :: initial_Cstocks_depth ! Soil depth for initial Carbon stocks for a cold-start end type params_type ! @@ -121,13 +122,14 @@ subroutine DecompCascadeBGCreadNML( NLFilename ) character(len=*), parameter :: subname = 'DecompCascadeBGCreadNML' character(len=*), parameter :: nmlname = 'CENTURY_soilBGCDecompCascade' !----------------------------------------------------------------------- - real(r8) :: initial_Cstocks(nsompools) - namelist /CENTURY_soilBGCDecompCascade/ initial_Cstocks + real(r8) :: initial_Cstocks(nsompools), initial_Cstocks_depth + namelist /CENTURY_soilBGCDecompCascade/ initial_Cstocks, initial_Cstocks_depth ! Initialize options to default values, in case they are not specified in ! the namelist - initial_Cstocks(:) = 200._r8 + initial_Cstocks(:) = 200._r8 + initial_Cstocks_depth = 0.3 if (masterproc) then unitn = getavu() @@ -145,7 +147,8 @@ subroutine DecompCascadeBGCreadNML( NLFilename ) call relavu( unitn ) end if - call shr_mpi_bcast (initial_Cstocks, mpicom) + call shr_mpi_bcast (initial_Cstocks , mpicom) + call shr_mpi_bcast (initial_Cstocks_depth, mpicom) if (masterproc) then write(iulog,*) ' ' @@ -154,7 +157,8 @@ subroutine DecompCascadeBGCreadNML( NLFilename ) write(iulog,*) ' ' end if - params_inst%initial_Cstocks(:) = initial_Cstocks(:) + params_inst%initial_Cstocks(:) = initial_Cstocks(:) + params_inst%initial_Cstocks_depth = initial_Cstocks_depth end subroutine DecompCascadeBGCreadNML @@ -288,11 +292,6 @@ subroutine readParams ( ncid ) if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) params_inst%cwd_flig_bgc=tempr - if ( use_ed ) then - cwd_fcel_ed = params_inst%cwd_fcel_bgc - cwd_flig_ed = params_inst%cwd_flig_bgc - endif - end subroutine readParams !----------------------------------------------------------------------- @@ -371,6 +370,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i is_cwd => decomp_cascade_con%is_cwd , & ! Output: [logical (:) ] TRUE => pool is a cwd pool initial_cn_ratio => decomp_cascade_con%initial_cn_ratio , & ! Output: [real(r8) (:) ] c:n ratio for initialization of pools initial_stock => decomp_cascade_con%initial_stock , & ! Output: [real(r8) (:) ] initial concentration for seeding at spinup + initial_stock_soildepth => decomp_cascade_con%initial_stock_soildepth , & ! Output: [real(r8) (:) ] soil depth for initial concentration for seeding at spinup is_metabolic => decomp_cascade_con%is_metabolic , & ! Output: [logical (:) ] TRUE => pool is metabolic material is_cellulose => decomp_cascade_con%is_cellulose , & ! Output: [logical (:) ] TRUE => pool is cellulose is_lignin => decomp_cascade_con%is_lignin , & ! Output: [logical (:) ] TRUE => pool is lignin @@ -418,6 +418,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i rf_s1s3(c,j) = t end do end do + initial_stock_soildepth = params_inst%initial_Cstocks_depth !------------------- list of pools and their attributes ------------ floating_cn_ratio_decomp_pools(i_litr1) = .true. @@ -462,7 +463,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i is_cellulose(i_litr3) = .false. is_lignin(i_litr3) = .true. - if (.not. use_ed) then + if (.not. use_fates) then ! CWD floating_cn_ratio_decomp_pools(i_cwd) = .true. decomp_pool_name_restart(i_cwd) = 'cwd' @@ -479,7 +480,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i is_lignin(i_cwd) = .false. endif - if (.not. use_ed) then + if (.not. use_fates) then i_soil1 = 5 else i_soil1 = 4 @@ -498,7 +499,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i is_cellulose(i_soil1) = .false. is_lignin(i_soil1) = .false. - if (.not. use_ed) then + if (.not. use_fates) then i_soil2 = 6 else i_soil2 = 5 @@ -517,7 +518,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i is_cellulose(i_soil2) = .false. is_lignin(i_soil2) = .false. - if (.not. use_ed) then + if (.not. use_fates) then i_soil3 = 7 else i_soil3 = 6 @@ -545,7 +546,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i spinup_factor(i_litr2) = 1._r8 spinup_factor(i_litr3) = 1._r8 !CWD - if (.not. use_ed) then + if (.not. use_fates) then spinup_factor(i_cwd) = max(1._r8, (speedup_fac * params_inst%tau_cwd_bgc / 2._r8 )) end if !som1 @@ -616,7 +617,7 @@ subroutine init_decompcascade_bgc(bounds, soilbiogeochem_state_inst, soilstate_i cascade_receiver_pool(i_s3s1) = i_soil1 pathfrac_decomp_cascade(bounds%begc:bounds%endc,1:nlevdecomp,i_s3s1) = 1.0_r8 - if (.not. use_ed) then + if (.not. use_fates) then i_cwdl2 = 9 cascade_step_name(i_cwdl2) = 'CWDL2' rf_decomp_cascade(bounds%begc:bounds%endc,1:nlevdecomp,i_cwdl2) = rf_cwdl2 @@ -795,7 +796,7 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & spinup_geogterm_l23(c) = 1._r8 endif ! - if ( .not. use_ed ) then + if ( .not. use_fates ) then if ( abs(spinup_factor(i_cwd) - 1._r8) .gt. .000001_r8) then spinup_geogterm_cwd(c) = spinup_factor(i_cwd) * get_spinup_latitude_term(grc%latdeg(col%gridcell(c))) else @@ -1096,8 +1097,8 @@ subroutine decomp_rate_constants_bgc(bounds, num_soilc, filter_soilc, & end do end if - ! do the same for cwd, but only if ed is not enabled, because ED handles CWD on its own structure - if (.not. use_ed) then + ! do the same for cwd, but only if fates is not enabled, because fates handles CWD on its own structure + if (.not. use_fates) then if (use_vertsoilc) then do j = 1,nlevdecomp do fc = 1,num_soilc diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeCNMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeCNMod.F90 index 09e0046a13..dc01989d57 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeCNMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeCNMod.F90 @@ -11,7 +11,7 @@ module SoilBiogeochemDecompCascadeCNMod use shr_log_mod , only : errMsg => shr_log_errMsg use clm_varpar , only : nlevsoi, nlevgrnd, nlevdecomp, ndecomp_cascade_transitions, ndecomp_pools use clm_varpar , only : i_met_lit, i_cel_lit, i_lig_lit, i_cwd - use clm_varctl , only : iulog, spinup_state, anoxia, use_lch4, use_vertsoilc, use_ed + use clm_varctl , only : iulog, spinup_state, anoxia, use_lch4, use_vertsoilc, use_fates use clm_varcon , only : zsoi use decompMod , only : bounds_type use abortutils , only : endrun @@ -24,7 +24,7 @@ module SoilBiogeochemDecompCascadeCNMod use TemperatureType , only : temperature_type use ch4Mod , only : ch4_type use ColumnType , only : col - use EDCLMLinkMod , only : cwd_fcel_ed, cwd_flig_ed + ! implicit none private @@ -215,11 +215,6 @@ subroutine readParams ( ncid ) if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) params_inst%cwd_flig_cn=tempr - if ( use_ed ) then - cwd_fcel_ed = params_inst%cwd_fcel_cn - cwd_flig_ed = params_inst%cwd_flig_cn - endif - end subroutine readParams !----------------------------------------------------------------------- @@ -357,7 +352,7 @@ subroutine init_decompcascade_cn(bounds, soilbiogeochem_state_inst) is_cellulose(i_litr3) = .false. is_lignin(i_litr3) = .true. - if (.not. use_ed) then + if (.not. use_fates) then floating_cn_ratio_decomp_pools(i_cwd) = .true. decomp_pool_name_restart(i_cwd) = 'cwd' decomp_pool_name_history(i_cwd) = 'CWD' @@ -373,7 +368,7 @@ subroutine init_decompcascade_cn(bounds, soilbiogeochem_state_inst) is_lignin(i_cwd) = .false. end if - if ( .not. use_ed ) then + if ( .not. use_fates ) then i_soil1 = 5 else i_soil1 = 4 @@ -392,7 +387,7 @@ subroutine init_decompcascade_cn(bounds, soilbiogeochem_state_inst) is_cellulose(i_soil1) = .false. is_lignin(i_soil1) = .false. - if ( .not. use_ed ) then + if ( .not. use_fates ) then i_soil2 = 6 else i_soil2 = 5 @@ -411,7 +406,7 @@ subroutine init_decompcascade_cn(bounds, soilbiogeochem_state_inst) is_cellulose(i_soil2) = .false. is_lignin(i_soil2) = .false. - if ( .not. use_ed ) then + if ( .not. use_fates ) then i_soil3 = 7 else i_soil3 = 6 @@ -430,7 +425,7 @@ subroutine init_decompcascade_cn(bounds, soilbiogeochem_state_inst) is_cellulose(i_soil3) = .false. is_lignin(i_soil3) = .false. - if ( .not. use_ed ) then + if ( .not. use_fates ) then i_soil4 = 8 else i_soil4 = 7 @@ -468,7 +463,7 @@ subroutine init_decompcascade_cn(bounds, soilbiogeochem_state_inst) spinup_factor(i_litr1) = 1._r8 spinup_factor(i_litr2) = 1._r8 spinup_factor(i_litr3) = 1._r8 - if (.not. use_ed) then + if (.not. use_fates) then spinup_factor(i_cwd) = 1._r8 end if spinup_factor(i_soil1) = params_inst%spinup_vector(1) @@ -527,7 +522,7 @@ subroutine init_decompcascade_cn(bounds, soilbiogeochem_state_inst) cascade_receiver_pool(i_s4atm) = i_atm pathfrac_decomp_cascade(bounds%begc:bounds%endc,1:nlevdecomp,i_s4atm) = 1.0_r8 - if (.not. use_ed) then + if (.not. use_fates) then i_cwdl2 = 8 cascade_step_name(i_cwdl2) = 'CWDL2' rf_decomp_cascade(bounds%begc:bounds%endc,1:nlevdecomp,i_cwdl2) = 0._r8 @@ -694,7 +689,7 @@ subroutine decomp_rate_constants_cn(bounds, & i_litr1 = 1 i_litr2 = 2 i_litr3 = 3 - if (use_ed) then + if (use_fates) then i_soil1 = 4 i_soil2 = 5 i_soil3 = 6 @@ -936,8 +931,8 @@ subroutine decomp_rate_constants_cn(bounds, & end do end if - ! do the same for cwd, but only if ed is not enabled (because ED handles CWD on its own structure - if (.not. use_ed) then + ! do the same for cwd, but only if fates is not enabled (because fates handles CWD on its own structure + if (.not. use_fates) then if (use_vertsoilc) then do j = 1,nlevdecomp do fc = 1,num_soilc diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 index 283094bb69..8a8e2f8dfa 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeConType.F90 @@ -32,6 +32,7 @@ module SoilBiogeochemDecompCascadeConType logical , pointer :: is_cwd(:) ! TRUE => pool is a cwd pool real(r8) , pointer :: initial_cn_ratio(:) ! c:n ratio for initialization of pools real(r8) , pointer :: initial_stock(:) ! initial concentration for seeding at spinup + real(r8) :: initial_stock_soildepth ! soil depth for initial concentration for seeding at spinup logical , pointer :: is_metabolic(:) ! TRUE => pool is metabolic material logical , pointer :: is_cellulose(:) ! TRUE => pool is cellulose logical , pointer :: is_lignin(:) ! TRUE => pool is lignin @@ -92,6 +93,7 @@ subroutine init_decomp_cascade_constants() decomp_cascade_con%is_cwd(0:ndecomp_pools) = .false. decomp_cascade_con%initial_cn_ratio(0:ndecomp_pools) = nan decomp_cascade_con%initial_stock(0:ndecomp_pools) = nan + decomp_cascade_con%initial_stock_soildepth = 0.3 decomp_cascade_con%is_metabolic(0:ndecomp_pools) = .false. decomp_cascade_con%is_cellulose(0:ndecomp_pools) = .false. decomp_cascade_con%is_lignin(0:ndecomp_pools) = .false. diff --git a/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 index f588de3a0c..413647bf1c 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompMod.F90 @@ -11,7 +11,7 @@ module SoilBiogeochemDecompMod use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use clm_varpar , only : nlevdecomp, ndecomp_cascade_transitions, ndecomp_pools - use clm_varctl , only : use_nitrif_denitrif, use_lch4, use_ed + use clm_varctl , only : use_nitrif_denitrif, use_lch4, use_fates use clm_varcon , only : dzsoi_decomp use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con use SoilBiogeochemStateType , only : soilbiogeochem_state_type @@ -135,7 +135,7 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, ! column loop to calculate actual immobilization and decomp rates, following ! resolution of plant/heterotroph competition for mineral N - if ( .not. use_ed) then + if ( .not. use_fates) then ! calculate c:n ratios of applicable pools do l = 1, ndecomp_pools if ( floating_cn_ratio_decomp_pools(l) ) then @@ -260,7 +260,7 @@ subroutine SoilBiogeochemDecomp (bounds, num_soilc, filter_soilc, do fc = 1,num_soilc c = filter_soilc(fc) do j = 1,nlevdecomp - if(.not.use_ed)then + if(.not.use_fates)then net_nmin(c) = net_nmin(c) + net_nmin_vr(c,j) * dzsoi_decomp(j) gross_nmin(c) = gross_nmin(c) + gross_nmin_vr(c,j) * dzsoi_decomp(j) ! else diff --git a/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 b/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 index 007872333d..a82ce9c469 100644 --- a/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemLittVertTranspMod.F90 @@ -5,7 +5,7 @@ module SoilBiogeochemLittVertTranspMod ! use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg - use clm_varctl , only : iulog, use_c13, use_c14, spinup_state, use_vertsoilc, use_ed, use_cn + use clm_varctl , only : iulog, use_c13, use_c14, spinup_state, use_vertsoilc, use_fates, use_cn use clm_varcon , only : secspday use decompMod , only : bounds_type use abortutils , only : endrun @@ -186,7 +186,7 @@ subroutine SoilBiogeochemLittVertTransp(bounds, num_soilc, filter_soilc, & if ( use_c14 ) then ntype = ntype+1 endif - if ( use_ed ) then + if ( use_fates ) then ntype = 1 endif spinup_term = 1._r8 diff --git a/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 b/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 index 7263e7be3d..f1ff0e48ca 100644 --- a/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNitrogenFluxType.F90 @@ -8,6 +8,7 @@ module SoilBiogeochemNitrogenFluxType use clm_varcon , only : spval, ispval, dzsoi_decomp use decompMod , only : bounds_type use clm_varctl , only : use_nitrif_denitrif, use_vertsoilc, use_crop + use CNSharedParamsMod , only : use_fun use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_con use abortutils , only : endrun use LandunitType , only : lun @@ -346,7 +347,7 @@ subroutine InitHistory(this, bounds) endif call hist_addfld1d (fname=fieldname, units='gN/m^2', & avgflag='A', long_name=longname, & - ptr_col=data1dptr) + ptr_col=data1dptr, default='inactive') end if !-- transfer fluxes (none from terminal pool, if present) @@ -359,7 +360,7 @@ subroutine InitHistory(this, bounds) ' N to '//trim(decomp_cascade_con%decomp_pool_name_long(decomp_cascade_con%cascade_receiver_pool(l)))//' N' call hist_addfld1d (fname=fieldname, units='gN/m^2', & avgflag='A', long_name=longname, & - ptr_col=data1dptr) + ptr_col=data1dptr, default='inactive') end if ! vertically resolved fluxes @@ -446,7 +447,7 @@ subroutine InitHistory(this, bounds) 'to '//trim(decomp_cascade_con%decomp_pool_name_history(decomp_cascade_con%cascade_receiver_pool(l))) call hist_addfld1d (fname=fieldname, units='gN/m^2', & avgflag='A', long_name=longname, & - ptr_col=data1dptr) + ptr_col=data1dptr, default='inactive') endif if ( nlevdecomp_full > 1 ) then @@ -540,14 +541,14 @@ subroutine InitHistory(this, bounds) this%f_nit_vr_col(begc:endc,:) = spval call hist_addfld_decomp (fname='F_NIT'//trim(vr_suffix), units='gN/m^3/s', type2d='levdcmp', & avgflag='A', long_name='nitrification flux', & - ptr_col=this%f_nit_vr_col) + ptr_col=this%f_nit_vr_col, default='inactive') end if if (use_nitrif_denitrif .and. nlevdecomp_full > 1 ) then this%f_denit_vr_col(begc:endc,:) = spval call hist_addfld_decomp (fname='F_DENIT'//trim(vr_suffix), units='gN/m^3/s', type2d='levdcmp', & avgflag='A', long_name='denitrification flux', & - ptr_col=this%f_denit_vr_col) + ptr_col=this%f_denit_vr_col, default='inactive') end if if (use_nitrif_denitrif .and. nlevdecomp_full > 1 ) then @@ -821,14 +822,14 @@ subroutine InitHistory(this, bounds) this%fert_to_sminn_col(begc:endc) = spval call hist_addfld1d (fname='FERT_TO_SMINN', units='gN/m^2/s', & avgflag='A', long_name='fertilizer to soil mineral N', & - ptr_col=this%fert_to_sminn_col) + ptr_col=this%fert_to_sminn_col, default='inactive') end if - if (use_crop) then + if (use_crop .and. .not. use_fun) then this%soyfixn_to_sminn_col(begc:endc) = spval call hist_addfld1d (fname='SOYFIXN_TO_SMINN', units='gN/m^2/s', & avgflag='A', long_name='Soybean fixation to soil mineral N', & - ptr_col=this%soyfixn_to_sminn_col) + ptr_col=this%soyfixn_to_sminn_col, default='inactive') end if end subroutine InitHistory diff --git a/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 b/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 index 7bde177ac2..ca09e63624 100644 --- a/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemNitrogenStateType.F90 @@ -9,7 +9,7 @@ module SoilBiogeochemNitrogenStateType use abortutils , only : endrun use spmdMod , only : masterproc use clm_varpar , only : ndecomp_cascade_transitions, ndecomp_pools, nlevcan - use clm_varpar , only : nlevdecomp_full, nlevdecomp + use clm_varpar , only : nlevdecomp_full, nlevdecomp, nlevsoi use clm_varcon , only : spval, dzsoi_decomp, zisoi use clm_varctl , only : use_nitrif_denitrif, use_vertsoilc, use_century_decomp use clm_varctl , only : iulog, override_bgc_restart_mismatch_dump, spinup_state @@ -52,6 +52,7 @@ module SoilBiogeochemNitrogenStateType ! the N balance check real(r8), pointer :: dyn_no3bal_adjustments_col (:) ! (gN/m2) NO3 adjustments to each column made in this timestep via dynamic column area adjustments (only makes sense at the column-level: meaningless if averaged to the gridcell-level) real(r8), pointer :: dyn_nh4bal_adjustments_col (:) ! (gN/m2) NH4 adjustments to each column made in this timestep via dynamic column adjustments (only makes sense at the column-level: meaningless if averaged to the gridcell-level) + real(r8) :: totvegcthresh ! threshold for total vegetation carbon to zero out decomposition pools contains @@ -60,6 +61,7 @@ module SoilBiogeochemNitrogenStateType procedure , public :: SetValues procedure , public :: Summary procedure , public :: DynamicColumnAdjustments ! adjust state variables when column areas change + procedure , public :: SetTotVgCThresh ! Set value for totvegcthresh needed in Restart procedure , private :: InitAllocate procedure , private :: InitHistory procedure , private :: InitCold @@ -82,6 +84,7 @@ subroutine Init(this, bounds, & real(r8) , intent(in) :: decomp_cpools_col (bounds%begc:, 1:) real(r8) , intent(in) :: decomp_cpools_1m_col (bounds%begc:, 1:) + this%totvegcthresh = nan call this%InitAllocate (bounds ) call this%InitHistory (bounds) @@ -169,7 +172,7 @@ subroutine InitHistory(this, bounds) longname = trim(decomp_cascade_con%decomp_pool_name_history(l))//' N (vertically resolved)' call hist_addfld2d (fname=fieldname, units='gN/m^3', type2d='levdcmp', & avgflag='A', long_name=longname, & - ptr_col=data2dptr, default='inactive') + ptr_col=data2dptr) endif data1dptr => this%decomp_npools_col(:,l) @@ -211,7 +214,7 @@ subroutine InitHistory(this, bounds) this%ntrunc_col(begc:endc) = spval call hist_addfld1d (fname='COL_NTRUNC', units='gN/m^2', & avgflag='A', long_name='column-level sink for N truncation', & - ptr_col=this%ntrunc_col) + ptr_col=this%ntrunc_col, default='inactive') ! add suffix if number of soil decomposition depths is greater than 1 if (nlevdecomp > 1) then @@ -221,17 +224,22 @@ subroutine InitHistory(this, bounds) endif if (use_nitrif_denitrif) then - this%smin_no3_vr_col(begc:endc,:) = spval - call hist_addfld_decomp (fname='SMIN_NO3'//trim(vr_suffix), units='gN/m^3', type2d='levdcmp', & - avgflag='A', long_name='soil mineral NO3 (vert. res.)', & - ptr_col=this%smin_no3_vr_col) + if ( nlevdecomp_full > 1 ) then + data2dptr => this%smin_no3_vr_col(begc:endc,1:nlevsoi) + call hist_addfld_decomp (fname='SMIN_NO3'//trim(vr_suffix), units='gN/m^3', type2d='levsoi', & + avgflag='A', long_name='soil mineral NO3 (vert. res.)', & + ptr_col=data2dptr) - this%smin_nh4_vr_col(begc:endc,:) = spval - call hist_addfld_decomp (fname='SMIN_NH4'//trim(vr_suffix), units='gN/m^3', type2d='levdcmp', & - avgflag='A', long_name='soil mineral NH4 (vert. res.)', & - ptr_col=this%smin_nh4_vr_col) + data2dptr => this%smin_nh4_vr_col(begc:endc,1:nlevsoi) + call hist_addfld_decomp (fname='SMIN_NH4'//trim(vr_suffix), units='gN/m^3', type2d='levsoi', & + avgflag='A', long_name='soil mineral NH4 (vert. res.)', & + ptr_col=data2dptr) + + data2dptr => this%sminn_vr_col(begc:endc,1:nlevsoi) + call hist_addfld_decomp (fname='SMINN'//trim(vr_suffix), units='gN/m^3', type2d='levsoi', & + avgflag='A', long_name='soil mineral N', & + ptr_col=data2dptr) - if ( nlevdecomp_full > 1 ) then this%smin_no3_col(begc:endc) = spval call hist_addfld1d (fname='SMIN_NO3', units='gN/m^2', & avgflag='A', long_name='soil mineral NO3', & @@ -242,16 +250,14 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='soil mineral NH4', & ptr_col=this%smin_nh4_col) endif - - this%sminn_vr_col(begc:endc,:) = spval - call hist_addfld_decomp (fname='SMINN'//trim(vr_suffix), units='gN/m^3', type2d='levdcmp', & - avgflag='A', long_name='soil mineral N', & - ptr_col=this%sminn_vr_col) else - this%sminn_vr_col(begc:endc,:) = spval - call hist_addfld_decomp (fname='SMINN'//trim(vr_suffix), units='gN/m^3', type2d='levdcmp', & - avgflag='A', long_name='soil mineral N', & - ptr_col=this%sminn_vr_col) + if ( nlevdecomp_full > 1 ) then + data2dptr => this%sminn_vr_col(begc:endc,1:nlevsoi) + call hist_addfld_decomp (fname='SMINN'//trim(vr_suffix), units='gN/m^3', type2d='levsoi', & + avgflag='A', long_name='soil mineral N', & + ptr_col=data2dptr) + end if + end if this%totlitn_col(begc:endc) = spval @@ -374,14 +380,14 @@ subroutine InitCold(this, bounds, & end subroutine InitCold !----------------------------------------------------------------------- - subroutine Restart ( this, bounds, ncid, flag ) + subroutine Restart ( this, bounds, ncid, flag, totvegc_col ) ! ! !DESCRIPTION: - ! Read/write CN restart data for carbon state + ! Read/write CN restart data for nitrogen state ! ! !USES: - use shr_infnan_mod , only : isnan => shr_infnan_isnan, nan => shr_infnan_nan, assignment(=) - use clm_time_manager , only : is_restart, get_nstep + use shr_infnan_mod , only : isnan => shr_infnan_isnan, nan => shr_infnan_nan, assignment(=) + use clm_time_manager , only : is_restart, get_nstep use restUtilMod use ncdio_pio ! @@ -390,6 +396,8 @@ subroutine Restart ( this, bounds, ncid, flag ) type(bounds_type) , intent(in) :: bounds type(file_desc_t) , intent(inout) :: ncid character(len=*) , intent(in) :: flag !'read' or 'write' or 'define' + real(r8) , intent(in) :: totvegc_col(bounds%begc:bounds%endc) ! (gC/m2) total vegetation carbon + ! ! !LOCAL VARIABLES: integer :: i,j,k,l,c @@ -602,6 +610,10 @@ subroutine Restart ( this, bounds, ncid, flag ) call endrun(msg=' Error in entering/exiting spinup - should occur only when nstep = 1'//& errMsg(sourcefile, __LINE__)) endif + if ( exit_spinup .and. isnan(this%totvegcthresh) )then + call endrun(msg=' Error in exit spinup - totvegcthresh was not set with SetTotVgCThresh'//& + errMsg(sourcefile, __LINE__)) + end if do k = 1, ndecomp_pools if ( exit_spinup ) then m = decomp_cascade_con%spinup_factor(k) @@ -609,10 +621,23 @@ subroutine Restart ( this, bounds, ncid, flag ) m = 1. / decomp_cascade_con%spinup_factor(k) end if do c = bounds%begc, bounds%endc + l = col%landunit(c) do j = 1, nlevdecomp if ( abs(m - 1._r8) .gt. 0.000001_r8 .and. exit_spinup) then this%decomp_npools_vr_col(c,j,k) = this%decomp_npools_vr_col(c,j,k) * m * & get_spinup_latitude_term(grc%latdeg(col%gridcell(c))) + ! If there is no vegetation nitrogen, + ! implying that all vegetation has + ! died, then + ! reset decomp pools to near zero during exit_spinup to + ! avoid very + ! large and inert soil carbon stocks; note that only + ! pools with spinup factor > 1 + ! will be affected, which means that total SOMN and LITN + ! pools will not be set to 0. + if (totvegc_col(c) <= this%totvegcthresh .and. lun%itype(l) /= istcrop) then + this%decomp_npools_vr_col(c,j,k) = 0._r8 + endif elseif ( abs(m - 1._r8) .gt. 0.000001_r8 .and. enter_spinup) then this%decomp_npools_vr_col(c,j,k) = this%decomp_npools_vr_col(c,j,k) * m / & get_spinup_latitude_term(grc%latdeg(col%gridcell(c))) @@ -885,7 +910,7 @@ subroutine Summary(this, bounds, num_allc, filter_allc) end subroutine Summary !----------------------------------------------------------------------- - subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) + subroutine DynamicColumnAdjustments(this, bounds, clump_index, column_state_updater) ! ! !DESCRIPTION: ! Adjust state variables when column areas change due to dynamic landuse @@ -896,6 +921,11 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) ! !ARGUMENTS: class(soilbiogeochem_nitrogenstate_type) , intent(inout) :: this type(bounds_type) , intent(in) :: bounds + + ! Index of clump on which we're currently operating. Note that this implies that this + ! routine must be called from within a clump loop. + integer , intent(in) :: clump_index + type(column_state_updater_type) , intent(in) :: column_state_updater ! ! !LOCAL VARIABLES: @@ -916,6 +946,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) do j = 1, nlevdecomp call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%decomp_npools_vr_col(begc:endc, j, l), & adjustment = adjustment_one_level(begc:endc)) this%dyn_nbal_adjustments_col(begc:endc) = & @@ -927,6 +958,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) do j = 1, nlevdecomp call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%ntrunc_vr_col(begc:endc, j), & adjustment = adjustment_one_level(begc:endc)) this%dyn_nbal_adjustments_col(begc:endc) = & @@ -935,6 +967,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%sminn_vr_col(begc:endc, j), & adjustment = adjustment_one_level(begc:endc)) this%dyn_nbal_adjustments_col(begc:endc) = & @@ -952,6 +985,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%smin_no3_vr_col(begc:endc, j), & adjustment = adjustment_one_level(begc:endc)) this%dyn_no3bal_adjustments_col(begc:endc) = & @@ -960,6 +994,7 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) call column_state_updater%update_column_state_no_special_handling( & bounds = bounds, & + clump_index = clump_index, & var = this%smin_nh4_vr_col(begc:endc, j), & adjustment = adjustment_one_level(begc:endc)) this%dyn_nh4bal_adjustments_col(begc:endc) = & @@ -971,5 +1006,18 @@ subroutine DynamicColumnAdjustments(this, bounds, column_state_updater) end subroutine DynamicColumnAdjustments + !------------------------------------------------------------------------ + subroutine SetTotVgCThresh(this, totvegcthresh) + + class(soilbiogeochem_nitrogenstate_type) :: this + real(r8) , intent(in) :: totvegcthresh + + if ( totvegcthresh <= 0.0_r8 )then + call endrun(msg=' Error totvegcthresh is zero or negative and should be > 0'//& + errMsg(sourcefile, __LINE__)) + end if + this%totvegcthresh = totvegcthresh + + end subroutine SetTotVgCThresh end module SoilBiogeochemNitrogenStateType diff --git a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 index 9b7c9decf8..2349a63fd4 100644 --- a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 @@ -16,7 +16,7 @@ module SoilBiogeochemPotentialMod use SoilBiogeochemCarbonFluxType , only : soilbiogeochem_carbonflux_type use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type use SoilBiogeochemNitrogenFluxType , only : soilbiogeochem_nitrogenflux_type - use clm_varctl , only : use_ed, iulog + use clm_varctl , only : use_fates, iulog ! implicit none private @@ -134,7 +134,7 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & fphr => soilbiogeochem_carbonflux_inst%fphr_col & ! Output: [real(r8) (:,:) ] fraction of potential SOM + LITTER heterotrophic ) - if ( .not. use_ed ) then + if ( .not. use_fates ) then ! set initial values for potential C and N fluxes p_decomp_cpool_loss(begc:endc, :, :) = 0._r8 pmnf_decomp_cascade(begc:endc, :, :) = 0._r8 @@ -228,7 +228,7 @@ subroutine SoilBiogeochemPotential (bounds, num_soilc, filter_soilc, & potential_immob_vr(c,j) = immob(c,j) end do end do - else ! use_ed + else ! use_fates ! As a first step we are making this a C-only model, so no N downregulation of fluxes. do k = 1, ndecomp_cascade_transitions do j = 1,nlevdecomp diff --git a/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 b/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 index da3789c183..2bd92d2d41 100644 --- a/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemPrecisionControlMod.F90 @@ -15,11 +15,50 @@ module SoilBiogeochemPrecisionControlMod private ! ! !PUBLIC MEMBER FUNCTIONS: - public:: SoilBiogeochemPrecisionControl + public:: SoilBiogeochemPrecisionControlInit ! Initialization + public:: SoilBiogeochemPrecisionControl ! Apply precision control to soil biogeochemistry carbon and nitrogen states + + ! !PUBLIC DATA: + real(r8), public :: ccrit ! critical carbon state value for truncation (gC/m2) + real(r8), public :: ncrit ! critical nitrogen state value for truncation (gN/m2) !----------------------------------------------------------------------- contains + !----------------------------------------------------------------------- + subroutine SoilBiogeochemPrecisionControlInit( soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & + c14_soilbiogeochem_carbonstate_inst, soilbiogeochem_nitrogenstate_inst) + + ! + ! !DESCRIPTION: + ! Initialization of soil biogeochemistry precision control + ! + ! !USES: + use clm_varctl , only : use_c13, use_c14 + ! + ! !ARGUMENTS: + type(soilbiogeochem_carbonstate_type) , intent(inout) :: soilbiogeochem_carbonstate_inst + type(soilbiogeochem_carbonstate_type) , intent(inout) :: c13_soilbiogeochem_carbonstate_inst + type(soilbiogeochem_carbonstate_type) , intent(inout) :: c14_soilbiogeochem_carbonstate_inst + type(soilbiogeochem_nitrogenstate_type) , intent(inout) :: soilbiogeochem_nitrogenstate_inst + ! + ! !LOCAL VARIABLES: + real(r8), parameter :: totvegcthresh = 0.1_r8 ! Total vegetation carbon threshold to zero out decomposition pools + !----------------------------------------------------------------------- + ccrit = 1.e-8_r8 ! critical carbon state value for truncation (gC/m2) + ncrit = 1.e-8_r8 ! critical nitrogen state value for truncation (gN/m2) + + call soilbiogeochem_carbonstate_inst%setTotVgCThresh( totvegcthresh ) + if ( use_c13 )then + call c13_soilbiogeochem_carbonstate_inst%setTotVgCThresh( totvegcthresh ) + end if + if ( use_c14 )then + call c14_soilbiogeochem_carbonstate_inst%setTotVgCThresh( totvegcthresh ) + end if + call soilbiogeochem_nitrogenstate_inst%setTotVgCThresh( totvegcthresh ) + + end subroutine SoilBiogeochemPrecisionControlInit + !----------------------------------------------------------------------- subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & soilbiogeochem_carbonstate_inst, c13_soilbiogeochem_carbonstate_inst, & @@ -49,8 +88,6 @@ subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & real(r8):: cc,cn ! truncation terms for column-level corrections real(r8):: cc13 ! truncation terms for column-level corrections real(r8):: cc14 ! truncation terms for column-level corrections - real(r8):: ccrit ! critical carbon state value for truncation - real(r8):: ncrit ! critical nitrogen state value for truncation !----------------------------------------------------------------------- ! soilbiogeochem_carbonstate_inst%ctrunc_vr_col Output: [real(r8) (:,:) ] (gC/m3) column-level sink for C truncation @@ -68,13 +105,6 @@ subroutine SoilBiogeochemPrecisionControl(num_soilc, filter_soilc, & c14cs => c14_soilbiogeochem_carbonstate_inst & ) - ! set the critical carbon state value for truncation (gC/m2) - ccrit = 1.e-8_r8 - - ! set the critical nitrogen state value for truncation (gN/m2) - ncrit = 1.e-8_r8 - - ! column loop do fc = 1,num_soilc c = filter_soilc(fc) diff --git a/src/soilbiogeochem/SoilBiogeochemStateType.F90 b/src/soilbiogeochem/SoilBiogeochemStateType.F90 index 684a064d59..45cf6e27dd 100644 --- a/src/soilbiogeochem/SoilBiogeochemStateType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemStateType.F90 @@ -117,8 +117,9 @@ subroutine InitHistory(this, bounds) ! Initialize module data structure ! ! !USES: - use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) - use histFileMod , only : hist_addfld1d, hist_addfld2d, hist_addfld_decomp, no_snow_normal + use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) + use histFileMod , only : hist_addfld1d, hist_addfld2d, hist_addfld_decomp, no_snow_normal + use CNSharedParamsMod , only : use_fun ! ! !ARGUMENTS: class(soilbiogeochem_state_type) :: this @@ -181,11 +182,13 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='fraction of potential immobilization', & ptr_col=this%fpi_col) endif - - this%fpg_col(begc:endc) = spval - call hist_addfld1d (fname='FPG', units='proportion', & - avgflag='A', long_name='fraction of potential gpp', & - ptr_col=this%fpg_col) + + if (.not. use_fun) then + this%fpg_col(begc:endc) = spval + call hist_addfld1d (fname='FPG', units='proportion', & + avgflag='A', long_name='fraction of potential gpp', & + ptr_col=this%fpg_col) + end if if (nlevdecomp > 1) then vr_suffix = "_vr" diff --git a/src/unit_test_shr/unittestSubgridMod.F90 b/src/unit_test_shr/unittestSubgridMod.F90 index 62691cb11f..f75384d8da 100644 --- a/src/unit_test_shr/unittestSubgridMod.F90 +++ b/src/unit_test_shr/unittestSubgridMod.F90 @@ -39,7 +39,7 @@ module unittestSubgridMod ! is true. use shr_kind_mod , only : r8 => shr_kind_r8 - use decompMod , only : bounds_type, BOUNDS_LEVEL_PROC + use decompMod , only : bounds_type, procinfo, get_proc_bounds use GridcellType , only : grc use LandunitType , only : lun use ColumnType , only : col @@ -162,15 +162,59 @@ subroutine unittest_subgrid_setup_end character(len=*), parameter :: subname = 'unittest_subgrid_setup_end' !----------------------------------------------------------------------- - - call set_bounds + + call set_decomp_info + call create_bounds_object call clm_ptrs_compdown(bounds) call compute_higher_order_weights(bounds) end subroutine unittest_subgrid_setup_end !----------------------------------------------------------------------- - subroutine set_bounds + subroutine set_decomp_info + ! + ! !DESCRIPTION: + ! Set up decomp info in decompMod. + ! + ! We need to do this (in addition to just making sure that the bounds derived type + ! object is set up correctly) for the sake of callers of get_proc_bounds. + ! + ! !USES: + ! + ! !ARGUMENTS: + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'set_decomp_info' + !----------------------------------------------------------------------- + + ! For now, not setting up clump info, because it isn't needed in any unit tests. We + ! may have to fix this in the future. + procinfo%nclumps = 1 + allocate(procinfo%cid(procinfo%nclumps)) + procinfo%cid(:) = -1 + + procinfo%begg = begg + procinfo%endg = gi + procinfo%begl = begl + procinfo%endl = li + procinfo%begc = begc + procinfo%endc = ci + procinfo%begp = begp + procinfo%endp = pi + + procinfo%ncells = procinfo%endg - procinfo%begg + 1 + procinfo%nlunits = procinfo%endl - procinfo%begl + 1 + procinfo%ncols = procinfo%endc - procinfo%begc + 1 + procinfo%npatches = procinfo%endp - procinfo%begp + 1 + + ! Currently leaving cohort info unset because it isn't needed in any unit tests. We + ! may have to fix this in the future. + + end subroutine set_decomp_info + + !----------------------------------------------------------------------- + subroutine create_bounds_object ! ! !DESCRIPTION: ! Create the bounds derived type object @@ -183,24 +227,15 @@ subroutine set_bounds character(len=*), parameter :: subname = 'set_bounds' !----------------------------------------------------------------------- - - bounds%begg = begg - bounds%endg = gi - bounds%begl = begl - bounds%endl = li - bounds%begc = begc - bounds%endc = ci - bounds%begp = begp - bounds%endp = pi ! Some routines want a proc-level bounds. So for now, just making bounds be ! proc-level. In the future, we may need both a proc-level and clumps-level bounds ! object (if other routines want a clump-level bounds). (For the sake of unit ! testing, proc-level and clump-level bounds objects can probably be the same except ! for bounds%level and bounds%clump_index.) - bounds%level = BOUNDS_LEVEL_PROC + call get_proc_bounds(bounds) - end subroutine set_bounds + end subroutine create_bounds_object diff --git a/src/unit_test_stubs/csm_share/mct_mod_stub.F90 b/src/unit_test_stubs/csm_share/mct_mod_stub.F90 index af5ae53b54..832b8847d7 100644 --- a/src/unit_test_stubs/csm_share/mct_mod_stub.F90 +++ b/src/unit_test_stubs/csm_share/mct_mod_stub.F90 @@ -6,7 +6,7 @@ module mct_mod implicit none public :: mct_gsMap - public :: mct_gsMap_OP + public :: mct_gsMap_orderedPoints type mct_gsMap ! Empty, dummy type @@ -14,8 +14,8 @@ module mct_mod contains - subroutine mct_gsMap_OP(GSMap, PEno, Points) - ! Stub routine that simply matches the signature of mct_gsMap_OP + subroutine mct_gsMap_orderedPoints(GSMap, PEno, Points) + ! Stub routine that simply matches the signature of mct_gsMap_orderedPoints ! this routine allocates the Points array, to match the documented behavior of the ! real routine. This is needed so that a later deallocate will succeed. But note that ! it is just allocated to be of size 1, so it cannot be used for any real @@ -25,6 +25,6 @@ subroutine mct_gsMap_OP(GSMap, PEno, Points) integer,dimension(:),pointer :: Points allocate(Points(1)) - end subroutine mct_gsMap_OP + end subroutine mct_gsMap_orderedPoints end module mct_mod diff --git a/src/unit_test_stubs/csm_share/seq_comm_mct.F90 b/src/unit_test_stubs/csm_share/seq_comm_mct.F90 index 7c2ce6e7e9..f8201284ba 100644 --- a/src/unit_test_stubs/csm_share/seq_comm_mct.F90 +++ b/src/unit_test_stubs/csm_share/seq_comm_mct.F90 @@ -1,7 +1,7 @@ module seq_comm_mct ! Stub of seq_comm_mct, containing just what's needed for CLM modules. ! - ! Note that the true seq_comm_mct is in driver_cpl/shr + ! Note that the true seq_comm_mct is in cime/scr/drivers/mct/shr implicit none save diff --git a/src/unit_test_stubs/main/ncdio_pio_fake.F90.in b/src/unit_test_stubs/main/ncdio_pio_fake.F90.in index e3bee231cf..a5578e10e6 100644 --- a/src/unit_test_stubs/main/ncdio_pio_fake.F90.in +++ b/src/unit_test_stubs/main/ncdio_pio_fake.F90.in @@ -49,6 +49,7 @@ module ncdio_pio public :: ncd_inqdid ! stub: inquire dimension id public :: ncd_inqvdlen ! stub: inquire size of a dimension public :: ncd_inqdlen ! stub: inquire size of a dimension + public :: ncd_inqfdims ! stub: inquire file dimensions public :: ncd_getatt ! stub: get attribute public :: ncd_putatt ! stub: put attribute @@ -70,6 +71,9 @@ module ncdio_pio module procedure ncd_io_1d_double module procedure ncd_io_2d_double module procedure ncd_io_1d_int + module procedure ncd_io_2d_int + module procedure ncd_io_3d_double + module procedure ncd_io_3d_int module procedure ncd_io_1d_logical !DIMS 0,1,2,3 @@ -248,6 +252,49 @@ contains end subroutine ncd_io_1d_{TYPE} + subroutine ncd_io_2d_int(varname, data, dim1name, lowerb2, upperb2, & + flag, ncid, nt, readvar, switchdim, cnvrtnan2fill) + ! + ! !DESCRIPTION: + ! Stub replacement: netcdf I/O for 2d int + ! + ! !ARGUMENTS: + class(file_desc_t), intent(inout) :: ncid ! netcdf file id + character(len=*) , intent(in) :: flag ! 'read' or 'write' + character(len=*) , intent(in) :: varname ! variable name + integer , pointer :: data(:,:) ! local decomposition input data + character(len=*) , intent(in) :: dim1name ! dimension 1 name + integer, optional, intent(in) :: nt ! time sample index + integer, optional, intent(in) :: lowerb2,upperb2 ! lower and upper bounds of second dimension + logical, optional, intent(out) :: readvar ! true => variable is on initial dataset (read only) + logical, optional, intent(in) :: switchdim ! true=> permute dim1 and dim2 for output + logical, optional, intent(in) :: cnvrtnan2fill ! true => convert any NaN's to _FillValue (spval) + + if (present(readvar)) then + readvar = .false. + end if + end subroutine ncd_io_2d_int + + !TYPE int,double + subroutine ncd_io_3d_{TYPE}(varname, data, dim1name, flag, ncid, nt, readvar) + ! + ! !DESCRIPTION: + ! Stub: Netcdf i/o of 3d + ! + ! !ARGUMENTS: + class(file_desc_t), intent(inout) :: ncid ! netcdf file id + character(len=*) , intent(in) :: flag ! 'read' or 'write' + character(len=*) , intent(in) :: varname ! variable name + {VTYPE} , pointer :: data(:,:,:) ! local decomposition input data + character(len=*) , intent(in) :: dim1name ! dimension 1 name + integer, optional, intent(in) :: nt ! time sample index + logical, optional, intent(out) :: readvar ! true => variable is on initial dataset (read only) + + if (present(readvar)) then + readvar = .false. + end if + end subroutine ncd_io_3d_{TYPE} + !------------------------------------------------------------------------ !DIMS 0,1,2,3 !TYPE int,double @@ -350,6 +397,26 @@ contains end subroutine ncd_inqdlen + !----------------------------------------------------------------------- + subroutine ncd_inqfdims(ncid, isgrid2d, ni, nj, ns) + ! + ! !DESCRIPTION: + ! Stub replacement for ncd_inqfdims. This does nothing, but just satisfies the + ! interface. + ! + ! !ARGUMENTS: + class(file_desc_t), intent(inout):: ncid + logical , intent(out) :: isgrid2d + integer , intent(out) :: ni + integer , intent(out) :: nj + integer , intent(out) :: ns + + isgrid2d = .true. + ni = 1 + nj = 1 + ns = 1 + end subroutine ncd_inqfdims + !----------------------------------------------------------------------- subroutine ncd_getatt_char(ncid,varid,attrib,value) ! diff --git a/src/unit_test_stubs/utils/CMakeLists.txt b/src/unit_test_stubs/utils/CMakeLists.txt index ab3474b8c9..dc48aa9225 100644 --- a/src/unit_test_stubs/utils/CMakeLists.txt +++ b/src/unit_test_stubs/utils/CMakeLists.txt @@ -11,6 +11,7 @@ list(APPEND clm_sources "${clm_genf90_sources}") list(APPEND clm_sources restUtilMod_stub.F90 spmdMod_stub.F90 + clmfates_paraminterfaceMod_stub.F90 ) sourcelist_to_parent(clm_sources) diff --git a/src/unit_test_stubs/utils/clmfates_paraminterfaceMod_stub.F90 b/src/unit_test_stubs/utils/clmfates_paraminterfaceMod_stub.F90 new file mode 100644 index 0000000000..4dd580a986 --- /dev/null +++ b/src/unit_test_stubs/utils/clmfates_paraminterfaceMod_stub.F90 @@ -0,0 +1,11 @@ +module CLMFatesParamInterfaceMod + + implicit none + + public :: FatesReadPfts + +contains + subroutine FatesReadPFTs() + implicit none + end subroutine FatesReadPFTs +end module CLMFatesParamInterfaceMod diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 48a5562ebf..72d02ad66d 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -10,7 +10,7 @@ module CLMFatesInterfaceMod ! The routines here, that call FATES library routines, will not pass any types defined ! by the driving land model (HLM). ! - ! either native type arrays (int,real,log, etc) or packed into ED boundary condition + ! either native type arrays (int,real,log, etc) or packed into fates boundary condition ! structures. ! ! Note that CLM/ALM does use Shared Memory Parallelism (SMP), where processes such as @@ -22,11 +22,10 @@ module CLMFatesInterfaceMod ! Therefore, the state variables in the clm_fates communicator is vectorized by ! threadcount, and the IO communication arrays are not. ! - ! INTERF-TODO: NEED AN INVALID R8 SETTING FOR FATES ! ! Conventions: ! keep line widths within 90 spaces - ! DLM acronym = Driving Land Model + ! HLM acronym = Host Land Model ! ! ------------------------------------------------------------------------------------- @@ -37,29 +36,45 @@ module CLMFatesInterfaceMod use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type use WaterStateType , only : waterstate_type + use WaterFluxType , only : waterflux_type use CanopyStateType , only : canopystate_type use TemperatureType , only : temperature_type use EnergyFluxType , only : energyflux_type - use SoilStateType , only : soilstate_type - use PhotosynthesisMod , only : photosyns_type - use clm_varctl , only : iulog, use_ed + + use SoilStateType , only : soilstate_type + use clm_varctl , only : iulog + use clm_varctl , only : use_vertsoilc + use clm_varctl , only : use_fates_spitfire use clm_varcon , only : tfrz - use clm_varcon , only : spval - use clm_varpar , only : numpft, & - numrad, & - nlevgrnd, & - nlevdecomp, & - nlevdecomp_full + use clm_varcon , only : spval + use clm_varcon , only : denice + use clm_varcon , only : ispval + + use clm_varpar , only : numpft + use clm_varpar , only : numrad + use clm_varpar , only : ivis + use clm_varpar , only : inir + use clm_varpar , only : nlevgrnd + use clm_varpar , only : nlevsoi + use clm_varpar , only : nlevdecomp + use clm_varpar , only : nlevdecomp_full + use PhotosynthesisMod , only : photosyns_type use atm2lndType , only : atm2lnd_type use SurfaceAlbedoType , only : surfalb_type use SolarAbsorbedType , only : solarabs_type - use SoilBiogeochemCarbonFluxType, only : soilbiogeochem_carbonflux_type + use SoilBiogeochemCarbonFluxType, only : soilbiogeochem_carbonflux_type + use SoilBiogeochemCarbonStateType, only : soilbiogeochem_carbonstate_type + use FrictionVelocityMod , only : frictionvel_type use clm_time_manager , only : is_restart - use ncdio_pio , only : file_desc_t + use ncdio_pio , only : file_desc_t, ncd_int, ncd_double + use restUtilMod, only : restartvar use clm_time_manager , only : get_days_per_year, & - get_curr_date - use clm_time_manager , only : get_ref_date, & - timemgr_datediff + get_curr_date, & + get_ref_date, & + timemgr_datediff, & + is_beg_curr_day, & + get_step_size, & + get_nstep use spmdMod , only : masterproc use decompMod , only : get_proc_bounds, & get_proc_clumps, & @@ -70,17 +85,25 @@ module CLMFatesInterfaceMod use landunit_varcon , only : istsoil use abortutils , only : endrun use shr_log_mod , only : errMsg => shr_log_errMsg + use clm_varcon , only : dzsoi_decomp + use FuncPedotransferMod, only: get_ipedof +! use SoilWaterPlantSinkMod, only : Compute_EffecRootFrac_And_VertTranSink_Default ! Used FATES Modules - use FatesInterfaceMod , only : fates_interface_type, & - set_fates_ctrlparms, & - allocate_bcin, & - allocate_bcout + use FatesInterfaceMod , only : fates_interface_type + use FatesInterfaceMod , only : allocate_bcin + use FatesInterfaceMod , only : allocate_bcout + use FatesInterfaceMod , only : SetFatesTime + use FatesInterfaceMod , only : set_fates_ctrlparms + + use FatesHistoryInterfaceMod, only : fates_history_interface_type + use FatesRestartInterfaceMod, only : fates_restart_interface_type - use EDCLMLinkMod , only : ed_clm_type - use EDTypesMod , only : udata + use ChecksBalancesMod , only : SummarizeNetFluxes, FATES_BGC_Carbon_BalanceCheck use EDTypesMod , only : ed_patch_type - use EDtypesMod , only : numPatchesPerCol + use FatesHydraulicsMemMod , only : nlevsoi_hyd + use EDTypesMod , only : use_fates_plant_hydro + use FatesInterfaceMod , only : hlm_numlevgrnd, hlm_numlevsoil, hlm_numlevdecomp_full use EDMainMod , only : ed_ecosystem_dynamics use EDMainMod , only : ed_update_site use EDInitMod , only : zero_site @@ -88,17 +111,20 @@ module CLMFatesInterfaceMod use EDInitMod , only : set_site_properties use EDPftVarcon , only : EDpftvarcon_inst use EDEcophysConType , only : EDecophysconInit - use EDRestVectorMod , only : EDRest use EDSurfaceRadiationMod , only : ED_SunShadeFracs, ED_Norman_Radiation use EDBtranMod , only : btran_ed, & get_active_suction_layers - - use EDPhotosynthesisMod , only : Photosynthesis_ED + use EDCanopyStructureMod , only : canopy_summarization, update_hlm_dynamics + use FatesPlantRespPhotosynthMod, only : FatesPlantRespPhotosynthDrive use EDAccumulateFluxesMod , only : AccumulateFluxes_ED - use EDPhysiologyMod , only: flux_into_litter_pools + use EDPhysiologyMod , only : flux_into_litter_pools + use FatesPlantHydraulicsMod, only : hydraulics_drive + use FatesPlantHydraulicsMod, only : HydrSiteColdStart + use FatesPlantHydraulicsMod, only : InitHydrSites + use FatesPlantHydraulicsMod, only : UpdateH2OVeg implicit none - + type, public :: f2hmap_type ! This is the associated column index of each FATES site @@ -130,19 +156,17 @@ module CLMFatesInterfaceMod type(f2hmap_type), allocatable :: f2hmap(:) - ! fates2hlm (previously called "clm_ed_inst") contains types and variables - ! that are passed back to the driving land model, ie fates-to-hlm. - ! usefull to a calling model. In this case HLM means "Hosting Land Model" - ! prev: type(ed_clm_type)::ed_clm_inst + ! fates_hist is the interface class for the history output + type(fates_history_interface_type) :: fates_hist - type(ed_clm_type) :: fates2hlm + ! fates_restart is the inteface calss for restarting the model + type(fates_restart_interface_type) :: fates_restart contains procedure, public :: init - procedure, public :: init_allocate procedure, public :: check_hlm_active - procedure, public :: init_restart + procedure, public :: restart procedure, public :: init_coldstart procedure, public :: dynamics_driv procedure, public :: wrap_sunfrac @@ -151,26 +175,36 @@ module CLMFatesInterfaceMod procedure, public :: wrap_accumulatefluxes procedure, public :: prep_canopyfluxes procedure, public :: wrap_canopy_radiation - procedure, private :: wrap_litter_fluxout + procedure, public :: wrap_bgc_summary + procedure, public :: TransferZ0mDisp + procedure, private :: init_history_io + procedure, private :: wrap_update_hlmfates_dyn + procedure, private :: init_soil_depths + procedure, public :: ComputeRootSoilFlux + procedure, public :: wrap_hydraulics_drive end type hlm_fates_interface_type + ! hlm_bounds_to_fates_bounds is not currently called outside the interface. + ! Although there may be good reasons to, I privatized it so that the next + ! developer will at least question its usage (RGK) + private :: hlm_bounds_to_fates_bounds logical :: DEBUG = .false. - character(len=*), parameter, private :: sourcefile = & - __FILE__ - -contains + character(len=*), parameter, private :: sourcefile = & + __FILE__ - ! ==================================================================================== +contains - subroutine init(this,bounds_proc, use_ed) + ! ==================================================================================== + + subroutine init(this, bounds_proc ) ! --------------------------------------------------------------------------------- - ! This initializes the dlm_fates_interface_type + ! This initializes the hlm_fates_interface_type ! - ! sites is the root of the ED state hierarchy (instantaneous info on + ! sites is the root of the fates state hierarchy (instantaneous info on ! the state of the ecosystem). As such, it governs the connection points between ! the host (which also dictates its allocation) and its patch structures. ! @@ -182,38 +216,40 @@ subroutine init(this,bounds_proc, use_ed) ! Note: CLM/ALM currently wants sites to be allocated even if ed ! is not turned on ! --------------------------------------------------------------------------------- - - use FatesInterfaceMod, only : FatesInterfaceInit + + use FatesInterfaceMod, only : FatesInterfaceInit + use EDTypesMod , only : numpft_ed + use FatesParameterDerivedMod, only : param_derived implicit none ! Input Arguments class(hlm_fates_interface_type), intent(inout) :: this type(bounds_type),intent(in) :: bounds_proc - logical,intent(in) :: use_ed ! NEEDS TO BE PASSED (FOR NOW) - ! BC THE FATES SITE VECTORS - ! NEED TO BE GENERATED - ! FOR NON-ED AS WELL. SO - ! ONLY PART OF THIS MAY BE OPERATIVE + ! local variables integer :: nclumps ! Number of threads logical :: verbose_output + integer :: pass_masterproc + integer :: pass_vertsoilc + integer :: pass_spitfire + integer :: pass_is_restart + integer :: nc ! thread index + integer :: s ! FATES site index + integer :: c ! HLM column index + integer :: l ! HLM LU index + integer :: g ! HLM grid index + integer :: pi,pf + integer, allocatable :: collist (:) + type(bounds_type) :: bounds_clump + integer :: nmaxcol - if (use_ed) then - - ! Initialize the FATES communicators with the HLM - ! This involves to stages - ! 1) allocate the vectors - ! 2) add the history variables defined in clm_inst to the history machinery - call this%fates2hlm%Init(bounds_proc) - - call EDecophysconInit( EDpftvarcon_inst, numpft ) - - end if - - if(DEBUG)then - write(iulog,*) 'Entering clm_fates%init' - end if + ! Initialize the FATES communicators with the HLM + ! This involves to stages + ! 1) allocate the vectors + ! 2) add the history variables defined in clm_inst to the history machinery + call EDecophysconInit( EDpftvarcon_inst, numpft ) + call param_derived%Init( numpft_ed ) verbose_output = .false. call FatesInterfaceInit(iulog, verbose_output) @@ -222,7 +258,6 @@ subroutine init(this,bounds_proc, use_ed) allocate(this%fates(nclumps)) allocate(this%f2hmap(nclumps)) - ! --------------------------------------------------------------------------------- ! Send dimensions and other model controling parameters to FATES. These ! are obviously only those parameters that are dictated by the host @@ -232,47 +267,57 @@ subroutine init(this,bounds_proc, use_ed) call set_fates_ctrlparms('flush_to_unset') ! Send parameters individually - call set_fates_ctrlparms('num_sw_bbands',numrad) - call set_fates_ctrlparms('num_lev_ground',nlevgrnd) - call set_fates_ctrlparms('num_levdecomp',nlevdecomp) - call set_fates_ctrlparms('num_levdecomp_full',nlevdecomp_full) + call set_fates_ctrlparms('num_sw_bbands',ival=numrad) + call set_fates_ctrlparms('vis_sw_index',ival=ivis) + call set_fates_ctrlparms('nir_sw_index',ival=inir) + + call set_fates_ctrlparms('num_lev_ground',ival=nlevgrnd) + call set_fates_ctrlparms('num_lev_soil',ival=nlevsoi) + call set_fates_ctrlparms('num_levdecomp',ival=nlevdecomp) + call set_fates_ctrlparms('num_levdecomp_full',ival=nlevdecomp_full) + call set_fates_ctrlparms('hlm_name',cval='CLM') + call set_fates_ctrlparms('hio_ignore_val',rval=spval) + call set_fates_ctrlparms('soilwater_ipedof',ival=get_ipedof(0)) + + if(is_restart()) then + pass_is_restart = 1 + else + pass_is_restart = 0 + end if + call set_fates_ctrlparms('is_restart',ival=pass_is_restart) + + if(use_vertsoilc) then + pass_vertsoilc = 1 + else + pass_vertsoilc = 0 + end if + call set_fates_ctrlparms('use_vertsoilc',ival=pass_vertsoilc) + + if(use_fates_spitfire) then + pass_spitfire = 1 + else + pass_spitfire = 0 + end if + call set_fates_ctrlparms('use_spitfire',ival=pass_spitfire) + + if(masterproc)then + pass_masterproc = 1 + else + pass_masterproc = 0 + end if + call set_fates_ctrlparms('masterproc',ival=pass_masterproc) ! Check through FATES parameters to see if all have been set call set_fates_ctrlparms('check_allset') - if(DEBUG)then write(iulog,*) 'clm_fates%init(): allocating for ',nclumps,' threads' end if - return - end subroutine init - - ! ==================================================================================== - - subroutine init_allocate(this) - implicit none - - ! Input Arguments - class(hlm_fates_interface_type), intent(inout) :: this - ! local variables - integer :: nclumps ! Number of threads - integer :: nc ! thread index - integer :: s ! FATES site index - integer :: c ! HLM column index - integer :: l ! HLM LU index - integer, allocatable :: collist (:) - type(bounds_type) :: bounds_clump - integer :: nmaxcol - - if(DEBUG)then - write(iulog,*) 'Entering clm_fates%init_allocate' - end if - nclumps = get_proc_clumps() - !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,nmaxcol,s,c,l,collist) + !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,nmaxcol,s,c,l,g,collist,pi,pf) do nc = 1,nclumps call get_clump_bounds(nc, bounds_clump) @@ -292,8 +337,6 @@ subroutine init_allocate(this) ! These are the key constraints that determine if this column ! will have a FATES site associated with it - - ! INTERF-TODO: WE HAVE NOT FILTERED OUT FATES SITES ON INACTIVE COLUMNS.. YET ! NEED A RUN-TIME ROUTINE THAT CLEARS AND REWRITES THE SITE LIST @@ -341,33 +384,67 @@ subroutine init_allocate(this) ! Allocate and Initialize the Boundary Condition Arrays ! These are staticaly allocated at maximums, so - ! No information about the patch or cohort - ! structure is needed at this step + ! No information about the patch or cohort structure is needed at this step do s = 1, this%fates(nc)%nsites call allocate_bcin(this%fates(nc)%bc_in(s)) call allocate_bcout(this%fates(nc)%bc_out(s)) call this%fates(nc)%zero_bcs(s) + + ! Pass any grid-cell derived attributes to the site + ! --------------------------------------------------------------------------- + c = this%f2hmap(nc)%fcolumn(s) + g = col%gridcell(c) + this%fates(nc)%sites(s)%lat = grc%latdeg(g) + this%fates(nc)%sites(s)%lon = grc%londeg(g) + end do + ! Initialize site-level static quantities dictated by the HLM + ! currently ground layering depth + + call this%init_soil_depths(nc) + + if (use_fates_plant_hydro) call InitHydrSites(this%fates(nc)%sites) + + if( this%fates(nc)%nsites == 0 ) then write(iulog,*) 'Clump ',nc,' had no valid FATES sites' write(iulog,*) 'This will likely cause problems until code is improved' call endrun(msg=errMsg(sourcefile, __LINE__)) end if + + ! Set patch itypes on natural veg columns to nonsense + ! This will force a crash if the model outside of FATES tries to think + ! of the patch as a PFT. + + do s = 1, this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + pi = col%patchi(c)+1 + pf = col%patchf(c) +! patch%itype(pi:pf) = ispval + patch%is_fates(pi:pf) = .true. + end do + end do !$OMP END PARALLEL DO - end subroutine init_allocate - - - ! ------------------------------------------------------------------------------------ - - subroutine check_hlm_active(this, nc, bounds_clump) + call this%init_history_io(bounds_proc) + + end subroutine init + + ! =================================================================================== + + subroutine check_hlm_active(this, nc, bounds_clump) + + ! --------------------------------------------------------------------------------- + ! This subroutine is not currently used. It is just a utility that may come + ! in handy when we have dynamic sites in FATES + ! --------------------------------------------------------------------------------- implicit none class(hlm_fates_interface_type), intent(inout) :: this @@ -377,14 +454,10 @@ subroutine check_hlm_active(this, nc, bounds_clump) ! local variables integer :: c - ! FATES-TODO: THIS SHOULD BE CHANGED TO DO RE-ALLOCATION - ! INSTEAD OF FAILURE - do c = bounds_clump%begc,bounds_clump%endc ! FATES ACTIVE BUT HLM IS NOT if(this%f2hmap(nc)%hsites(c)>0 .and. .not.col%active(c)) then - write(iulog,*) 'INACTIVE COLUMN WITH ACTIVE FATES SITE' write(iulog,*) 'c = ',c @@ -398,15 +471,14 @@ subroutine check_hlm_active(this, nc, bounds_clump) end if end do - - end subroutine check_hlm_active ! ------------------------------------------------------------------------------------ subroutine dynamics_driv(this, nc, bounds_clump, & atm2lnd_inst, soilstate_inst, temperature_inst, & - waterstate_inst, canopystate_inst, soilbiogeochem_carbonflux_inst) + waterstate_inst, canopystate_inst, soilbiogeochem_carbonflux_inst, & + frictionvel_inst ) ! This wrapper is called daily from clm_driver ! This wrapper calls ed_driver, which is the daily dynamics component of FATES @@ -423,160 +495,598 @@ subroutine dynamics_driv(this, nc, bounds_clump, & type(waterstate_type) , intent(inout) :: waterstate_inst type(canopystate_type) , intent(inout) :: canopystate_inst type(soilbiogeochem_carbonflux_type), intent(inout) :: soilbiogeochem_carbonflux_inst + type(frictionvel_type) , intent(inout) :: frictionvel_inst ! !LOCAL VARIABLES: - real(r8) :: dayDiff ! day of run - integer :: dayDiffInt ! integer of day of run - integer :: s ! site + integer :: s ! site index + integer :: c ! column index (HLM) + integer :: ifp ! patch index + integer :: p ! HLM patch index integer :: yr ! year (0, ...) integer :: mon ! month (1, ..., 12) integer :: day ! day of month (1, ..., 31) integer :: sec ! seconds of the day - integer :: ncdate ! current date - integer :: nbdate ! base date (reference date) + integer :: current_year + integer :: current_month + integer :: current_day + integer :: current_tod + integer :: current_date + integer :: jan01_curr_year + integer :: reference_date + integer :: days_per_year + real(r8) :: model_day + real(r8) :: day_of_year !----------------------------------------------------------------------- - ! --------------------------------------------------------------------------------- - ! INTERF-TODO: REMOVE ED_DRIVER ARGUMENTS OF CLM STUCTURED TYPES AND - ! REPLACE THEM WITH FATES_BC TYPES WITH ITS OWN MAPPING SCHEME - ! ALSO, NOTE THAT THE ED_DYNAMICS IS A MODULE OF FATES NOW - ! ie: - ! fates(nc)%fatesbc%leaf_temp <=> canopystate_inst% - ! - ! call this%fates(nc)%ed_driver(this%fates(nc)%site, & - ! this%fates(nc)%fatesbc) + ! Part I. + ! Prepare input boundary conditions for FATES dynamics + ! Note that timing information is the same across all sites, this may + ! seem redundant, but it is possible that we may have asynchronous site simulations + ! one day. The cost of holding site level boundary conditions is minimal + ! and it keeps all the boundaries in one location ! --------------------------------------------------------------------------------- - - call this%fates2hlm%SetValues( bounds_clump, 0._r8 ) + days_per_year = get_days_per_year() + call get_curr_date(current_year,current_month,current_day,current_tod) + current_date = current_year*10000 + current_month*100 + current_day + jan01_curr_year = current_year*10000 + 100 + 1 - ! timing statements. - udata%n_sub = get_days_per_year() - udata%deltat = 1.0_r8/dble(udata%n_sub) !for working out age of patches in years - if(udata%time_period == 0)then - udata%time_period = udata%n_sub - endif - - call get_curr_date(yr, mon, day, sec) - ncdate = yr*10000 + mon*100 + day call get_ref_date(yr, mon, day, sec) - nbdate = yr*10000 + mon*100 + day - - call timemgr_datediff(nbdate, 0, ncdate, sec, dayDiff) - - dayDiffInt = floor(dayDiff) - udata%time_period = mod( dayDiffInt , udata%n_sub ) + reference_date = yr*10000 + mon*100 + day + + call timemgr_datediff(reference_date, sec, current_date, current_tod, model_day) + + call timemgr_datediff(jan01_curr_year,0,current_date,sec,day_of_year) + call SetFatesTime(current_year, current_month, & + current_day, current_tod, & + current_date, reference_date, & + model_day, floor(day_of_year), & + days_per_year, 1.0_r8/dble(days_per_year)) + + + do s=1,this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + this%fates(nc)%bc_in(s)%h2o_liqvol_gl(1:nlevsoi) = & + waterstate_inst%h2osoi_vol_col(c,1:nlevsoi) + + ! TO-DO: SHOULD THIS BE LIQVOL OR IS VOL OK? (RGK-02-2017) + + this%fates(nc)%bc_in(s)%t_veg24_si = & + temperature_inst%t_veg24_patch(col%patchi(c)) + + this%fates(nc)%bc_in(s)%max_rooting_depth_index_col = canopystate_inst%altmax_lastyear_indx_col(c) + + do ifp = 1, this%fates(nc)%sites(s)%youngest_patch%patchno + p = ifp+col%patchi(c) + this%fates(nc)%bc_in(s)%t_veg24_pa(ifp) = & + temperature_inst%t_veg24_patch(p) + + this%fates(nc)%bc_in(s)%precip24_pa(ifp) = & + atm2lnd_inst%prec24_patch(p) + + this%fates(nc)%bc_in(s)%relhumid24_pa(ifp) = & + atm2lnd_inst%rh24_patch(p) + + this%fates(nc)%bc_in(s)%wind24_pa(ifp) = & + atm2lnd_inst%wind24_patch(p) + + end do + + + if(use_fates_plant_hydro)then + this%fates(nc)%bc_in(s)%hksat_sisl(1:nlevsoi) = soilstate_inst%hksat_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%watsat_sisl(1:nlevsoi) = soilstate_inst%watsat_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%watres_sisl(1:nlevsoi) = soilstate_inst%watres_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%sucsat_sisl(1:nlevsoi) = soilstate_inst%sucsat_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%bsw_sisl(1:nlevsoi) = soilstate_inst%bsw_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%h2o_liq_sisl(1:nlevsoi) = waterstate_inst%h2osoi_liq_col(c,1:nlevsoi) + end if + - ! TODO-INTEF: PROCEDURE FOR CONVERTING CLM/ALM FIELDS TO MODEL BOUNDARY - ! CONDITIONS. IE. + end do + ! --------------------------------------------------------------------------------- + ! Part II: Call the FATES model now that input boundary conditions have been + ! provided. + ! --------------------------------------------------------------------------------- - ! where most things happen do s = 1,this%fates(nc)%nsites call ed_ecosystem_dynamics(this%fates(nc)%sites(s), & - this%fates2hlm, & - atm2lnd_inst, & - soilstate_inst, temperature_inst, waterstate_inst) + this%fates(nc)%bc_in(s)) + + call ed_update_site(this%fates(nc)%sites(s), & + this%fates(nc)%bc_in(s)) - call ed_update_site(this%fates(nc)%sites(s)) - enddo - - call wrap_litter_fluxout(this, nc, bounds_clump, canopystate_inst, soilbiogeochem_carbonflux_inst) - - ! link to CLM/ALM structures - call this%fates2hlm%ed_clm_link( bounds_clump, & - this%fates(nc)%nsites, & - this%fates(nc)%sites, & - this%f2hmap(nc)%fcolumn, & - waterstate_inst, & - canopystate_inst) + ! call subroutine to aggregate fates litter output fluxes and + ! package them for handing across interface + call flux_into_litter_pools(this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%fates(nc)%bc_in, & + this%fates(nc)%bc_out) + + + ! --------------------------------------------------------------------------------- + ! Part III: Process FATES output into the dimensions and structures that are part + ! of the HLMs API. (column, depth, and litter fractions) + ! --------------------------------------------------------------------------------- + + do s = 1, this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lab_c_col(c,:) = & + this%fates(nc)%bc_out(s)%FATES_c_to_litr_lab_c_col(:) + soilbiogeochem_carbonflux_inst%FATES_c_to_litr_cel_c_col(c,:) = & + this%fates(nc)%bc_out(s)%FATES_c_to_litr_cel_c_col(:) + soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lig_c_col(c,:) = & + this%fates(nc)%bc_out(s)%FATES_c_to_litr_lig_c_col(:) + end do + + ! --------------------------------------------------------------------------------- + ! Part III.2 (continued). + ! Update diagnostics of the FATES ecosystem structure that are used in the HLM. + ! --------------------------------------------------------------------------------- + call this%wrap_update_hlmfates_dyn(nc, & + bounds_clump, & + waterstate_inst, & + canopystate_inst, & + frictionvel_inst) + + ! --------------------------------------------------------------------------------- + ! Part IV: + ! Update history IO fields that depend on ecosystem dynamics + ! --------------------------------------------------------------------------------- + call this%fates_hist%update_history_dyn( nc, & + this%fates(nc)%nsites, & + this%fates(nc)%sites) if (masterproc) then - write(iulog, *) 'clm: leaving ED model', bounds_clump%begg, & - bounds_clump%endg, dayDiffInt + write(iulog, *) 'clm: leaving fates model', bounds_clump%begg, & + bounds_clump%endg end if return end subroutine dynamics_driv - ! ------------------------------------------------------------------------------------ - subroutine init_restart(this, ncid, flag, waterstate_inst, canopystate_inst ) + subroutine wrap_update_hlmfates_dyn(this, nc, bounds_clump, & + waterstate_inst, canopystate_inst, frictionvel_inst ) + + ! --------------------------------------------------------------------------------- + ! This routine handles the updating of vegetation canopy diagnostics, (such as lai) + ! that either requires HLM boundary conditions (like snow accumulation) or + ! provides boundary conditions (such as vegetation fractional coverage) + ! --------------------------------------------------------------------------------- + + implicit none + class(hlm_fates_interface_type), intent(inout) :: this + type(bounds_type),intent(in) :: bounds_clump + integer , intent(in) :: nc + type(waterstate_type) , intent(inout) :: waterstate_inst + type(canopystate_type) , intent(inout) :: canopystate_inst + type(frictionvel_type) , intent(inout) :: frictionvel_inst + + integer :: npatch ! number of patches in each site + integer :: ifp ! index FATES patch + integer :: p ! HLM patch index + integer :: s ! site index + integer :: c ! column index + + associate( & + tlai => canopystate_inst%tlai_patch , & + elai => canopystate_inst%elai_patch , & + tsai => canopystate_inst%tsai_patch , & + esai => canopystate_inst%esai_patch , & + htop => canopystate_inst%htop_patch , & + hbot => canopystate_inst%hbot_patch , & + z0m => frictionvel_inst%z0m_patch , & ! Output: [real(r8) (:) ] momentum roughness length (m) + displa => canopystate_inst%displa_patch, & + dleaf_patch => canopystate_inst%dleaf_patch, & + snow_depth => waterstate_inst%snow_depth_col, & + frac_sno_eff => waterstate_inst%frac_sno_eff_col, & + frac_veg_nosno_alb => canopystate_inst%frac_veg_nosno_alb_patch) + + + ! Process input boundary conditions to FATES + ! -------------------------------------------------------------------------------- + do s=1,this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + this%fates(nc)%bc_in(s)%snow_depth_si = snow_depth(c) + this%fates(nc)%bc_in(s)%frac_sno_eff_si = frac_sno_eff(c) + end do + + ! Canopy diagnostics for FATES + call canopy_summarization(this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%fates(nc)%bc_in) + + ! Canopy diagnostic outputs for HLM + call update_hlm_dynamics(this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%f2hmap(nc)%fcolumn, & + this%fates(nc)%bc_out ) + + !--------------------------------------------------------------------------------- + ! CHANGING STORED WATER DURING PLANT DYNAMICS IS NOT FULLY IMPLEMENTED + ! LEAVING AS A PLACE-HOLDER FOR NOW. + ! ! Diagnose water storage in canopy if hydraulics is on + ! ! This updates the internal value and the bc_out value. + ! ! If hydraulics is off, it returns 0 storage + ! if ( use_fates_plant_hydro ) then + ! call UpdateH2OVeg(this%fates(nc)%nsites, & + ! this%fates(nc)%sites, & + ! this%fates(nc)%bc_out) + ! + ! do s = 1, this%fates(nc)%nsites + ! c = this%f2hmap(nc)%fcolumn(s) + ! waterstate_inst%total_plant_stored_h2o_col(c) = & + ! this%fates(nc)%bc_out(s)%plant_stored_h2o_si + ! end do + ! end if + !--------------------------------------------------------------------------------- + + ! Convert FATES dynamics into HLM usable information + ! Initialize weighting variables (note FATES is the only HLM module + ! that uses "is_veg" and "is_bareground". The entire purpose of these + ! variables is to inform patch%wtcol(p). wt_ed is imposed on wtcol, + ! but only for FATES columns. + + patch%is_veg(bounds_clump%begp:bounds_clump%endp) = .false. + patch%is_bareground(bounds_clump%begp:bounds_clump%endp) = .false. + patch%wt_ed(bounds_clump%begp:bounds_clump%endp) = 0.0_r8 + + do s = 1,this%fates(nc)%nsites + + c = this%f2hmap(nc)%fcolumn(s) + + ! Other modules may have AI's we only flush values + ! that are on the naturally vegetated columns + elai(col%patchi(c):col%patchf(c)) = 0.0_r8 + tlai(col%patchi(c):col%patchf(c)) = 0.0_r8 + esai(col%patchi(c):col%patchf(c)) = 0.0_r8 + tsai(col%patchi(c):col%patchf(c)) = 0.0_r8 + htop(col%patchi(c):col%patchf(c)) = 0.0_r8 + hbot(col%patchi(c):col%patchf(c)) = 0.0_r8 + + ! FATES does not dictate bare-ground so turbulent + ! variables are not over-written. + z0m(col%patchi(c)+1:col%patchf(c)) = 0.0_r8 + displa(col%patchi(c)+1:col%patchf(c)) = 0.0_r8 + dleaf_patch(col%patchi(c)+1:col%patchf(c)) = 0.0_r8 + + frac_veg_nosno_alb(col%patchi(c):col%patchf(c)) = 0.0_r8 + + ! Set the bareground patch indicator + patch%is_bareground(col%patchi(c)) = .true. + npatch = this%fates(nc)%sites(s)%youngest_patch%patchno + patch%wt_ed(col%patchi(c)) = 1.0-sum(this%fates(nc)%bc_out(s)%canopy_fraction_pa(1:npatch)) + + if(sum(this%fates(nc)%bc_out(s)%canopy_fraction_pa(1:npatch))>1.0_r8)then + write(iulog,*)'Projected Canopy Area of all FATES patches' + write(iulog,*)'cannot exceed 1.0' + !end_run() + end if + + do ifp = 1, npatch + + p = ifp+col%patchi(c) + + ! bc_out(s)%canopy_fraction_pa(ifp) is the area fraction + ! the site's total ground area that is occupied by the + ! area footprint of the current patch's vegetation canopy + + patch%is_veg(p) = .true. + patch%wt_ed(p) = this%fates(nc)%bc_out(s)%canopy_fraction_pa(ifp) + elai(p) = this%fates(nc)%bc_out(s)%elai_pa(ifp) + tlai(p) = this%fates(nc)%bc_out(s)%tlai_pa(ifp) + esai(p) = this%fates(nc)%bc_out(s)%esai_pa(ifp) + tsai(p) = this%fates(nc)%bc_out(s)%tsai_pa(ifp) + hbot(p) = this%fates(nc)%bc_out(s)%hbot_pa(ifp) + htop(p) = this%fates(nc)%bc_out(s)%htop_pa(ifp) + frac_veg_nosno_alb(p) = this%fates(nc)%bc_out(s)%frac_veg_nosno_alb_pa(ifp) + + ! Note that while we pass the following values at this point + ! we have to send the same values after each time-step because + ! the HLM keeps changing the value and re-setting, so we + ! re-send instead of re-set. See clm_fates%TransferZ0mDisp() + z0m(p) = this%fates(nc)%bc_out(s)%z0m_pa(ifp) + displa(p) = this%fates(nc)%bc_out(s)%displa_pa(ifp) + dleaf_patch(p) = this%fates(nc)%bc_out(s)%dleaf_pa(ifp) + + + end do + + end do + end associate + end subroutine wrap_update_hlmfates_dyn + + ! ==================================================================================== + + subroutine restart( this, bounds_proc, ncid, flag, waterstate_inst, & + canopystate_inst, frictionvel_inst ) + + ! --------------------------------------------------------------------------------- + ! The ability to restart the model is handled through three different types of calls + ! "Define" the variables in the restart file, we "read" those variables into memory + ! or "write" data into the file from memory. This subroutine accomodates all three + ! of those modes through the "flag" argument. FATES as an external model also + ! requires an initialization step, where we set-up the dimensions, allocate and + ! flush the memory space that is used to transfer data in and out of the file. This + ! Only occurs once, where as the define step occurs every time a file is opened. + ! + ! Note: waterstate_inst and canopystate_inst are arguments only because following + ! the reading of variables, it is necessary to update diagnostics of the canopy + ! throug the interface call clm_fates%wrap_update_hlmfates_dyn() which requires + ! this information from the HLM. + ! --------------------------------------------------------------------------------- + + + use FatesConstantsMod, only : fates_long_string_length + use FatesIODimensionsMod, only: fates_bounds_type + use FatesIOVariableKindMod, only : site_r8, site_int, cohort_r8, cohort_int + use EDMainMod, only : ed_update_site + use FatesInterfaceMod, only: fates_maxElementsPerSite implicit none ! Arguments + class(hlm_fates_interface_type), intent(inout) :: this + type(bounds_type) , intent(in) :: bounds_proc type(file_desc_t) , intent(inout) :: ncid ! netcdf id - character(len=*) , intent(in) :: flag !'read' or 'write' + character(len=*) , intent(in) :: flag type(waterstate_type) , intent(inout) :: waterstate_inst type(canopystate_type) , intent(inout) :: canopystate_inst - + type(frictionvel_type) , intent(inout) :: frictionvel_inst + ! Locals type(bounds_type) :: bounds_clump integer :: nc integer :: nclumps + type(fates_bounds_type) :: fates_bounds + type(fates_bounds_type) :: fates_clump + integer :: c ! HLM column index + integer :: s ! Fates site index + integer :: dk_index + character(len=fates_long_string_length) :: ioname + integer :: nvar + integer :: ivar + logical :: readvar + + logical, save :: initialized = .false. + nclumps = get_proc_clumps() - !$OMP PARALLEL DO PRIVATE (nc,bounds_clump) - do nc = 1, nclumps - if (this%fates(nc)%nsites>0) then + + ! --------------------------------------------------------------------------------- + ! note (rgk: 11-2016) The history and restart intialization process assumes + ! that the number of site/columns active is a static entity. Thus + ! we only allocate the mapping tables for the column/sites we start with. + ! If/when we start having dynamic column/sites (for reasons uknown as of yet) + ! we will need to re-evaluate the allocation of the mapping tables so they + ! can be unallocated,reallocated and set every time a new column/site is spawned + ! --------------------------------------------------------------------------------- + + ! --------------------------------------------------------------------------------- + ! Only initialize the FATES restart structures the first time it is called + ! Note that the allocations involved with initialization are static. + ! This is because the array spaces for IO span the entire column, patch and cohort + ! range on the proc. + ! With DYNAMIC LANDUNITS or SPAWNING NEW OR CULLING OLD SITES: + ! we will in that case have to de-allocate, reallocate and then re-set the mapping + ! tables: this%fates_restart%restart_map(nc) + ! I think that is it... + ! --------------------------------------------------------------------------------- + + if(.not.initialized) then + + initialized=.true. + + ! ------------------------------------------------------------------------------ + ! PART I: Set FATES DIMENSIONING INFORMATION + ! ------------------------------------------------------------------------------ + + call hlm_bounds_to_fates_bounds(bounds_proc, fates_bounds) + + call this%fates_restart%Init(nclumps, fates_bounds) + + ! Define the bounds on the first dimension for each thread + !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,fates_clump) + do nc = 1,nclumps call get_clump_bounds(nc, bounds_clump) - call EDRest( bounds_clump, & - this%fates(nc)%nsites, & - this%fates(nc)%sites, & - this%f2hmap(nc)%fcolumn, ncid, flag ) + ! thread bounds for patch + call hlm_bounds_to_fates_bounds(bounds_clump, fates_clump) + call this%fates_restart%SetThreadBoundsEach(nc, fates_clump) + end do + !$OMP END PARALLEL DO + + !$OMP PARALLEL DO PRIVATE (nc,s,c) + do nc = 1,nclumps + + allocate(this%fates_restart%restart_map(nc)%site_index(this%fates(nc)%nsites)) + allocate(this%fates_restart%restart_map(nc)%cohort1_index(this%fates(nc)%nsites)) + do s=1,this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + this%fates_restart%restart_map(nc)%site_index(s) = c + this%fates_restart%restart_map(nc)%cohort1_index(s) = & + bounds_proc%begCohort + (c-bounds_proc%begc)*fates_maxElementsPerSite + 1 + end do + + end do + !$OMP END PARALLEL DO + + ! ------------------------------------------------------------------------------------ + ! PART II: USE THE JUST DEFINED DIMENSIONS TO ASSEMBLE THE VALID IO TYPES + ! INTERF-TODO: THESE CAN ALL BE EMBEDDED INTO A SUBROUTINE IN HISTORYIOMOD + ! ------------------------------------------------------------------------------------ + call this%fates_restart%assemble_restart_output_types() + + + ! ------------------------------------------------------------------------------------ + ! PART III: DEFINE THE LIST OF OUTPUT VARIABLE OBJECTS, AND REGISTER THEM WITH THE + ! HLM ACCORDING TO THEIR TYPES + ! ------------------------------------------------------------------------------------ + call this%fates_restart%initialize_restart_vars() + + end if + + ! --------------------------------------------------------------------------------- + ! If we are writing, we must loop through our linked list structures and transfer the + ! information in the linked lists (FATES state memory) to the output vectors. + ! --------------------------------------------------------------------------------- + + if(flag=='write')then + !$OMP PARALLEL DO PRIVATE (nc) + do nc = 1, nclumps + if (this%fates(nc)%nsites>0) then + call this%fates_restart%set_restart_vectors(nc,this%fates(nc)%nsites, & + this%fates(nc)%sites) + end if + end do + !$OMP END PARALLEL DO + end if + + ! --------------------------------------------------------------------------------- + ! In all cases, iterate through the list of variable objects + ! and either define, write or read to the NC buffer + ! This seems strange, but keep in mind that the call to restartvar() + ! has a different function in all three cases. + ! --------------------------------------------------------------------------------- + + nvar = this%fates_restart%num_restart_vars() + do ivar = 1, nvar - if ( trim(flag) == 'read' ) then + associate( vname => this%fates_restart%rvars(ivar)%vname, & + vunits => this%fates_restart%rvars(ivar)%units, & + vlong => this%fates_restart%rvars(ivar)%long ) + + dk_index = this%fates_restart%rvars(ivar)%dim_kinds_index + ioname = trim(this%fates_restart%dim_kinds(dk_index)%name) + + select case(trim(ioname)) + case(cohort_r8) + + call restartvar(ncid=ncid, flag=flag, varname=trim(vname), & + xtype=ncd_double,dim1name=trim('cohort'),long_name=trim(vlong), & + units=trim(vunits),interpinic_flag='interp', & + data=this%fates_restart%rvars(ivar)%r81d,readvar=readvar) + + case(site_r8) + + call restartvar(ncid=ncid, flag=flag, varname=trim(vname), & + xtype=ncd_double,dim1name=trim('column'),long_name=trim(vlong), & + units=trim(vunits),interpinic_flag='interp', & + data=this%fates_restart%rvars(ivar)%r81d,readvar=readvar) + + case(cohort_int) + + call restartvar(ncid=ncid, flag=flag, varname=trim(vname), & + xtype=ncd_int,dim1name=trim('cohort'),long_name=trim(vlong), & + units=trim(vunits),interpinic_flag='interp', & + data=this%fates_restart%rvars(ivar)%int1d,readvar=readvar) + + case(site_int) + + call restartvar(ncid=ncid, flag=flag, varname=trim(vname), & + xtype=ncd_int,dim1name=trim('column'),long_name=trim(vlong), & + units=trim(vunits),interpinic_flag='interp', & + data=this%fates_restart%rvars(ivar)%int1d,readvar=readvar) + + case default + write(iulog,*) 'A FATES iotype was created that was not registerred' + write(iulog,*) 'in CLM.:',trim(ioname) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + end associate + end do + + ! --------------------------------------------------------------------------------- + ! If we are in a read mode, then we have just populated the sparse vectors + ! in the IO object list. The data in these vectors needs to be transferred + ! to the linked lists to populate the state memory. + ! --------------------------------------------------------------------------------- + + if(flag=='read')then + + !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,s) + do nc = 1, nclumps + if (this%fates(nc)%nsites>0) then + + call get_clump_bounds(nc, bounds_clump) + + ! ------------------------------------------------------------------------ + ! Convert newly read-in vectors into the FATES namelist state variables + ! ------------------------------------------------------------------------ + call this%fates_restart%create_patchcohort_structure(nc, & + this%fates(nc)%nsites, this%fates(nc)%sites, this%fates(nc)%bc_in) - call this%fates2hlm%ed_clm_link( bounds_clump, & - this%fates(nc)%nsites, & - this%fates(nc)%sites, & - this%f2hmap(nc)%fcolumn, & - waterstate_inst, & - canopystate_inst) + call this%fates_restart%get_restart_vectors(nc, this%fates(nc)%nsites, & + this%fates(nc)%sites ) + + ! I think ed_update_site and update_hlmfates_dyn are doing some similar + ! update type stuff, should consolidate (rgk 11-2016) + do s = 1,this%fates(nc)%nsites + call ed_update_site( this%fates(nc)%sites(s), & + this%fates(nc)%bc_in(s) ) + end do + + ! ------------------------------------------------------------------------ + ! Update diagnostics of FATES ecosystem structure used in HLM. + ! ------------------------------------------------------------------------ + call this%wrap_update_hlmfates_dyn(nc,bounds_clump, & + waterstate_inst,canopystate_inst,frictionvel_inst) + ! ------------------------------------------------------------------------ + ! Update history IO fields that depend on ecosystem dynamics + ! ------------------------------------------------------------------------ + call this%fates_hist%update_history_dyn( nc, & + this%fates(nc)%nsites, & + this%fates(nc)%sites) + end if - end if - call this%fates2hlm%restart(bounds_clump, ncid, flag) - end do - !$OMP END PARALLEL DO + end do + !$OMP END PARALLEL DO + + end if return - end subroutine init_restart + end subroutine restart - ! ==================================================================================== + !===================================================================================== + + subroutine init_coldstart(this, waterstate_inst, canopystate_inst, soilstate_inst, frictionvel_inst) - subroutine init_coldstart(this, waterstate_inst, canopystate_inst) ! Arguments class(hlm_fates_interface_type), intent(inout) :: this type(waterstate_type) , intent(inout) :: waterstate_inst type(canopystate_type) , intent(inout) :: canopystate_inst + type(soilstate_type) , intent(inout) :: soilstate_inst + type(frictionvel_type) , intent(inout) :: frictionvel_inst ! locals integer :: nclumps integer :: nc type(bounds_type) :: bounds_clump ! locals + real(r8) :: vol_ice + real(r8) :: eff_porosity + integer :: j integer :: s integer :: c - integer :: g - nclumps = get_proc_clumps() - !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,s,c,g) + !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,s,c,j,vol_ice,eff_porosity) do nc = 1, nclumps if ( this%fates(nc)%nsites>0 ) then @@ -585,40 +1095,88 @@ subroutine init_coldstart(this, waterstate_inst, canopystate_inst) do s = 1,this%fates(nc)%nsites call zero_site(this%fates(nc)%sites(s)) - c = this%f2hmap(nc)%fcolumn(s) - g = col%gridcell(c) - this%fates(nc)%sites(s)%lat = grc%latdeg(g) - this%fates(nc)%sites(s)%lon = grc%londeg(g) end do call set_site_properties(this%fates(nc)%nsites, this%fates(nc)%sites) - - call init_patches(this%fates(nc)%nsites, this%fates(nc)%sites) + + ! ---------------------------------------------------------------------------- + ! Initialize Hydraulics Code if turned on + ! Called prior to init_patches(). Site level rhizosphere shells must + ! be set prior to cohort initialization. + ! ---------------------------------------------------------------------------- + if (use_fates_plant_hydro) then + + do s = 1,this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + + this%fates(nc)%bc_in(s)%watsat_sisl(1:nlevsoi) = & + soilstate_inst%watsat_col(c,1:nlevsoi) + + this%fates(nc)%bc_in(s)%watres_sisl(1:nlevsoi) = & + soilstate_inst%watres_col(c,1:nlevsoi) + + this%fates(nc)%bc_in(s)%sucsat_sisl(1:nlevsoi) = & + soilstate_inst%sucsat_col(c,1:nlevsoi) + + this%fates(nc)%bc_in(s)%bsw_sisl(1:nlevsoi) = & + soilstate_inst%bsw_col(c,1:nlevsoi) + + this%fates(nc)%bc_in(s)%h2o_liq_sisl(1:nlevsoi) = & + waterstate_inst%h2osoi_liq_col(c,1:nlevsoi) + + this%fates(nc)%bc_in(s)%hksat_sisl(1:nlevsoi) = & + soilstate_inst%hksat_col(c,1:nlevsoi) + + do j = 1, nlevsoi + vol_ice = min(soilstate_inst%watsat_col(c,j), & + waterstate_inst%h2osoi_ice_col(c,j)/(col%dz(c,j)*denice)) + eff_porosity = max(0.01_r8,soilstate_inst%watsat_col(c,j)-vol_ice) + this%fates(nc)%bc_in(s)%eff_porosity_gl(j) = eff_porosity + end do + + end do + + if (use_fates_plant_hydro) call HydrSiteColdStart(this%fates(nc)%sites,this%fates(nc)%bc_in) + end if + + call init_patches(this%fates(nc)%nsites, this%fates(nc)%sites, & + this%fates(nc)%bc_in) do s = 1,this%fates(nc)%nsites - call ed_update_site(this%fates(nc)%sites(s)) + call ed_update_site(this%fates(nc)%sites(s), & + this%fates(nc)%bc_in(s)) end do + + ! ------------------------------------------------------------------------ + ! Update diagnostics of FATES ecosystem structure used in HLM. + ! ------------------------------------------------------------------------ + call this%wrap_update_hlmfates_dyn(nc,bounds_clump, & + waterstate_inst,canopystate_inst,frictionvel_inst) + + ! ------------------------------------------------------------------------ + ! Update history IO fields that depend on ecosystem dynamics + ! ------------------------------------------------------------------------ + call this%fates_hist%update_history_dyn( nc, & + this%fates(nc)%nsites, & + this%fates(nc)%sites) + - call this%fates2hlm%ed_clm_link( bounds_clump, & - this%fates(nc)%nsites, & - this%fates(nc)%sites, & - this%f2hmap(nc)%fcolumn, & - waterstate_inst, & - canopystate_inst) + end if end do !$OMP END PARALLEL DO - return + end subroutine init_coldstart ! ====================================================================================== subroutine wrap_sunfrac(this,nc,atm2lnd_inst,canopystate_inst) - + ! --------------------------------------------------------------------------------- ! This interface function is a wrapper call on ED_SunShadeFracs. The only ! returned variable is a patch vector, fsun_patch, which describes the fraction ! of the canopy that is exposed to sun. + ! --------------------------------------------------------------------------------- implicit none @@ -645,7 +1203,7 @@ subroutine wrap_sunfrac(this,nc,atm2lnd_inst,canopystate_inst) type(ed_patch_type), pointer :: cpatch ! c"urrent" patch INTERF-TODO: SHOULD ! BE HIDDEN AS A FATES PRIVATE - + associate( forc_solad => atm2lnd_inst%forc_solad_grc, & forc_solai => atm2lnd_inst%forc_solai_grc, & fsun => canopystate_inst%fsun_patch, & @@ -698,7 +1256,7 @@ subroutine wrap_sunfrac(this,nc,atm2lnd_inst,canopystate_inst) end do end associate - return + end subroutine wrap_sunfrac ! =================================================================================== @@ -722,8 +1280,6 @@ subroutine prep_canopyfluxes(this, nc, fn, filterp, photosyns_inst) ! parameters integer,parameter :: rsmax0 = 2.e4_r8 - if (.not.use_ed) return - do s = 1, this%fates(nc)%nsites ! filter flag == 1 means that this patch has not been called for photosynthesis this%fates(nc)%bc_in(s)%filter_photo_pa(:) = 1 @@ -768,7 +1324,7 @@ subroutine wrap_btran(this,nc,fn,filterc,soilstate_inst, waterstate_inst, & integer :: j integer :: ifp integer :: p - + associate(& sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) @@ -864,7 +1420,6 @@ subroutine wrap_btran(this,nc,fn,filterc,soilstate_inst, waterstate_inst, & this%fates(nc)%bc_in, & this%fates(nc)%bc_out) - ! ------------------------------------------------------------------------------- ! Convert output BC's ! For CLM/ALM this wrapper provides return variables that should @@ -896,7 +1451,7 @@ subroutine wrap_btran(this,nc,fn,filterc,soilstate_inst, waterstate_inst, & end do end do end associate - return + end subroutine wrap_btran ! ==================================================================================== @@ -908,18 +1463,15 @@ subroutine wrap_photosynthesis(this, nc, bounds, fn, filterp, & use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun use decompMod , only : bounds_type - use clm_time_manager , only : get_step_size use clm_varcon , only : rgas, tfrz, namep - use clm_varpar , only : nlevsoi, mxpft + use clm_varpar , only : nlevsoi use clm_varctl , only : iulog use pftconMod , only : pftcon use perf_mod , only : t_startf, t_stopf use PatchType , only : patch use quadraticMod , only : quadratic - use EDParamsMod , only : ED_val_grperc - use EDSharedParamsMod , only : EDParamsShareInst use EDTypesMod , only : numpft_ed, dinc_ed - use EDtypesMod , only : ed_patch_type, ed_cohort_type, ed_site_type, numpft_ed, numPatchesPerCol + use EDtypesMod , only : ed_patch_type, ed_cohort_type, ed_site_type, numpft_ed use EDEcophysContype , only : EDecophyscon ! @@ -995,11 +1547,11 @@ subroutine wrap_photosynthesis(this, nc, bounds, fn, filterp, & ! Call photosynthesis - call Photosynthesis_ED (this%fates(nc)%nsites, & - this%fates(nc)%sites, & - this%fates(nc)%bc_in, & - this%fates(nc)%bc_out, & - dtime) + call FatesPlantRespPhotosynthDrive (this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%fates(nc)%bc_in, & + this%fates(nc)%bc_out, & + dtime) ! Perform a double check to see if all patches on naturally vegetated columns ! were activated for photosynthesis @@ -1027,20 +1579,22 @@ subroutine wrap_photosynthesis(this, nc, bounds, fn, filterp, & end associate call t_stopf('edpsn') - return + end subroutine wrap_photosynthesis ! ====================================================================================== subroutine wrap_accumulatefluxes(this, nc, fn, filterp) - - ! !ARGUMENTS: - class(hlm_fates_interface_type), intent(inout) :: this - integer , intent(in) :: nc ! clump index - integer , intent(in) :: fn ! size of pft filter - integer , intent(in) :: filterp(fn) ! pft filter - integer :: s,c,p,ifp,icp + ! !ARGUMENTS: + class(hlm_fates_interface_type), intent(inout) :: this + integer , intent(in) :: nc ! clump index + integer , intent(in) :: fn ! size of pft filter + integer , intent(in) :: filterp(fn) ! pft filter + + integer :: s,c,p,ifp,icp + real(r8) :: dtime + ! Run a check on the filter do icp = 1,fn @@ -1053,12 +1607,19 @@ subroutine wrap_accumulatefluxes(this, nc, fn, filterp) end if end do - call AccumulateFluxes_ED(this%fates(nc)%nsites, & - this%fates(nc)%sites, & - this%fates(nc)%bc_in, & - this%fates(nc)%bc_out) - return + dtime = get_step_size() + call AccumulateFluxes_ED(this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%fates(nc)%bc_in, & + this%fates(nc)%bc_out, & + dtime) + + + call this%fates_hist%update_history_prod(nc, & + this%fates(nc)%nsites, & + this%fates(nc)%sites, & + dtime) end subroutine wrap_accumulatefluxes @@ -1146,48 +1707,614 @@ subroutine wrap_canopy_radiation(this, bounds_clump, nc, & end associate - return end subroutine wrap_canopy_radiation ! ====================================================================================== - - subroutine wrap_litter_fluxout(this, nc, bounds_clump, canopystate_inst, soilbiogeochem_carbonflux_inst) - - implicit none - + + subroutine wrap_bgc_summary(this, nc, soilbiogeochem_carbonflux_inst, & + soilbiogeochem_carbonstate_inst) + + + + ! Arguments + class(hlm_fates_interface_type), intent(inout) :: this + integer , intent(in) :: nc + type(soilbiogeochem_carbonflux_type), intent(in) :: soilbiogeochem_carbonflux_inst + type(soilbiogeochem_carbonstate_type), intent(in) :: soilbiogeochem_carbonstate_inst + + ! locals + real(r8) :: dtime + integer :: nstep + logical :: is_beg_day + integer :: s,c + + associate(& + hr => soilbiogeochem_carbonflux_inst%hr_col, & ! (gC/m2/s) total heterotrophic respiration + totsomc => soilbiogeochem_carbonstate_inst%totsomc_col, & ! (gC/m2) total soil organic matter carbon + totlitc => soilbiogeochem_carbonstate_inst%totlitc_col) ! (gC/m2) total litter carbon in BGC pools + + ! Summarize Net Fluxes + do s = 1, this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + this%fates(nc)%bc_in(s)%tot_het_resp = hr(c) + this%fates(nc)%bc_in(s)%tot_somc = totsomc(c) + this%fates(nc)%bc_in(s)%tot_litc = totlitc(c) + end do + + is_beg_day = is_beg_curr_day() + dtime = get_step_size() + nstep = get_nstep() + + call SummarizeNetFluxes(this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%fates(nc)%bc_in, & + is_beg_day) + + + call FATES_BGC_Carbon_Balancecheck(this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%fates(nc)%bc_in, & + is_beg_day, & + dtime, nstep) + + + ! Update history variables that track these variables + call this%fates_hist%update_history_cbal(nc, & + this%fates(nc)%nsites, & + this%fates(nc)%sites) + + + end associate + end subroutine wrap_bgc_summary + + ! ====================================================================================== + + + subroutine TransferZ0mDisp(this,bounds_clump,frictionvel_inst,canopystate_inst) + ! Arguments class(hlm_fates_interface_type), intent(inout) :: this - integer , intent(in) :: nc type(bounds_type),intent(in) :: bounds_clump - type(canopystate_type) , intent(inout) :: canopystate_inst - type(soilbiogeochem_carbonflux_type), intent(inout) :: soilbiogeochem_carbonflux_inst - - ! local variables - integer :: s, c - - - ! process needed input boundary conditions to define rooting profiles - ! call subroutine to aggregate ED litter output fluxes and package them for handing across interface - ! process output into the dimensions that the BGC model wants (column, depth, and litter fractions) + type(canopystate_type) , intent(inout) :: canopystate_inst + type(frictionvel_type) , intent(inout) :: frictionvel_inst + + ! Locals + integer :: ci ! Current clump index + integer :: s ! Site index + integer :: c ! Column index + integer :: ifp ! Fates patch index + integer :: p ! CLM patch index + + ci = bounds_clump%clump_index + + do s = 1, this%fates(ci)%nsites + c = this%f2hmap(ci)%fcolumn(s) + + frictionvel_inst%z0m_patch(col%patchi(c)+1:col%patchf(c)) = 0.0_r8 + canopystate_inst%displa_patch(col%patchi(c)+1:col%patchf(c)) = 0.0_r8 + + do ifp = 1, this%fates(ci)%sites(s)%youngest_patch%patchno + p = ifp+col%patchi(c) + frictionvel_inst%z0m_patch(p) = this%fates(ci)%bc_out(s)%z0m_pa(ifp) + canopystate_inst%displa_patch(p) = this%fates(ci)%bc_out(s)%displa_pa(ifp) + end do + end do + + return + end subroutine TransferZ0mDisp + + ! ====================================================================================== + + subroutine init_history_io(this,bounds_proc) + + use histFileMod, only : hist_addfld1d, hist_addfld2d, hist_addfld_decomp + + use FatesConstantsMod, only : fates_short_string_length, fates_long_string_length + use FatesIOVariableKindMod, only : patch_r8, patch_ground_r8, patch_size_pft_r8 + use FatesIOVariableKindMod, only : site_r8, site_ground_r8, site_size_pft_r8 + use FatesIOVariableKindMod, only : site_size_r8, site_pft_r8, site_age_r8 + use FatesIOVariableKindMod, only : site_fuel_r8, site_cwdsc_r8, site_scag_r8 + use FatesIOVariableKindMod, only : site_can_r8, site_cnlf_r8, site_cnlfpft_r8 + use FatesIODimensionsMod, only : fates_bounds_type + + + ! Arguments + class(hlm_fates_interface_type), intent(inout) :: this + type(bounds_type),intent(in) :: bounds_proc ! Currently "proc" + + + ! Locals + type(bounds_type) :: bounds_clump + integer :: nvar ! number of IO variables found + integer :: ivar ! variable index 1:nvar + integer :: nc ! thread counter 1:nclumps + integer :: nclumps ! number of threads on this proc + integer :: s ! FATES site index + integer :: c ! ALM/CLM column index + character(len=fates_short_string_length) :: dim2name + character(len=fates_long_string_length) :: ioname + integer :: d_index, dk_index + + type(fates_bounds_type) :: fates_bounds + type(fates_bounds_type) :: fates_clump + + ! This routine initializes the types of output variables + ! not the variables themselves, just the types + ! --------------------------------------------------------------------------------- + + nclumps = get_proc_clumps() + + ! ------------------------------------------------------------------------------------ + ! PART I: Set FATES DIMENSIONING INFORMATION + ! + ! ------------------------------------------------------------------------------- + ! Those who wish add variables that require new dimensions, please + ! see FATES: FatesHistoryInterfaceMod.F90. Dimension types are defined at the top of the + ! module, and a new explicitly named instance of that type should be created. + ! With this new dimension, a new output type/kind can contain that dimension. + ! A new type/kind can be added to the dim_kinds structure, which defines its members + ! in created in init_dim_kinds_maps(). Make sure to increase the size of fates_num_dim_kinds. + ! A type/kind of output is defined by the data type (ie r8,int,..) + ! and the dimensions. Keep in mind that 3D variables (or 4D if you include time) + ! are not really supported in CLM/ALM right now. There are ways around this + ! limitations by creating combined dimensions, for instance the size+pft dimension + ! "scpf" + ! ------------------------------------------------------------------------------------ + + call hlm_bounds_to_fates_bounds(bounds_proc, fates_bounds) + + call this%fates_hist%Init(nclumps, fates_bounds) + + ! Define the bounds on the first dimension for each thread + !$OMP PARALLEL DO PRIVATE (nc,bounds_clump,fates_clump) + do nc = 1,nclumps + + call get_clump_bounds(nc, bounds_clump) + + ! thread bounds for patch + call hlm_bounds_to_fates_bounds(bounds_clump, fates_clump) + call this%fates_hist%SetThreadBoundsEach(nc, fates_clump) + end do + !$OMP END PARALLEL DO + + ! ------------------------------------------------------------------------------------ + ! PART I.5: SET SOME INDEX MAPPINGS SPECIFICALLY FOR SITE<->COLUMN AND PATCH + ! ------------------------------------------------------------------------------------ + + !$OMP PARALLEL DO PRIVATE (nc,s,c) + do nc = 1,nclumps + + allocate(this%fates_hist%iovar_map(nc)%site_index(this%fates(nc)%nsites)) + allocate(this%fates_hist%iovar_map(nc)%patch1_index(this%fates(nc)%nsites)) + + do s=1,this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + this%fates_hist%iovar_map(nc)%site_index(s) = c + this%fates_hist%iovar_map(nc)%patch1_index(s) = col%patchi(c)+1 + end do + + end do + !$OMP END PARALLEL DO + + ! ------------------------------------------------------------------------------------ + ! PART II: USE THE JUST DEFINED DIMENSIONS TO ASSEMBLE THE VALID IO TYPES + ! INTERF-TODO: THESE CAN ALL BE EMBEDDED INTO A SUBROUTINE IN HISTORYIOMOD + ! ------------------------------------------------------------------------------------ + call this%fates_hist%assemble_history_output_types() + + ! ------------------------------------------------------------------------------------ + ! PART III: DEFINE THE LIST OF OUTPUT VARIABLE OBJECTS, AND REGISTER THEM WITH THE + ! HLM ACCORDING TO THEIR TYPES + ! ------------------------------------------------------------------------------------ + call this%fates_hist%initialize_history_vars() + nvar = this%fates_hist%num_history_vars() + + do ivar = 1, nvar + + associate( vname => this%fates_hist%hvars(ivar)%vname, & + vunits => this%fates_hist%hvars(ivar)%units, & + vlong => this%fates_hist%hvars(ivar)%long, & + vdefault => this%fates_hist%hvars(ivar)%use_default, & + vavgflag => this%fates_hist%hvars(ivar)%avgflag) + + dk_index = this%fates_hist%hvars(ivar)%dim_kinds_index + ioname = trim(this%fates_hist%dim_kinds(dk_index)%name) + + select case(trim(ioname)) + case(patch_r8) + call hist_addfld1d(fname=trim(vname),units=trim(vunits), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_patch=this%fates_hist%hvars(ivar)%r81d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + + case(site_r8) + call hist_addfld1d(fname=trim(vname),units=trim(vunits), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r81d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + + case(patch_ground_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & ! <--- addfld2d + type2d=trim(dim2name), & ! <--- type2d + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_patch=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + + case(patch_size_pft_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_patch=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_ground_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_size_pft_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_size_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_pft_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_age_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_fuel_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_cwdsc_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_can_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_cnlf_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_cnlfpft_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + case(site_scag_r8) + d_index = this%fates_hist%dim_kinds(dk_index)%dim2_index + dim2name = this%fates_hist%dim_bounds(d_index)%name + call hist_addfld2d(fname=trim(vname),units=trim(vunits), & + type2d=trim(dim2name), & + avgflag=trim(vavgflag),long_name=trim(vlong), & + ptr_col=this%fates_hist%hvars(ivar)%r82d, & + default=trim(vdefault), & + set_lake=0._r8,set_urb=0._r8) + + + case default + write(iulog,*) 'A FATES iotype was created that was not registerred' + write(iulog,*) 'in CLM.:',trim(ioname) + call endrun(msg=errMsg(sourcefile, __LINE__)) + end select + + end associate + end do + end subroutine init_history_io + + ! ====================================================================================== + + subroutine init_soil_depths(this, nc) + ! Input Arguments + class(hlm_fates_interface_type), intent(inout) :: this + integer,intent(in) :: nc ! Clump + + ! Locals + integer :: s ! site index + integer :: c ! column index + integer :: j ! Depth index + + do s = 1, this%fates(nc)%nsites c = this%f2hmap(nc)%fcolumn(s) - this%fates(nc)%bc_in(s)%max_rooting_depth_index_col = canopystate_inst%altmax_lastyear_indx_col(c) + this%fates(nc)%bc_in(s)%zi_sisl(0:hlm_numlevsoil) = col%zi(c,0:hlm_numlevsoil) + this%fates(nc)%bc_in(s)%dz_sisl(1:hlm_numlevsoil) = col%dz(c,1:hlm_numlevsoil) + this%fates(nc)%bc_in(s)%z_sisl(1:hlm_numlevsoil) = col%z(c,1:hlm_numlevsoil) + this%fates(nc)%bc_in(s)%dz_decomp_sisl(1:hlm_numlevdecomp_full) = & + dzsoi_decomp(1:hlm_numlevdecomp_full) end do + + return + end subroutine init_soil_depths + + ! ====================================================================================== + + subroutine ComputeRootSoilFlux(this, bounds_clump, num_filterc, filterc, & + soilstate_inst, waterflux_inst) + + class(hlm_fates_interface_type), intent(inout) :: this + type(bounds_type),intent(in) :: bounds_clump + integer,intent(in) :: num_filterc + integer,intent(in) :: filterc(num_filterc) + type(soilstate_type), intent(inout) :: soilstate_inst + type(waterflux_type), intent(inout) :: waterflux_inst - call flux_into_litter_pools(this%fates(nc)%nsites, & - this%fates(nc)%sites, & - this%fates(nc)%bc_in, & - this%fates(nc)%bc_out) + ! locals + integer :: s + integer :: c + integer :: l + integer :: nc + integer :: num_filter_fates + + + if( .not. use_fates_plant_hydro ) return + + nc = bounds_clump%clump_index + + ! Perform a check that the number of columns submitted to fates for + ! root water sink is the same that was expected in the hydrology filter + num_filter_fates = 0 + do s = 1,num_filterc + l = col%landunit(filterc(s)) + if (lun%itype(l) == istsoil ) then + num_filter_fates = num_filter_fates + 1 + end if + end do + + if(num_filter_fates .ne. this%fates(nc)%nsites )then + write(iulog,*) 'The HLM list of natural veg columns during root water transfer' + write(iulog,*) 'is not the same size as the fates site list?' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if do s = 1, this%fates(nc)%nsites c = this%f2hmap(nc)%fcolumn(s) - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lab_c_col(c,:) = this%fates(nc)%bc_out(s)%FATES_c_to_litr_lab_c_col(:) - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_cel_c_col(c,:) = this%fates(nc)%bc_out(s)%FATES_c_to_litr_cel_c_col(:) - soilbiogeochem_carbonflux_inst%FATES_c_to_litr_lig_c_col(c,:) = this%fates(nc)%bc_out(s)%FATES_c_to_litr_lig_c_col(:) + waterflux_inst%qflx_rootsoi_col(c,:) = this%fates(nc)%bc_out(s)%qflx_soil2root_sisl(:) end do + + end subroutine ComputeRootSoilFlux + ! ====================================================================================== +! +! THIS WAS MOVED TO WRAP_HYDRAULICS_DRIVE() +! +! subroutine TransferPlantWaterStorage(this, bounds_clump, nc, waterstate_inst) +! +! implicit none +! class(hlm_fates_interface_type), intent(inout) :: this +! type(bounds_type),intent(in) :: bounds_clump +! integer,intent(in) :: nc +! type(waterstate_type) , intent(inout) :: waterstate_inst +! +! ! locals +! integer :: s +! integer :: c +! +! if (.not. (use_fates .and. use_fates_plant_hydro) ) return +! +! do s = 1, this%fates(nc)%nsites +! c = this%f2hmap(nc)%fcolumn(s) +! waterstate_inst%total_plant_stored_h2o_col(c) = & +! this%fates(nc)%bc_out(s)%plant_stored_h2o_si +! end do +! return +!end subroutine TransferPlantWaterStorage + + + + + ! ====================================================================================== + + subroutine wrap_hydraulics_drive(this, bounds_clump, nc, & + soilstate_inst, waterstate_inst, waterflux_inst, & + solarabs_inst, energyflux_inst) + + + implicit none + class(hlm_fates_interface_type), intent(inout) :: this + type(bounds_type),intent(in) :: bounds_clump + integer,intent(in) :: nc + type(soilstate_type) , intent(inout) :: soilstate_inst + type(waterstate_type) , intent(inout) :: waterstate_inst + type(waterflux_type) , intent(inout) :: waterflux_inst + type(solarabs_type) , intent(inout) :: solarabs_inst + type(energyflux_type) , intent(inout) :: energyflux_inst + + ! locals + integer :: s + integer :: c + integer :: j + integer :: ifp + integer :: p + real(r8) :: dtime + + + if ( .not.use_fates_plant_hydro ) return + + + dtime = get_step_size() + + ! Prepare Input Boundary Conditions + ! ------------------------------------------------------------------------------------ + + do s = 1, this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + this%fates(nc)%bc_in(s)%smpmin_si = & + soilstate_inst%smpmin_col(c) + this%fates(nc)%bc_in(s)%watsat_sisl(1:nlevsoi) = & + soilstate_inst%watsat_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%watres_sisl(1:nlevsoi) = & + soilstate_inst%watres_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%sucsat_sisl(1:nlevsoi) = & + soilstate_inst%sucsat_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%bsw_sisl(1:nlevsoi) = & + soilstate_inst%bsw_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%h2o_liq_sisl(1:nlevsoi) = & + waterstate_inst%h2osoi_liq_col(c,1:nlevsoi) + this%fates(nc)%bc_in(s)%eff_porosity_gl(1:nlevsoi) = & + soilstate_inst%eff_porosity_col(c,1:nlevsoi) + + do ifp = 1, this%fates(nc)%sites(s)%youngest_patch%patchno + p = ifp+col%patchi(c) + this%fates(nc)%bc_in(s)%swrad_net_pa(ifp) = solarabs_inst%fsa_patch(p) + this%fates(nc)%bc_in(s)%lwrad_net_pa(ifp) = energyflux_inst%eflx_lwrad_net_patch(p) + this%fates(nc)%bc_in(s)%qflx_transp_pa(ifp) = waterflux_inst%qflx_tran_veg_patch(p) + end do + end do + + ! Call Fates Hydraulics + ! ------------------------------------------------------------------------------------ + + + call hydraulics_drive(this%fates(nc)%nsites, & + this%fates(nc)%sites, & + this%fates(nc)%bc_in, & + this%fates(nc)%bc_out, & + dtime) + + ! Prepare Output Boundary Conditions + ! ------------------------------------------------------------------------------------ + + do s = 1, this%fates(nc)%nsites + c = this%f2hmap(nc)%fcolumn(s) + waterstate_inst%total_plant_stored_h2o_col(c) = & + this%fates(nc)%bc_out(s)%plant_stored_h2o_si + end do - end subroutine wrap_litter_fluxout + + ! Update History Buffers that need to be updated after hydraulics calls + + call this%fates_hist%update_history_hydraulics(nc, & + this%fates(nc)%nsites, & + this%fates(nc)%sites, & + dtime) + + + return + end subroutine wrap_hydraulics_drive + + ! ====================================================================================== + + subroutine hlm_bounds_to_fates_bounds(hlm, fates) + + use FatesIODimensionsMod, only : fates_bounds_type + use EDtypesMod, only : nlevsclass_ed, nlevage_ed + use EDtypesMod, only : nfsc, ncwd + use EDtypesMod, only : nlevleaf, nclmax, numpft_ed + use EDTypesMod, only : maxpft + use clm_varpar, only : nlevgrnd + + implicit none + + type(bounds_type), intent(in) :: hlm + type(fates_bounds_type), intent(out) :: fates + + fates%cohort_begin = hlm%begcohort + fates%cohort_end = hlm%endcohort + + fates%patch_begin = hlm%begp + fates%patch_end = hlm%endp + + fates%column_begin = hlm%begc + fates%column_end = hlm%endc + + fates%ground_begin = 1 + fates%ground_end = nlevgrnd + + fates%sizepft_class_begin = 1 + fates%sizepft_class_end = nlevsclass_ed * maxpft + + fates%size_class_begin = 1 + fates%size_class_end = nlevsclass_ed + + fates%pft_class_begin = 1 + fates%pft_class_end = maxpft + + fates%age_class_begin = 1 + fates%age_class_end = nlevage_ed + + fates%sizeage_class_begin = 1 + fates%sizeage_class_end = nlevsclass_ed * nlevage_ed + + fates%fuel_begin = 1 + fates%fuel_end = nfsc + + fates%cwdsc_begin = 1 + fates%cwdsc_end = ncwd + + fates%can_begin = 1 + fates%can_end = nclmax + + fates%cnlf_begin = 1 + fates%cnlf_end = nlevleaf * nclmax + + fates%cnlfpft_begin = 1 + fates%cnlfpft_end = nlevleaf * nclmax * numpft_ed + + end subroutine hlm_bounds_to_fates_bounds end module CLMFatesInterfaceMod diff --git a/src/utils/clmfates_paraminterfaceMod.F90 b/src/utils/clmfates_paraminterfaceMod.F90 new file mode 100644 index 0000000000..ff70fc8c03 --- /dev/null +++ b/src/utils/clmfates_paraminterfaceMod.F90 @@ -0,0 +1,238 @@ +module CLMFatesParamInterfaceMod + ! NOTE(bja, 2017-01) this code can not go into the main clm-fates + ! interface module because of circular dependancies with pftvarcon. + + use FatesGlobals, only : fates_log + + implicit none + + ! NOTE(bja, 2017-01) these methods can NOT be part of the clmi-fates + ! nterface type because they are called before the instance is + ! initialized. + public :: FatesReadParameters + public :: FatesReadPFTs + private :: ParametersFromNetCDF + private :: SetParameterDimensions + private :: GetUsedDimensionSizes + + logical :: DEBUG = .false. + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + +contains + + !----------------------------------------------------------------------- + subroutine FatesReadParameters() + + use clm_varctl, only : use_fates, paramfile, fates_paramfile + use spmdMod, only : masterproc + + use FatesParametersInterface, only : fates_parameters_type + + use EDParamsMod, only : FatesRegisterParams, FatesReceiveParams + use SFParamsMod, only : SpitFireRegisterParams, SpitFireReceiveParams + use FatesSynchronizedParamsMod, only : FatesSynchronizedParamsInst + + implicit none + + character(len=32) :: subname = 'FatesReadParameters' + class(fates_parameters_type), allocatable :: fates_params + logical :: is_host_file + + if (use_fates) then + if (masterproc) then + write(fates_log(), *) 'clmfates_interfaceMod.F90::'//trim(subname)//' :: CLM reading ED/FATES '//' parameters ' + end if + + allocate(fates_params) + call fates_params%Init() + call FatesRegisterParams(fates_params) + call SpitFireRegisterParams(fates_params) + call FatesSynchronizedParamsInst%RegisterParams(fates_params) + + is_host_file = .false. + call ParametersFromNetCDF(fates_paramfile, is_host_file, fates_params) + + is_host_file = .true. + call ParametersFromNetCDF(paramfile, is_host_file, fates_params) + + call FatesReceiveParams(fates_params) + call SpitFireReceiveParams(fates_params) + call FatesSynchronizedParamsInst%ReceiveParams(fates_params) + + call fates_params%Destroy() + deallocate(fates_params) + end if + + end subroutine FatesReadParameters + + !----------------------------------------------------------------------- + subroutine FatesReadPFTs() + + use clm_varctl, only : use_fates, paramfile, fates_paramfile + use spmdMod, only : masterproc + + use FatesParametersInterface, only : fates_parameters_type + use EDPftvarcon , only : EDPftvarcon_inst + + use fileutils , only : getfil + use ncdio_pio , only : file_desc_t, ncd_pio_closefile, ncd_pio_openfile + + implicit none + + character(len=32) :: subname = 'FatesReadPFTs' + class(fates_parameters_type), allocatable :: fates_params + logical :: is_host_file + + character(len=256) :: locfn ! local file name + type(file_desc_t) :: ncid ! pio netCDF file id + + if (use_fates) then + if (masterproc) then + write(fates_log(), *) 'clmfates_interfaceMod.F90::'//trim(subname)//' :: CLM reading ED/FATES '//' PFTs ' + end if + + allocate(fates_params) + call fates_params%Init() + call EDPftvarcon_inst%Init() + + call EDPftvarcon_inst%Register(fates_params) + + is_host_file = .false. + call ParametersFromNetCDF(fates_paramfile, is_host_file, fates_params) + + is_host_file = .true. + call ParametersFromNetCDF(paramfile, is_host_file, fates_params) + + call EDPftvarcon_inst%Receive(fates_params) + + call fates_params%Destroy() + deallocate(fates_params) + end if + + end subroutine FatesReadPFTs + + !----------------------------------------------------------------------- + subroutine SetParameterDimensions(ncid, is_host_file, fates_params) + ! Get the list of dimensions used by the fates parameters, + ! retreive them from the parameter file, then give the information + ! back to fates. + use FatesParametersInterface, only : fates_parameters_type, param_string_length, max_dimensions, max_used_dimensions + use ncdio_pio , only : file_desc_t + + implicit none + + type(file_desc_t), intent(inout) :: ncid + logical, intent(in) :: is_host_file + class(fates_parameters_type), intent(inout) :: fates_params + + integer :: num_used_dimensions + character(len=param_string_length) :: used_dimension_names(max_used_dimensions) + integer :: used_dimension_sizes(max_used_dimensions) + + call fates_params%GetUsedDimensions(is_host_file, num_used_dimensions, used_dimension_names) + + call GetUsedDimensionSizes(ncid, num_used_dimensions, used_dimension_names, used_dimension_sizes) + + call fates_params%SetDimensionSizes(is_host_file, num_used_dimensions, used_dimension_names, used_dimension_sizes) + + end subroutine SetParameterDimensions + + !----------------------------------------------------------------------- + subroutine GetUsedDimensionSizes(ncid, num_used_dimensions, dimension_names, dimension_sizes) + + use ncdio_pio , only : ncd_inqdid, ncd_inqdlen + use FatesParametersInterface, only : param_string_length + use ncdio_pio, only : file_desc_t + + + implicit none + + type(file_desc_t), intent(inout) :: ncid + integer, intent(in) :: num_used_dimensions + character(len=param_string_length), intent(in) :: dimension_names(:) + integer, intent(out) :: dimension_sizes(:) + + integer :: d, max_dim_size, num_dims + integer :: dim_len, dim_id + + dimension_sizes(:) = 0 + max_dim_size = 0 + + do d = 1, num_used_dimensions + call ncd_inqdid(ncid, dimension_names(d), dim_id) + call ncd_inqdlen(ncid, dim_id, dim_len) + dimension_sizes(d) = dim_len + !write(*, *) '--> ', trim(dimension_names(d)), ' setting size ', dimension_sizes(d) + end do + + end subroutine GetUsedDimensionSizes + + !----------------------------------------------------------------------- + subroutine ParametersFromNetCDF(filename, is_host_file, fates_params) + + use shr_kind_mod, only: r8 => shr_kind_r8 + use abortutils, only : endrun + use fileutils , only : getfil + use ncdio_pio , only : file_desc_t, ncd_pio_closefile, ncd_pio_openfile + use paramUtilMod, only : readNcdio + + use FatesParametersInterface, only : fates_parameters_type + use FatesParametersInterface, only : param_string_length, max_dimensions, max_used_dimensions + use FatesParametersInterface, only : dimension_shape_scalar, dimension_shape_1d, dimension_shape_2d + + implicit none + + character(len=*), intent(in) :: filename + logical, intent(in) :: is_host_file + class(fates_parameters_type), intent(inout) :: fates_params + + character(len=32) :: subname = 'clmfates_interface::ReadParameters' + character(len=256) :: locfn ! local file name + type(file_desc_t) :: ncid ! pio netCDF file id + integer :: dimid ! netCDF dimension id + integer :: i, num_params, dimension_shape + integer :: max_dim_size + real(r8), allocatable :: data(:, :) + character(len=param_string_length) :: name + integer :: dimension_sizes(max_dimensions) + character(len=param_string_length) :: dimension_names(max_dimensions) + integer :: size_dim_1, size_dim_2 + logical :: is_host_param + + call getfil (filename, locfn, 0) + call ncd_pio_openfile (ncid, trim(locfn), 0) + + call SetParameterDimensions(ncid, is_host_file, fates_params) + max_dim_size = fates_params%GetMaxDimensionSize() + allocate(data(max_dim_size, max_dim_size)) + + num_params = fates_params%num_params() + do i = 1, num_params + call fates_params%GetMetaData(i, name, dimension_shape, dimension_sizes, dimension_names, is_host_param) + if (is_host_file .eqv. is_host_param) then + select case(dimension_shape) + case(dimension_shape_scalar) + size_dim_1 = 1 + size_dim_2 = 1 + case(dimension_shape_1d) + size_dim_1 = dimension_sizes(1) + size_dim_2 = 1 + case(dimension_shape_2d) + size_dim_1 = dimension_sizes(1) + size_dim_2 = dimension_sizes(2) + case default + call endrun(msg='unsupported number of dimensions reading parameters.') + end select + write(fates_log(), *) 'clmfates_interfaceMod.F90:: reading '//trim(name) + call readNcdio(ncid, name, dimension_shape, dimension_names, subname, data(1:size_dim_1, 1:size_dim_2)) + call fates_params%SetData(i, data(1:size_dim_1, 1:size_dim_2)) + end if + end do + deallocate(data) + call ncd_pio_closefile(ncid) + end subroutine ParametersFromNetCDF + !----------------------------------------------------------------------- + +end module CLMFatesParamInterfaceMod diff --git a/src/utils/quadraticMod.F90 b/src/utils/quadraticMod.F90 index d6540546f9..615547227c 100644 --- a/src/utils/quadraticMod.F90 +++ b/src/utils/quadraticMod.F90 @@ -35,17 +35,28 @@ subroutine quadratic (a, b, c, r1, r2) ! ! !LOCAL VARIABLES: real(r8) :: q ! Temporary term for quadratic solution + real(r8) :: root ! Term that will have a square root taken !------------------------------------------------------------------------------ if (a == 0._r8) then write (iulog,*) 'Quadratic solution error: a = ',a call endrun(msg=errmsg(sourcefile, __LINE__)) end if + + root = b*b - 4._r8*a*c + if ( root < 0.0 )then + if ( sqrt(-root) > epsilon(b) )then + root = 0.0_r8 + else + write (iulog,*) 'Quadratic solution error: b^2 - 4ac is negative = ', root + call endrun(msg=errmsg(sourcefile, __LINE__)) + end if + end if if (b >= 0._r8) then - q = -0.5_r8 * (b + sqrt(b*b - 4._r8*a*c)) + q = -0.5_r8 * (b + sqrt(root)) else - q = -0.5_r8 * (b - sqrt(b*b - 4._r8*a*c)) + q = -0.5_r8 * (b - sqrt(root)) end if r1 = q / a diff --git a/src/utils/restUtilMod.F90.in b/src/utils/restUtilMod.F90.in index dccb298a1f..cda77ccd84 100644 --- a/src/utils/restUtilMod.F90.in +++ b/src/utils/restUtilMod.F90.in @@ -8,7 +8,7 @@ module restUtilMod use shr_kind_mod, only: r8=>shr_kind_r8, r4 => shr_kind_r4, i4=>shr_kind_i4 use shr_sys_mod, only: shr_sys_abort use spmdMod, only: masterproc - use clm_varctl, only: iulog + use clm_varctl, only: iulog, nsrest, nsrContinue, nsrBranch use clm_varcon, only: spval, ispval use decompMod, only: bounds_type use ncdio_pio @@ -53,7 +53,7 @@ module restUtilMod end interface set_missing_vals_to_constant public :: set_missing_vals_to_constant - private :: is_restart + private :: missing_field_possibly_abort character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -186,7 +186,9 @@ contains end if if (flag == 'read') then - if (.not. readvar .and. is_restart()) call shr_sys_abort() + if (.not. readvar) then + call missing_field_possibly_abort(my_varname) + end if end if end subroutine restartvar_{DIMS}d_{TYPE} @@ -338,7 +340,9 @@ contains end if if (flag == 'read') then - if (.not. readvar .and. is_restart()) call shr_sys_abort() + if (.not. readvar) then + call missing_field_possibly_abort(my_varname) + end if end if end subroutine restartvar_{DIMS}d_{TYPE} @@ -501,7 +505,9 @@ contains end if if (flag == 'read') then - if (.not. readvar .and. is_restart()) call shr_sys_abort() + if (.not. readvar) then + call missing_field_possibly_abort(my_varname) + end if end if end subroutine restartvar_2d_{TYPE}_bounds @@ -617,17 +623,42 @@ contains end subroutine set_missing_vals_to_constant_{DIMS}d - - !----------------------------------------------------------------------- - logical function is_restart( ) - ! Determine if restart run - use clm_varctl, only : nsrest, nsrContinue - if (nsrest == nsrContinue) then - is_restart = .true. - else - is_restart = .false. + subroutine missing_field_possibly_abort(varname) + ! + ! !DESCRIPTION: + ! This should be called if a field is missing from the restart file. It aborts with a + ! helpful error message if this run is one where a missing field is treated as an + ! error (e.g., a restart run). + ! + ! !ARGUMENTS: + character(len=*), intent(in) :: varname ! name of variable that triggered the error + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'missing_field_possibly_abort' + !----------------------------------------------------------------------- + + if (nsrest == nsrContinue .or. & + nsrest == nsrBranch) then + if (masterproc) then + write(iulog,*) 'ERROR: Field missing from restart file: ', trim(varname) + write(iulog,*) 'Missing fields are not allowed in branch or continue (restart) runs.' + write(iulog,*) ' ' + write(iulog,*) 'This can happen when the restart file is from a different' + write(iulog,*) 'model configuration or different code base, which did not' + write(iulog,*) 'contain all of the restart fields needed for the current' + write(iulog,*) 'code base and configuration.' + write(iulog,*) ' ' + write(iulog,*) 'You can get around this problem by doing a startup or hybrid run' + write(iulog,*) 'that points to this initial condition file, instead of attempting' + write(iulog,*) 'a branch or continue run. However, note that, in many cases,' + write(iulog,*) 'this will result in the missing fields being filled in with' + write(iulog,*) 'their cold start initialization values, which may or may not' + write(iulog,*) 'be what you want.' + end if + call shr_sys_abort('Field missing from restart file.') end if - end function is_restart + end subroutine missing_field_possibly_abort end module restUtilMod diff --git a/src_clm40/main/GetGlobalValuesMod.F90 b/src_clm40/main/GetGlobalValuesMod.F90 index 9bcac2385c..bfe99b3361 100644 --- a/src_clm40/main/GetGlobalValuesMod.F90 +++ b/src_clm40/main/GetGlobalValuesMod.F90 @@ -56,7 +56,7 @@ integer function GetGlobalIndex(decomp_index, clmlevel) end if call get_clmlevel_gsmap(clmlevel=trim(clmlevel), gsmap=gsmap) - call mct_gsmap_op(gsmap, iam, gsmap_ordered) + call mct_gsmap_orderedPoints(gsmap, iam, gsmap_ordered) GetGlobalIndex = gsmap_ordered(decomp_index - beg_index + 1) deallocate(gsmap_ordered) diff --git a/src_clm40/main/ncdio_pio.F90.in b/src_clm40/main/ncdio_pio.F90.in index a95a347624..de38171f6c 100644 --- a/src_clm40/main/ncdio_pio.F90.in +++ b/src_clm40/main/ncdio_pio.F90.in @@ -24,7 +24,7 @@ module ncdio_pio use decompMod , only : get_clmlevel_gsize,get_clmlevel_gsmap use perf_mod , only : t_startf, t_stopf use fileutils , only : getavu, relavu - use mct_mod , only : mct_gsMap, mct_gsMap_lsize, mct_gsMap_gsize, mct_gsMap_OP + use mct_mod , only : mct_gsMap, mct_gsMap_lsize, mct_gsMap_gsize, mct_gsMap_orderedPoints use pio , only : file_desc_t, io_desc_t, iosystem_desc_t, pio_64bit_offset use pio , only : pio_bcast_error, pio_char, pio_clobber, pio_closefile, pio_createfile, pio_def_dim use pio , only : pio_def_var, pio_double, pio_enddef, pio_get_att, pio_get_var, pio_global, pio_initdecomp @@ -2199,7 +2199,7 @@ contains gsmap_lsize = mct_gsmap_lsize(gsmap,mpicom) gsmap_gsize = mct_gsmap_gsize(gsmap) - call mct_gsmap_OP(gsmap,iam,gsmOP) + call mct_gsmap_orderedPoints(gsmap,iam,gsmOP) fullsize = 1 do n = 1,ndims diff --git a/test/tools/TCBCFGtools.sh b/test/tools/TCBCFGtools.sh index e714217d00..bbdd6421c7 100755 --- a/test/tools/TCBCFGtools.sh +++ b/test/tools/TCBCFGtools.sh @@ -85,6 +85,7 @@ if [ $rc -ne 0 ]; then exit 5 fi +. $INITMODULES . ./.env_mach_specific.sh attempt=1 diff --git a/test/tools/TSMCFGtools.sh b/test/tools/TSMCFGtools.sh index 1bbdb7c808..6a8b97ad55 100755 --- a/test/tools/TSMCFGtools.sh +++ b/test/tools/TSMCFGtools.sh @@ -73,10 +73,11 @@ fi echo "Run file type = ${3#*.}" if [ ${3#*.} == "runoptions" ]; then - echo "$toolrun "`cat ${runfile}` + runopts=`cat ${runfile} | sed -e "s|CSMDATA|$CSMDATA|g"` + echo "$toolrun $runopts" cp $cfgdir/*.nc . if [ "$debug" != "YES" ] && [ "$compile_only" != "YES" ]; then - $toolrun `cat ${runfile}` >> test.log 2>&1 + $toolrun $runopts >> test.log 2>&1 rc=$? status="PASS" else diff --git a/test/tools/TSMscript_tools.sh b/test/tools/TSMscript_tools.sh index 5a5ef2d5c1..00aa7b434e 100755 --- a/test/tools/TSMscript_tools.sh +++ b/test/tools/TSMscript_tools.sh @@ -61,7 +61,7 @@ if [[ "$1" == "PTCLM" ]]; then # Copy map files so we can use them subdir=1x1pt_US-UMB mkdir $rundir/$subdir - cp $CSMDATA/lnd/clm2/PTCLMmydatafiles.c160208/$subdir/map_* $rundir/$subdir + cp $CSMDATA/lnd/clm2/PTCLMmydatafiles.c171024/$subdir/map_* $rundir/$subdir elif [ "$optfile" != "$3" ]; then echo "TSMscript_tools.sh: calling TCBtools.sh to prepare $1 executable" ${CLM_SCRIPTDIR}/TCBtools.sh $1 $cfgfile diff --git a/test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 b/test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 index 7a11bd2282..cd22e7e02a 100644 --- a/test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 +++ b/test/tools/nl_files/PTCLM_USUMB_Cycle_clm4_5 @@ -1 +1 @@ --s US-UMB -d CSMDATA --mydatadir . --phys=clm4_5 --map_gdate 160208 --cycle_forcing +-s US-UMB -d CSMDATA --mydatadir . --map_gdate 171024 --cycle_forcing diff --git a/test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 b/test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 index b209d7e682..7ddc02f582 100644 --- a/test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 +++ b/test/tools/nl_files/PTCLM_USUMB_Global_clm4_5 @@ -1 +1 @@ --s US-UMB -d CSMDATA --mydatadir . --phys=clm4_5 --map_gdate 160208 --donot_use_tower_yrs --clmnmlusecase 20thC_transient --pftgrid --soilgrid +-s US-UMB -d CSMDATA --mydatadir . --map_gdate 171024 --donot_use_tower_yrs --clmnmlusecase 20thC_transient --pftgrid --soilgrid diff --git a/test/tools/nl_files/PTCLM_USUMB_clm4_5 b/test/tools/nl_files/PTCLM_USUMB_clm4_5 index c4835ae41e..f651773542 100644 --- a/test/tools/nl_files/PTCLM_USUMB_clm4_5 +++ b/test/tools/nl_files/PTCLM_USUMB_clm4_5 @@ -1 +1 @@ --s US-UMB -d CSMDATA --mydatadir . --phys=clm4_5 --map_gdate 160208 +-s US-UMB -d CSMDATA --mydatadir . --map_gdate 171024 diff --git a/test/tools/nl_files/gen_domain.T31.runoptions b/test/tools/nl_files/gen_domain.T31.runoptions index 0fbe17a9f4..c1fcc07df1 100644 --- a/test/tools/nl_files/gen_domain.T31.runoptions +++ b/test/tools/nl_files/gen_domain.T31.runoptions @@ -1 +1 @@ --m /glade/p/cesm/cseg/inputdata/cpl/cpl6/map_gx3v7_to_T31_aave_da_090903.nc -o domain.ocn.gx3v7_test.nc -l domain.lnd.10x15_gx3v7.test.nc +-m CSMDATA/cpl/cpl6/map_gx3v7_to_T31_aave_da_090903.nc -o domain.ocn.gx3v7_test.nc -l domain.lnd.10x15_gx3v7.test.nc diff --git a/test/tools/nl_files/gen_domain.ne30.runoptions b/test/tools/nl_files/gen_domain.ne30.runoptions index 8dbc853a24..790969101e 100644 --- a/test/tools/nl_files/gen_domain.ne30.runoptions +++ b/test/tools/nl_files/gen_domain.ne30.runoptions @@ -1 +1 @@ --m /glade/p/cesm/cseg/inputdata/cpl/cpl6/map_gx1v6_to_ne30np4_aave_da_091227.nc -o domain.ocn.gx1v6_test.nc -l domain.lnd.ne30np4_gx1v6.test.nc +-m CSMDATA/cpl/cpl6/map_gx1v6_to_ne30np4_aave_da_091227.nc -o domain.ocn.gx1v6_test.nc -l domain.lnd.ne30np4_gx1v6.test.nc diff --git a/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000 b/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000 index d3ec4285bd..af85dcf226 100644 --- a/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000 +++ b/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000 @@ -1 +1 @@ --i CFGDIR/clm4054_ne30g16_I2000.clm2.h0.2000-01_c121107.nc -o ne30output_onf19grid.nc -m CFGDIR/map_ne30np4_nomask_to_fv1.9x2.5_nomask_aave_da_c121107.nc -t CFGDIR/clm4054_f19g16_I2000.clm2.h0.2000-01_c121107.nc -e EXEDIR +-i CSMDATA/lnd/clm2/test_mkprocdata_map/clm4054_ne30g16_I2000.clm2.h0.2000-01_c170430.nc -o ne30output_onf19grid.nc -m CSMDATA/lnd/clm2/test_mkprocdata_map/map_ne30np4_nomask_to_fv1.9x2.5_nomask_aave_da_c121107.nc -t CSMDATA/lnd/clm2/test_mkprocdata_map/clm4054_f19g16_I2000.clm2.h0.2000-01_c170430.nc -e EXEDIR diff --git a/test/tools/nl_files/mksrfdt_10x15_1850 b/test/tools/nl_files/mksrfdt_10x15_1850 index 40add21cb0..daa822804c 100644 --- a/test/tools/nl_files/mksrfdt_10x15_1850 +++ b/test/tools/nl_files/mksrfdt_10x15_1850 @@ -1 +1 @@ --l CSMDATA -r 10x15 -no_crop -y 1850 -exedir EXEDIR +-l CSMDATA -r 10x15 -no-crop -y 1850 -exedir EXEDIR diff --git a/test/tools/nl_files/mksrfdt_1x1_vancouverCAN_2000 b/test/tools/nl_files/mksrfdt_1x1_vancouverCAN_2000 index cc278dd62d..a446e82fcd 100644 --- a/test/tools/nl_files/mksrfdt_1x1_vancouverCAN_2000 +++ b/test/tools/nl_files/mksrfdt_1x1_vancouverCAN_2000 @@ -1 +1 @@ --l CSMDATA -r 1x1_vancouverCAN -no_crop -y 2000 -exedir EXEDIR +-l CSMDATA -r 1x1_vancouverCAN -no-crop -y 2000 -exedir EXEDIR diff --git a/test/tools/test_driver.sh b/test/tools/test_driver.sh index b081169eb3..198d1e9dd6 100755 --- a/test/tools/test_driver.sh +++ b/test/tools/test_driver.sh @@ -25,6 +25,66 @@ cur_time=`date '+%H:%M:%S'` hostname=`hostname` case $hostname in + ##cheyenne + cheyenne*) + submit_script="test_driver_cheyenne${cur_time}.sh" + +##vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv writing to batch script vvvvvvvvvvvvvvvvvvv +cat > ./${submit_script} << EOF +#!/bin/sh +# + +interactive="YES" +input_file="tests_pretag_cheyenne_nompi" +c_threads=36 + + +export INITMODULES="/glade/u/apps/ch/opt/lmod/7.2.1/lmod/lmod/init/sh" +. \$INITMODULES + +module purge +module load ncarenv/1.0 +module load intel/17.0.1 +module load mkl +module load ncarcompilers/0.3.5 +module load netcdf/4.4.1.1 + +module load nco +module load python +module load ncl + + +##omp threads +if [ -z "\$CLM_THREADS" ]; then #threads NOT set on command line + export CLM_THREADS=\$c_threads +fi + +# Stop on first failed test +if [ -z "\$CLM_SOFF" ]; then #CLM_SOFF NOT set + export CLM_SOFF=FALSE +fi + +export CESM_MACH="cheyenne" +export CESM_COMP="intel" + +export NETCDF_DIR=\$NETCDF +export INC_NETCDF=\$NETCDF/include +export LIB_NETCDF=\$NETCDF/lib +export MAKE_CMD="gmake -j " +export CFG_STRING="" +export TOOLS_MAKE_STRING="USER_FC=ifort USER_LINKER=ifort USER_CPPDEFS=-DLINUX" +export MACH_WORKSPACE="/glade/scratch" +export CPRNC_EXE="$CESMDATAROOT/tools/cime/tools/cprnc/cprnc.cheyenne" +dataroot="$CESMDATAROOT" +export TOOLSLIBS="" +export TOOLS_CONF_STRING="" + + +echo_arg="" + +EOF +##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^ + ;; ##yellowstone ys* | caldera* | geyser* | pronghorn*) submit_script="test_driver_yellowstone${cur_time}.sh" @@ -38,7 +98,8 @@ interactive="YES" input_file="tests_pretag_yellowstone_nompi" c_threads=16 -source /glade/apps/opt/lmod/lmod/init/sh +export INITMODULES="/glade/apps/opt/lmod/lmod/init/sh" +. \$INITMODULES module purge module load ncarenv/1.0 @@ -143,13 +204,15 @@ export CESM_MACH="hobart" limit stacksize unlimited limit coredumpsize unlimited -module purge -module load compiler/intel/15.0.2.164 - export CESM_COMP="intel" export TOOLS_MAKE_STRING="USER_FC=ifort USER_CC=icc " -export TOOLS_CONF_STRING="" +export TOOLS_CONF_STRING=" -mpilib mpi-serial" export CFG_STRING="" +export INITMODULES="/usr/share/Modules/init/sh" + +. \$INITMODULES +module purge +module load compiler/intel/15.0.2.164 export NETCDF_DIR=\$NETCDF_PATH export INC_NETCDF=\${NETCDF_PATH}/include @@ -221,7 +284,7 @@ EOF ##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^ ;; * ) - echo "Only setup to work on: yellowstone, hobart, and yong" + echo "Only setup to work on: cheyenne, yellowstone, hobart, and yong" exit diff --git a/test/tools/tests_pretag_cheyenne_nompi b/test/tools/tests_pretag_cheyenne_nompi new file mode 100644 index 0000000000..1795119813 --- /dev/null +++ b/test/tools/tests_pretag_cheyenne_nompi @@ -0,0 +1,15 @@ +smc#4 blc#4 +sme14 ble14 +sme@4 ble@4 +smg54 blg54 +smi24 bli24 +smi53 bli53 +smi54 bli54 +smi57 bli57 +smi58 bli58 +smiS4 bliS4 +smi74 bli74 +smiT4 bliT4 +smf84 blf84 +smfc4 blfc4 +smfg4 blfg4 diff --git a/tools/SVN_EXTERNAL_DIRECTORIES b/tools/SVN_EXTERNAL_DIRECTORIES deleted file mode 100644 index 99a32434ab..0000000000 --- a/tools/SVN_EXTERNAL_DIRECTORIES +++ /dev/null @@ -1 +0,0 @@ -PTCLM https://svn-ccsm-models.cgd.ucar.edu/PTCLM/trunk_tags/PTCLM2_170302 diff --git a/tools/mkmapdata/mkmapdata.sh b/tools/mkmapdata/mkmapdata.sh index 00e25f3eb8..fcf4c075c8 100755 --- a/tools/mkmapdata/mkmapdata.sh +++ b/tools/mkmapdata/mkmapdata.sh @@ -42,14 +42,14 @@ if [ -z "$CSMDATA" ]; then CSMDATA=/glade/p/cesm/cseg/inputdata fi if [ -z "$REGRID_PROC" ]; then - REGRID_PROC=8 + REGRID_PROC=36 fi #---------------------------------------------------------------------- # Usage subroutine usage() { echo "" echo "**********************" - echo "usage on yellowstone:" + echo "usage:" echo "./mkmapdata.sh" echo "" echo "valid arguments: " @@ -67,10 +67,10 @@ usage() { echo " Model output grid type" echo " supported values are [regional,global], (default is global)" echo "[-b|--batch]" - echo " Toggles batch mode usage. If you want to run in batch mode" + echo " Toggles batch mode usage (and run with mpi). If you want to run in batch mode" echo " you need to have a separate batch script for a supported machine" echo " that calls this script interactively - you cannot submit this" - echo " script directory to the batch system" + echo " script directly to the batch system" echo "[-l|--list]" echo " List mapping files required (use check_input_data to get them)" echo " also writes data to $outfilelist" @@ -83,12 +83,15 @@ usage() { echo "" echo " You can also set the following env variables:" echo " ESMFBIN_PATH - Path to ESMF binaries " + echo " (default is determined by machine running on)" echo " CSMDATA ------ Path to CESM input data" - echo " (default is /glade/p/cesm/cseg/inputdata)" + echo " (default is $CSMDATA)" echo " MPIEXEC ------ Name of mpirun executable" - echo " (default is mpirun.lsf)" + echo " (default is determined by machine running on)" echo " REGRID_PROC -- Number of MPI processors to use" - echo " (default is 8)" + echo " (default is $REGRID_PROC)" + echo "" + echo "**defaults can be determined on the machines: cheyenne, yellowstone, or edison" echo "" echo "**pass environment variables by preceding above commands " echo " with 'env var1=setting var2=setting '" @@ -141,8 +144,8 @@ while [ $# -gt 0 ]; do verbose="YES" ;; -b|--batch) - interactive="NO" - ;; + interactive="NO" + ;; -d|--debug) debug="YES" ;; @@ -232,6 +235,10 @@ if [ "$type" = "global" ] && [ `echo "$res" | grep -c "1x1_"` = 1 ]; then echo "This is a regional resolution and yet it is being run as global, set type with '-t' option\n"; exit 1 fi +if [ "$type" = "global" ] && [ `echo "$res" | grep -c "5x5_"` = 1 ]; then + echo "This is a regional resolution and yet it is being run as global, set type with '-t' option\n"; + exit 1 +fi echo "Output grid resolution is $res" if [ -z "$GRIDFILE" ]; then echo "Output grid file was NOT found for this resolution: $res\n"; @@ -254,6 +261,7 @@ fi if [ "$phys" = "clm4_5" ]; then grids=( \ "0.5x0.5_AVHRR" \ + "0.25x0.25_MODIS" \ "0.5x0.5_MODIS" \ "3x3min_LandScan2004" \ "3x3min_MODIS-wCsp" \ @@ -261,13 +269,15 @@ if [ "$phys" = "clm4_5" ]; then "5x5min_nomask" \ "5x5min_IGBP-GSDP" \ "5x5min_ISRIC-WISE" \ + "5x5min_ORNL-Soil" \ "10x10min_nomask" \ "10x10min_IGBPmergeICESatGIS" \ "3x3min_GLOBE-Gardner" \ "3x3min_GLOBE-Gardner-mergeGIS" \ "0.9x1.25_GRDC" \ "360x720cru_cruncep" \ - "1km-merge-10min_HYDRO1K-merge-nomask" ) + "1km-merge-10min_HYDRO1K-merge-nomask" \ + ) else echo "ERROR: Unknown value for phys: $phys" @@ -321,50 +331,55 @@ hostname=`hostname` if [ -n "$NERSC_HOST" ]; then hostname=$NERSC_HOST fi +echo "Hostname = $hostname" case $hostname in - ##yellowstone - ys* | caldera* | geyser* ) - . /glade/apps/opt/lmod/lmod/init/bash - module load esmf + ##cheyenne + cheyenne* | r* ) + . /glade/u/apps/ch/opt/lmod/7.2.1/lmod/lmod/init/bash + esmfvers=7.0.0 + intelvers=16.0.3 + module load esmf_libs/$esmfvers + module load intel/$intelvers module load ncl module load nco + #export MPI_USE_ARRAY=false if [ -z "$ESMFBIN_PATH" ]; then - if [ "$type" = "global" ]; then - mpi=mpi - mpitype="mpich2" + if [ "$interactive" = "NO" ]; then + mpi=ncdfio-mpi + mpitype="mpi" else - mpi=uni + mpi=ncdfio mpitype="mpiuni" fi - ESMFBIN_PATH=/glade/apps/opt/esmf/6.3.0-ncdfio/intel/12.1.5/bin/binO/Linux.intel.64.${mpitype}.default + ESMFBIN_PATH=/glade/u/apps/ch/opt/esmf/${esmfvers}-${mpi}/intel/$intelvers/bin/binO/Linux.intel.64.${mpitype}.default fi if [ -z "$MPIEXEC" ]; then - MPIEXEC="mpirun.lsf" + #MPIEXEC="mpirun -np $REGRID_PROC" + MPIEXEC="mpiexec_mpt -np $REGRID_PROC" fi ;; - ## hopper - hopper* ) - . /opt/modules/default/init/bash - module load ncl/6.1.2 + ##yellowstone + ys* | caldera* | geyser* ) + . /glade/apps/opt/lmod/lmod/init/bash + module load esmf + module load ncl module load nco + if [ -z "$ESMFBIN_PATH" ]; then - module use -a /project/projectdirs/ccsm1/modulefiles/hopper - if [ "$type" = "global" ]; then + if [ "$interactive" = "NO" ]; then mpi=mpi - mpitype="mpi" + mpitype="mpich2" else mpi=uni mpitype="mpiuni" fi - module load esmf/6.3.0r-ncdfio-${mpitype}-O - ESMFBIN_PATH=$ESMF_LIBDIR/../bin + ESMFBIN_PATH=/glade/apps/opt/esmf/6.3.0-ncdfio/intel/12.1.5/bin/binO/Linux.intel.64.${mpitype}.default fi if [ -z "$MPIEXEC" ]; then - MPIEXEC="aprun -n $REGRID_PROC" + MPIEXEC="mpirun.lsf" fi - ;; ## edison @@ -374,7 +389,7 @@ case $hostname in module load nco if [ -z "$ESMFBIN_PATH" ]; then module use -a /project/projectdirs/ccsm1/modulefiles/edison - if [ "$type" = "global" ]; then + if [ "$interactive" = "NO" ]; then mpi=mpi mpitype="mpi" else @@ -419,8 +434,8 @@ if [ "$interactive" = "NO" ]; then echo "Set the environment variable: MPIEXEC" exit 1 fi - if [ ! -x `which $MPIEXEC` ]; then - echo "The MPIEXEC pathname given is NOT an executable: $MPIEXEC" + if [ ! -x `which ${MPIEXEC%% *}` ]; then + echo "The MPIEXEC pathname given is NOT an executable: ${MPIEXEC%% *}" echo "Set the environment variable: MPIEXEC or run in interactive mode without MPI" exit 1 fi diff --git a/tools/mkmapdata/regridbatch.sh b/tools/mkmapdata/regridbatch.sh index a2796ec726..8e87ed4dfb 100755 --- a/tools/mkmapdata/regridbatch.sh +++ b/tools/mkmapdata/regridbatch.sh @@ -23,12 +23,14 @@ #BSUB -W 24:00 #BSUB -q geyser # queue -# hopper/edison specific batch commands: +# cheyenne specific batch commands: +#PBS -A P93300606 #PBS -N regrid #PBS -q regular -#PBS -l mppwidth=8 -#PBS -l walltime=24:00:00 +#PBS -l select=4:ncpus=2:mpiprocs=2:mem=109GB +#PBS -l walltime=2:00:00 #PBS -j oe +#PBS -me #PBS -V #PBS -S /bin/bash diff --git a/tools/mkprocdata_map/README.filedescriptions b/tools/mkprocdata_map/README.filedescriptions new file mode 100644 index 0000000000..90d9cc266f --- /dev/null +++ b/tools/mkprocdata_map/README.filedescriptions @@ -0,0 +1,25 @@ +README.filedescriptions Erik Kluzek + 11/7/2017 + +mkprocdata_map_all ------------ Script to run over a list of files +mkprocdata_map_wrap ----------- Main script to actually use +mkprocdata_map_functions.bash - Bash shell functions to use in other scripts +README ------------------------ Description and how to run +src --------------------------- Directory with FORTRAN source code + +Also there are some sample files that can be used for testing under inputdata in + +$DIN_LOC_ROOT/lnd/clm2/test_mkprocdata_map + +See how this is done by looking at the file for testing mkprocdata_map: + +../../test/tools/nl_files/mkprocdata_ne30_to_f19_I2000 + +Which does something like the following: + +./mkprocdata_map_wrap \ +-i $DIN_LOC_ROOT/lnd/clm2/test_mkprocdata_map/clm4054_ne30g16_I2000.clm2.h0.2000-01_c170430.nc \ +-o ne30output_onf19grid.nc \ +-m $DIN_LOC_ROOT/lnd/clm2/test_mkprocdata_map/map_ne30np4_nomask_to_fv1.9x2.5_nomask_aave_da_c121107.nc \ +-t $DIN_LOC_ROOT/lnd/clm2/test_mkprocdata_map/clm4054_f19g16_I2000.clm2.h0.2000-01_c170430.nc + diff --git a/tools/mkprocdata_map/mkprocdata_map_in b/tools/mkprocdata_map/mkprocdata_map_in deleted file mode 100644 index 99ed1ec15f..0000000000 --- a/tools/mkprocdata_map/mkprocdata_map_in +++ /dev/null @@ -1,6 +0,0 @@ -&mkprocdata_map_in - fmap = 'map_ne30np4_to_fv1.9x2.5_aave_da_091230.nc' - filei = 'Ib14_ne30np4_gx1v6.clm2.h0.0001-01-06-00000.nc' - fileo = 'Ib14_ne30np4_gx1v6_2d.clm2.h0.0001-01-06-00000.nc' -/ - diff --git a/tools/mkprocdata_map/mkprocdata_map_wrap b/tools/mkprocdata_map/mkprocdata_map_wrap index 9671b42c1f..1d951a8c9d 100755 --- a/tools/mkprocdata_map/mkprocdata_map_wrap +++ b/tools/mkprocdata_map/mkprocdata_map_wrap @@ -88,20 +88,20 @@ function change_missing_to_value { varname_tmp=${varname}_tmp_$$ cat > cmds.nco.tmp.$$ < 0); +*landmask_float=(landfrac > 0); landmask_float.change_miss($landmask_fill); -landmask = int(landmask_float); +landmask=int(landmask_float); EOF do_cmd "ncap2 -O -S cmds.nco.tmp.$$ $output_file $output_file" 0 diff --git a/tools/mksurfdata_map/Makefile.data b/tools/mksurfdata_map/Makefile.data index f9a1c8149f..74636175eb 100644 --- a/tools/mksurfdata_map/Makefile.data +++ b/tools/mksurfdata_map/Makefile.data @@ -9,7 +9,8 @@ # make -f Makefile.data crop-numa # # NOTE: The default behavior is to parallelize data set creation using -# the batch system by submitting jobs to the interactive queue in the +# the batch system by submitting jobs to the batch queue (on cheyenne). +# On yellowstone we submit to an interactive queue in the # background. Standard out and standard error are redirected to a text # file. To change this behavior, you can comment out the BATCHJOBS and # BACKGROUND variables and replace them with empty variables. @@ -24,10 +25,34 @@ # results in extra processes, but ensures that the surface datasets have the # correct name (rather than having 'hist' or 'rcpXXX' in their file name). # -BATCHJOBS = execgy -BACKGROUND = &> $@.stdout.txt & -MKSURFDATA = $(BATCHJOBS) ./mksurfdata.pl +# Set up special characters +null := + +# Set a few things needed for batch handling +PROJECT = $(shell cat $(HOME)/.cesm_proj) +LOGOUT = $@.stdout.txt +PWD = $(shell pwd) + +# Setup batch handling for either cheyenne or yellowstone +# Determine what to use by machine hostname +BATCHJOBS_ys = execgy +# Send to regular queue for 2 processors with extra memory, combine stdout/stderr output to log file, and send email on abort or exit +BATCHJOBS_ch = qsub -A $(PROJECT) -q regular -l select=1:ncpus=2:mem=110GB -l walltime=4:00:00 -j oe -N $(LOGOUT) -m ae -- +HOST = $(shell hostname) +FINDCH = $(findstring cheyenne,$(HOST)) +ifeq ($(FINDCH),$(null)) + ifeq ($(PROJECT),$(null)) + $(error Can NOT find PROJECT number from ~/.cesm_proj file create it and try again) + endif + BATCHJOBS = $(BATCHJOBS_ys) + BACKGROUND = &> $(LOGOUT) & +else + BATCHJOBS = $(BATCHJOBS_ch) + BACKGROUND = -rundir $(PWD) +endif + +MKSURFDATA = $(BATCHJOBS) $(PWD)/mksurfdata.pl STANDARD_RES = 360x720cru,48x96,0.9x1.25,1.9x2.5,10x15,ne30np4 @@ -36,6 +61,7 @@ STANDARD = \ global-present-f45 \ global-present-ne16np4 \ global-present-ne120np4 \ + global-present-T42 \ global-historical \ global-historical-ne120np4 \ global-transient-f45 \ @@ -46,8 +72,6 @@ TROPICS = \ tropics-present \ tropics-historical \ tropics-transient \ - tropics-atlantic-present \ - tropics-atlantic-transient \ crop-tropics-present \ crop-tropics-historical \ crop-tropics-transient @@ -58,12 +82,11 @@ CROP = \ crop-global-present-ne16np4 \ crop-global-present-ne120np4 \ crop-numa-present \ + crop-numa-historical \ crop-smallville \ - crop-smallville-1850 \ - crop-global-1850 \ - crop-global-1850-f45 \ - crop-global-1850-ne120np4 \ + crop-smallville-historical \ crop-global-historical \ + crop-global-historical-f45 \ crop-global-historical-ne120np4 \ crop-global-transient-f45 \ crop-global-transient \ @@ -71,40 +94,48 @@ CROP = \ all : standard tropics crop urban landuse-timeseries +DEBUG: + @echo "HOST := $(HOST)" + @echo "PROJECT := $(PROJECT)" + @echo "BATCHJOBS := $(BATCHJOBS)" + @echo "BACKGROUND := $(BACKGROUND)" # # standard # standard : $(STANDARD) global-present : FORCE - $(MKSURFDATA) -no_crop -glc_nec 10 -y 2000 -res $(STANDARD_RES) $(BACKGROUND) + $(MKSURFDATA) -no-crop -glc_nec 10 -y 2000 -res $(STANDARD_RES) $(BACKGROUND) global-present-f45 : FORCE - $(MKSURFDATA) -no_crop -glc_nec 10 -y 1850,2000 -res 4x5 $(BACKGROUND) + $(MKSURFDATA) -no-crop -glc_nec 10 -y 1850,2000 -res 4x5 $(BACKGROUND) + +global-present-T42 : FORCE + $(MKSURFDATA) -no-crop -glc_nec 10 -y 2000 -res 64x128 $(BACKGROUND) global-present-0.125 : FORCE - $(MKSURFDATA) -no_crop -hirespft -glc_nec 10 -y 2000 -res 0.125x0.125 $(BACKGROUND) + $(MKSURFDATA) -no-crop -hirespft -glc_nec 10 -y 2000 -res 0.125x0.125 $(BACKGROUND) global-present-ne16np4 : FORCE - $(MKSURFDATA) -no_crop -glc_nec 10 -y 2000 -res ne16np4 $(BACKGROUND) + $(MKSURFDATA) -no-crop -glc_nec 10 -y 2000 -res ne16np4 $(BACKGROUND) global-present-ne120np4 : FORCE - $(MKSURFDATA) -no_crop -glc_nec 10 -y 2000 -res ne120np4 $(BACKGROUND) + $(MKSURFDATA) -no-crop -glc_nec 10 -y 2000 -res ne120np4 $(BACKGROUND) global-historical : FORCE - $(MKSURFDATA) -no_crop -glc_nec 10 -y 1850 -res $(STANDARD_RES) $(BACKGROUND) + $(MKSURFDATA) -no-crop -glc_nec 10 -y 1850 -res $(STANDARD_RES) $(BACKGROUND) global-historical-ne120np4 : FORCE - $(MKSURFDATA) -no_crop -glc_nec 10 -y 1850 -res ne120np4 $(BACKGROUND) + $(MKSURFDATA) -no-crop -glc_nec 10 -y 1850 -res ne120np4 $(BACKGROUND) global-transient : FORCE - $(MKSURFDATA) -no_crop -no_surfdata -glc_nec 10 -y 1850-2000 -res $(STANDARD_RES) $(BACKGROUND) + $(MKSURFDATA) -no-crop -no_surfdata -glc_nec 10 -y 1850-2000 -res $(STANDARD_RES) $(BACKGROUND) global-transient-ne120np4 : FORCE - $(MKSURFDATA) -no_crop -no_surfdata -glc_nec 10 -y 1850-2000 -res ne120np4 $(BACKGROUND) + $(MKSURFDATA) -no-crop -no_surfdata -glc_nec 10 -y 1850-2000 -res ne120np4 $(BACKGROUND) global-transient-f45 : FORCE - $(MKSURFDATA) -no_crop -no_surfdata -glc_nec 10 -y 1850-2000 -res 4x5 $(BACKGROUND) + $(MKSURFDATA) -no-crop -no_surfdata -glc_nec 10 -y 1850-2000 -res 4x5 $(BACKGROUND) # # tropics @@ -112,28 +143,22 @@ global-transient-f45 : FORCE tropics : $(TROPICS) tropics-present : FORCE - $(MKSURFDATA) -glc_nec 0 -no_crop -y 2000 -res 5x5_amazon,1x1_brazil $(BACKGROUND) + $(MKSURFDATA) -glc_nec 10 -no-crop -y 2000 -res 5x5_amazon,1x1_brazil $(BACKGROUND) tropics-historical : FORCE - $(MKSURFDATA) -glc_nec 0 -no_crop -y 1850 -res 1x1_brazil $(BACKGROUND) + $(MKSURFDATA) -glc_nec 10 -no-crop -y 1850 -res 1x1_brazil $(BACKGROUND) tropics-transient : FORCE - $(MKSURFDATA) -glc_nec 0 -no_crop -no_surfdata -y 1850-2000 -res 1x1_brazil $(BACKGROUND) - -tropics-atlantic-present : FORCE - $(MKSURFDATA) -glc_nec 0 -no_crop -y 2000 -res 1x1_tropicAtl $(BACKGROUND) - -tropics-atlantic-transient : FORCE - $(MKSURFDATA) -glc_nec 0 -no_crop -y 1850-2000 -res 1x1_tropicAtl $(BACKGROUND) + $(MKSURFDATA) -glc_nec 10 -no-crop -no_surfdata -y 1850-2000 -res 1x1_brazil $(BACKGROUND) crop-tropics-present : FORCE - $(MKSURFDATA) -glc_nec 0 -y 2000 -res 5x5_amazon,1x1_brazil $(BACKGROUND) + $(MKSURFDATA) -glc_nec 10 -y 2000 -res 5x5_amazon,1x1_brazil $(BACKGROUND) crop-tropics-historical : FORCE - $(MKSURFDATA) -glc_nec 0 -y 1850 -res 1x1_brazil $(BACKGROUND) + $(MKSURFDATA) -glc_nec 10 -y 1850 -res 1x1_brazil $(BACKGROUND) crop-tropics-transient : FORCE - $(MKSURFDATA) -glc_nec 0 -no_surfdata -y 1850-2000 -res 1x1_brazil $(BACKGROUND) + $(MKSURFDATA) -glc_nec 10 -no_surfdata -y 1850-2000 -res 1x1_brazil $(BACKGROUND) # # crop @@ -150,10 +175,13 @@ crop-global-present-f45 : FORCE $(MKSURFDATA) -glc_nec 10 -y 1850,2000 -res 4x5 $(BACKGROUND) crop-numa-present : FORCE - $(MKSURFDATA) -glc_nec 0 -y 2000 -r 1x1_numaIA $(BACKGROUND) + $(MKSURFDATA) -glc_nec 10 -y 2000 -r 1x1_numaIA $(BACKGROUND) + +crop-numa-historical : FORCE + $(MKSURFDATA) -glc_nec 10 -y 1850 -r 1x1_numaIA $(BACKGROUND) crop-smallville : FORCE - $(MKSURFDATA) -glc_nec 0 -y 2000 -r 1x1_smallvilleIA \ + $(MKSURFDATA) -glc_nec 10 -y 2000 -r 1x1_smallvilleIA \ -pft_idx 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78 \ -pft_frc 6.5,1.5,1.6,1.7,1.8,1.9,1.5,1.6,1.7,1.8,1.9,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5 \ $(BACKGROUND) @@ -164,9 +192,19 @@ crop-global-present-ne16np4 : FORCE crop-global-present-ne120np4 : FORCE $(MKSURFDATA) -glc_nec 10 -y 2000 -res ne120np4 $(BACKGROUND) +# Note that the smallville 1850 dataset is entirely natural vegetation. This +# facilitates testing a transient case that starts with no crop, and then later +# adds crop (to make sure that it works properly to add crop in a grid cell +# where there used to be no crop). +crop-smallville-historical : FORCE + $(MKSURFDATA) -glc_nec 10 -y 1850 -r 1x1_smallvilleIA -pft_idx 13 -pft_frc 100 $(BACKGROUND) + crop-global-historical : FORCE $(MKSURFDATA) -glc_nec 10 -y 1850 -res $(STANDARD_RES) $(BACKGROUND) +crop-global-historical-f45 : FORCE + $(MKSURFDATA) -glc_nec 10 -y 1850 -r 4x5 $(BACKGROUND) + crop-global-historical-ne120np4 : FORCE $(MKSURFDATA) -glc_nec 10 -y 1850 -res ne120np4 $(BACKGROUND) @@ -178,34 +216,18 @@ crop-global-transient-ne120np4 : FORCE crop-global-transient-f45 : FORCE $(MKSURFDATA) -no_surfdata -glc_nec 10 -y 1850-2000 -res 4x5 $(BACKGROUND) - -# Note that the smallville 1850 dataset is entirely natural vegetation. This -# facilitates testing a transient case that starts with no crop, and then later -# adds crop (to make sure that it works properly to add crop in a grid cell -# where there used to be no crop). -crop-smallville-1850 : FORCE - $(MKSURFDATA) -glc_nec 0 -y 1850 -r 1x1_smallvilleIA -pft_idx 13 -pft_frc 100 $(BACKGROUND) - -crop-global-1850 : FORCE - $(MKSURFDATA) -glc_nec 10 -y 1850 -r $(STANDARD_RES) $(BACKGROUND) - -crop-global-1850-f45 : FORCE - $(MKSURFDATA) -glc_nec 10 -y 1850 -r 4x5 $(BACKGROUND) - -crop-global-1850-ne120np4 : FORCE - $(MKSURFDATA) -glc_nec 10 -y 1850 -r ne120np4 $(BACKGROUND) # # urban # urban : urban-present urban-alpha urban-present : FORCE - $(MKSURFDATA) -y 2000 -no_crop -glc_nec 0 -r 1x1_camdenNJ,1x1_vancouverCAN,1x1_mexicocityMEX $(BACKGROUND) + $(MKSURFDATA) -y 2000 -no-crop -glc_nec 10 -r 1x1_camdenNJ,1x1_vancouverCAN,1x1_mexicocityMEX $(BACKGROUND) # NOTE(bja, 2015-01) skip abort on invalid data necessary as of 2015-01. See # /glade/p/cesm/cseg/inputdata/lnd/clm2/surfdata_map/README_c141219 urban-alpha : FORCE - $(MKSURFDATA) -y 2000 -no_crop -glc_nec 0 -r 1x1_urbanc_alpha -urban_skip_abort_on_invalid_data_check $(BACKGROUND) + $(MKSURFDATA) -y 2000 -no-crop -glc_nec 10 -r 1x1_urbanc_alpha -urban_skip_abort_on_invalid_data_check $(BACKGROUND) # @@ -217,7 +239,7 @@ landuse-timeseries-f10 : FORCE $(MKSURFDATA) -no_surfdata -glc_nec 10 -y 1850-2000 -r 10x15 $(BACKGROUND) landuse-timeseries-smallville : FORCE - $(MKSURFDATA) -no_surfdata -glc_nec 0 -y 1850-1855 -r 1x1_smallvilleIA \ + $(MKSURFDATA) -no_surfdata -glc_nec 10 -y 1850-1855 -r 1x1_smallvilleIA \ -pft_idx 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78 \ -pft_frc 6.5,1.5,1.6,1.7,1.8,1.9,1.5,1.6,1.7,1.8,1.9,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5,1.5 \ -dynpft single_point_dynpft_files/landuse_timeseries_smallvilleIA_hist_simyr1850-1855.txt \ diff --git a/tools/mksurfdata_map/landuse_timeseries_hist_78pfts_simyr1850-2015.txt b/tools/mksurfdata_map/landuse_timeseries_hist_78pfts_simyr1850-2015.txt index 2fd5f83137..3c622f3965 100644 --- a/tools/mksurfdata_map/landuse_timeseries_hist_78pfts_simyr1850-2015.txt +++ b/tools/mksurfdata_map/landuse_timeseries_hist_78pfts_simyr1850-2015.txt @@ -1,332 +1,332 @@ -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1850.c161208.nc 1850 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1850_c170103.nc 1850 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1851.c161208.nc 1851 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1851_c170103.nc 1851 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1852.c161208.nc 1852 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1852_c170103.nc 1852 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1853.c161208.nc 1853 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1853_c170103.nc 1853 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1854.c161208.nc 1854 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1854_c170103.nc 1854 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1855.c161208.nc 1855 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1855_c170103.nc 1855 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1856.c161208.nc 1856 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1856_c170103.nc 1856 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1857.c161208.nc 1857 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1857_c170103.nc 1857 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1858.c161208.nc 1858 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1858_c170103.nc 1858 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1859.c161208.nc 1859 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1859_c170103.nc 1859 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1860.c161208.nc 1860 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1860_c170103.nc 1860 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1861.c161208.nc 1861 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1861_c170103.nc 1861 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1862.c161208.nc 1862 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1862_c170103.nc 1862 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1863.c161208.nc 1863 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1863_c170103.nc 1863 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1864.c161208.nc 1864 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1864_c170103.nc 1864 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1865.c161208.nc 1865 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1865_c170103.nc 1865 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1866.c161208.nc 1866 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1866_c170103.nc 1866 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1867.c161208.nc 1867 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1867_c170103.nc 1867 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1868.c161208.nc 1868 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1868_c170103.nc 1868 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1869.c161208.nc 1869 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1869_c170103.nc 1869 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1870.c161208.nc 1870 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1870_c170103.nc 1870 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1871.c161208.nc 1871 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1871_c170103.nc 1871 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1872.c161208.nc 1872 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1872_c170103.nc 1872 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1873.c161208.nc 1873 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1873_c170103.nc 1873 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1874.c161208.nc 1874 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1874_c170103.nc 1874 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1875.c161208.nc 1875 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1875_c170103.nc 1875 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1876.c161208.nc 1876 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1876_c170103.nc 1876 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1877.c161208.nc 1877 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1877_c170103.nc 1877 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1878.c161208.nc 1878 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1878_c170103.nc 1878 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1879.c161208.nc 1879 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1879_c170103.nc 1879 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1880.c161208.nc 1880 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1880_c170103.nc 1880 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1881.c161208.nc 1881 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1881_c170103.nc 1881 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1882.c161208.nc 1882 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1882_c170103.nc 1882 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1883.c161208.nc 1883 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1883_c170103.nc 1883 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1884.c161208.nc 1884 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1884_c170103.nc 1884 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1885.c161208.nc 1885 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1885_c170103.nc 1885 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1886.c161208.nc 1886 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1886_c170103.nc 1886 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1887.c161208.nc 1887 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1887_c170103.nc 1887 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1888.c161208.nc 1888 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1888_c170103.nc 1888 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1889.c161208.nc 1889 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1889_c170103.nc 1889 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1890.c161208.nc 1890 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1890_c170103.nc 1890 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1891.c161208.nc 1891 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1891_c170103.nc 1891 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1892.c161208.nc 1892 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1892_c170103.nc 1892 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1893.c161208.nc 1893 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1893_c170103.nc 1893 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1894.c161208.nc 1894 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1894_c170103.nc 1894 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1895.c161208.nc 1895 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1895_c170103.nc 1895 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1896.c161208.nc 1896 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1896_c170103.nc 1896 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1897.c161208.nc 1897 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1897_c170103.nc 1897 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1898.c161208.nc 1898 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1898_c170103.nc 1898 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1899.c161208.nc 1899 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1899_c170103.nc 1899 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1900.c161208.nc 1900 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1900_c170103.nc 1900 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1901.c161208.nc 1901 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1901_c170103.nc 1901 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1902.c161208.nc 1902 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1902_c170103.nc 1902 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1903.c161208.nc 1903 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1903_c170103.nc 1903 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1904.c161208.nc 1904 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1904_c170103.nc 1904 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1905.c161208.nc 1905 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1905_c170103.nc 1905 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1906.c161208.nc 1906 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1906_c170103.nc 1906 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1907.c161208.nc 1907 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1907_c170103.nc 1907 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1908.c161208.nc 1908 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1908_c170103.nc 1908 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1909.c161208.nc 1909 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1909_c170103.nc 1909 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1910.c161208.nc 1910 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1910_c170103.nc 1910 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1911.c161208.nc 1911 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1911_c170103.nc 1911 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1912.c161208.nc 1912 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1912_c170103.nc 1912 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1913.c161208.nc 1913 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1913_c170103.nc 1913 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1914.c161208.nc 1914 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1914_c170103.nc 1914 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1915.c161208.nc 1915 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1915_c170103.nc 1915 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1916.c161208.nc 1916 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1916_c170103.nc 1916 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1917.c161208.nc 1917 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1917_c170103.nc 1917 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1918.c161208.nc 1918 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1918_c170103.nc 1918 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1919.c161208.nc 1919 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1919_c170103.nc 1919 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1920.c161208.nc 1920 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1920_c170103.nc 1920 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1921.c161208.nc 1921 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1921_c170103.nc 1921 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1922.c161208.nc 1922 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1922_c170103.nc 1922 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1923.c161208.nc 1923 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1923_c170103.nc 1923 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1924.c161208.nc 1924 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1924_c170103.nc 1924 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1925.c161208.nc 1925 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1925_c170103.nc 1925 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1926.c161208.nc 1926 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1926_c170103.nc 1926 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1927.c161208.nc 1927 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1927_c170103.nc 1927 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1928.c161208.nc 1928 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1928_c170103.nc 1928 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1929.c161208.nc 1929 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1929_c170103.nc 1929 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1930.c161208.nc 1930 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1930_c170103.nc 1930 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1931.c161208.nc 1931 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1931_c170103.nc 1931 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1932.c161208.nc 1932 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1932_c170103.nc 1932 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1933.c161208.nc 1933 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1933_c170103.nc 1933 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1934.c161208.nc 1934 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1934_c170103.nc 1934 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1935.c161208.nc 1935 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1935_c170103.nc 1935 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1936.c161208.nc 1936 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1936_c170103.nc 1936 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1937.c161208.nc 1937 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1937_c170103.nc 1937 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1938.c161208.nc 1938 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1938_c170103.nc 1938 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1939.c161208.nc 1939 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1939_c170103.nc 1939 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1940.c161208.nc 1940 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1940_c170103.nc 1940 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1941.c161208.nc 1941 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1941_c170103.nc 1941 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1942.c161208.nc 1942 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1942_c170103.nc 1942 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1943.c161208.nc 1943 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1943_c170103.nc 1943 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1944.c161208.nc 1944 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1944_c170103.nc 1944 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1945.c161208.nc 1945 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1945_c170103.nc 1945 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1946.c161208.nc 1946 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1946_c170103.nc 1946 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1947.c161208.nc 1947 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1947_c170103.nc 1947 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1948.c161208.nc 1948 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1948_c170103.nc 1948 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1949.c161208.nc 1949 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1949_c170103.nc 1949 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1950.c161208.nc 1950 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1950_c170103.nc 1950 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1951.c161208.nc 1951 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1951_c170103.nc 1951 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1952.c161208.nc 1952 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1952_c170103.nc 1952 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1953.c161208.nc 1953 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1953_c170103.nc 1953 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1954.c161208.nc 1954 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1954_c170103.nc 1954 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1955.c161208.nc 1955 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1955_c170103.nc 1955 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1956.c161208.nc 1956 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1956_c170103.nc 1956 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1957.c161208.nc 1957 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1957_c170103.nc 1957 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1958.c161208.nc 1958 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1958_c170103.nc 1958 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1959.c161208.nc 1959 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1959_c170103.nc 1959 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1960.c161208.nc 1960 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1960_c170103.nc 1960 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1961.c161208.nc 1961 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1961_c170103.nc 1961 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1962.c161208.nc 1962 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1962_c170103.nc 1962 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1963.c161208.nc 1963 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1963_c170103.nc 1963 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1964.c161208.nc 1964 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1964_c170103.nc 1964 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1965.c161208.nc 1965 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1965_c170103.nc 1965 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1966.c161208.nc 1966 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1966_c170103.nc 1966 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1967.c161208.nc 1967 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1967_c170103.nc 1967 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1968.c161208.nc 1968 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1968_c170103.nc 1968 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1969.c161208.nc 1969 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1969_c170103.nc 1969 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1970.c161208.nc 1970 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1970_c170103.nc 1970 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1971.c161208.nc 1971 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1971_c170103.nc 1971 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1972.c161208.nc 1972 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1972_c170103.nc 1972 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1973.c161208.nc 1973 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1973_c170103.nc 1973 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1974.c161208.nc 1974 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1974_c170103.nc 1974 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1975.c161208.nc 1975 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1975_c170103.nc 1975 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1976.c161208.nc 1976 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1976_c170103.nc 1976 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1977.c161208.nc 1977 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1977_c170103.nc 1977 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1978.c161208.nc 1978 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1978_c170103.nc 1978 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1979.c161208.nc 1979 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1979_c170103.nc 1979 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1980.c161208.nc 1980 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1980_c170103.nc 1980 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1981.c161208.nc 1981 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1981_c170103.nc 1981 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1982.c161208.nc 1982 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1982_c170103.nc 1982 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1983.c161208.nc 1983 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1983_c170103.nc 1983 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1984.c161208.nc 1984 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1984_c170103.nc 1984 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1985.c161208.nc 1985 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1985_c170103.nc 1985 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1986.c161208.nc 1986 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1986_c170103.nc 1986 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1987.c161208.nc 1987 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1987_c170103.nc 1987 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1988.c161208.nc 1988 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1988_c170103.nc 1988 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1989.c161208.nc 1989 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1989_c170103.nc 1989 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1990.c161208.nc 1990 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1990_c170103.nc 1990 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1991.c161208.nc 1991 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1991_c170103.nc 1991 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1992.c161208.nc 1992 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1992_c170103.nc 1992 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1993.c161208.nc 1993 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1993_c170103.nc 1993 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1994.c161208.nc 1994 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1994_c170103.nc 1994 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1995.c161208.nc 1995 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1995_c170103.nc 1995 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1996.c161208.nc 1996 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1996_c170103.nc 1996 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1997.c161208.nc 1997 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1997_c170103.nc 1997 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1998.c161208.nc 1998 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1998_c170103.nc 1998 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_1999.c161208.nc 1999 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_1999_c170103.nc 1999 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2000.c161208.nc 2000 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2000_c170103.nc 2000 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2001.c161208.nc 2001 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2001_c170103.nc 2001 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2002.c161208.nc 2002 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2002_c170103.nc 2002 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2003.c161208.nc 2003 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2003_c170103.nc 2003 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2004.c161208.nc 2004 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2004_c170103.nc 2004 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2005.c161208.nc 2005 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2005_c170103.nc 2005 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2006.c161208.nc 2006 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2006_c170103.nc 2006 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2007.c161208.nc 2007 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2007_c170103.nc 2007 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2008.c161208.nc 2008 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2008_c170103.nc 2008 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2009.c161208.nc 2009 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2009_c170103.nc 2009 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2010.c161208.nc 2010 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2010_c170103.nc 2010 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2011.c161208.nc 2011 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2011_c170103.nc 2011 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2012.c161208.nc 2012 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2012_c170103.nc 2012 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2013.c161208.nc 2013 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2013_c170103.nc 2013 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2014.c161208.nc 2014 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2014_c170103.nc 2014 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2015.c161208.nc 2015 -/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2015_c170103.nc 2015 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1850.c170412.nc 1850 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1850.c170412.nc 1850 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1851.c170412.nc 1851 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1851.c170412.nc 1851 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1852.c170412.nc 1852 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1852.c170412.nc 1852 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1853.c170412.nc 1853 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1853.c170412.nc 1853 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1854.c170412.nc 1854 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1854.c170412.nc 1854 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1855.c170412.nc 1855 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1855.c170412.nc 1855 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1856.c170412.nc 1856 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1856.c170412.nc 1856 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1857.c170412.nc 1857 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1857.c170412.nc 1857 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1858.c170412.nc 1858 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1858.c170412.nc 1858 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1859.c170412.nc 1859 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1859.c170412.nc 1859 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1860.c170412.nc 1860 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1860.c170412.nc 1860 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1861.c170412.nc 1861 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1861.c170412.nc 1861 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1862.c170412.nc 1862 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1862.c170412.nc 1862 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1863.c170412.nc 1863 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1863.c170412.nc 1863 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1864.c170412.nc 1864 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1864.c170412.nc 1864 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1865.c170412.nc 1865 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1865.c170412.nc 1865 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1866.c170412.nc 1866 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1866.c170412.nc 1866 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1867.c170412.nc 1867 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1867.c170412.nc 1867 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1868.c170412.nc 1868 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1868.c170412.nc 1868 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1869.c170412.nc 1869 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1869.c170412.nc 1869 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1870.c170412.nc 1870 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1870.c170412.nc 1870 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1871.c170412.nc 1871 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1871.c170412.nc 1871 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1872.c170412.nc 1872 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1872.c170412.nc 1872 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1873.c170412.nc 1873 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1873.c170412.nc 1873 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1874.c170412.nc 1874 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1874.c170412.nc 1874 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1875.c170412.nc 1875 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1875.c170412.nc 1875 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1876.c170412.nc 1876 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1876.c170412.nc 1876 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1877.c170412.nc 1877 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1877.c170412.nc 1877 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1878.c170412.nc 1878 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1878.c170412.nc 1878 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1879.c170412.nc 1879 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1879.c170412.nc 1879 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1880.c170412.nc 1880 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1880.c170412.nc 1880 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1881.c170412.nc 1881 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1881.c170412.nc 1881 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1882.c170412.nc 1882 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1882.c170412.nc 1882 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1883.c170412.nc 1883 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1883.c170412.nc 1883 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1884.c170412.nc 1884 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1884.c170412.nc 1884 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1885.c170412.nc 1885 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1885.c170412.nc 1885 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1886.c170412.nc 1886 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1886.c170412.nc 1886 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1887.c170412.nc 1887 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1887.c170412.nc 1887 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1888.c170412.nc 1888 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1888.c170412.nc 1888 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1889.c170412.nc 1889 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1889.c170412.nc 1889 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1890.c170412.nc 1890 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1890.c170412.nc 1890 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1891.c170412.nc 1891 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1891.c170412.nc 1891 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1892.c170412.nc 1892 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1892.c170412.nc 1892 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1893.c170412.nc 1893 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1893.c170412.nc 1893 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1894.c170412.nc 1894 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1894.c170412.nc 1894 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1895.c170412.nc 1895 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1895.c170412.nc 1895 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1896.c170412.nc 1896 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1896.c170412.nc 1896 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1897.c170412.nc 1897 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1897.c170412.nc 1897 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1898.c170412.nc 1898 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1898.c170412.nc 1898 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1899.c170412.nc 1899 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1899.c170412.nc 1899 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1900.c170412.nc 1900 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1900.c170412.nc 1900 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1901.c170412.nc 1901 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1901.c170412.nc 1901 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1902.c170412.nc 1902 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1902.c170412.nc 1902 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1903.c170412.nc 1903 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1903.c170412.nc 1903 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1904.c170412.nc 1904 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1904.c170412.nc 1904 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1905.c170412.nc 1905 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1905.c170412.nc 1905 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1906.c170412.nc 1906 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1906.c170412.nc 1906 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1907.c170412.nc 1907 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1907.c170412.nc 1907 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1908.c170412.nc 1908 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1908.c170412.nc 1908 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1909.c170412.nc 1909 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1909.c170412.nc 1909 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1910.c170412.nc 1910 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1910.c170412.nc 1910 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1911.c170412.nc 1911 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1911.c170412.nc 1911 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1912.c170412.nc 1912 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1912.c170412.nc 1912 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1913.c170412.nc 1913 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1913.c170412.nc 1913 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1914.c170412.nc 1914 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1914.c170412.nc 1914 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1915.c170412.nc 1915 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1915.c170412.nc 1915 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1916.c170412.nc 1916 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1916.c170412.nc 1916 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1917.c170412.nc 1917 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1917.c170412.nc 1917 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1918.c170412.nc 1918 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1918.c170412.nc 1918 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1919.c170412.nc 1919 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1919.c170412.nc 1919 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1920.c170412.nc 1920 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1920.c170412.nc 1920 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1921.c170412.nc 1921 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1921.c170412.nc 1921 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1922.c170412.nc 1922 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1922.c170412.nc 1922 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1923.c170412.nc 1923 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1923.c170412.nc 1923 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1924.c170412.nc 1924 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1924.c170412.nc 1924 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1925.c170412.nc 1925 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1925.c170412.nc 1925 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1926.c170412.nc 1926 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1926.c170412.nc 1926 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1927.c170412.nc 1927 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1927.c170412.nc 1927 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1928.c170412.nc 1928 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1928.c170412.nc 1928 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1929.c170412.nc 1929 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1929.c170412.nc 1929 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1930.c170412.nc 1930 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1930.c170412.nc 1930 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1931.c170412.nc 1931 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1931.c170412.nc 1931 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1932.c170412.nc 1932 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1932.c170412.nc 1932 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1933.c170412.nc 1933 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1933.c170412.nc 1933 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1934.c170412.nc 1934 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1934.c170412.nc 1934 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1935.c170412.nc 1935 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1935.c170412.nc 1935 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1936.c170412.nc 1936 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1936.c170412.nc 1936 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1937.c170412.nc 1937 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1937.c170412.nc 1937 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1938.c170412.nc 1938 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1938.c170412.nc 1938 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1939.c170412.nc 1939 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1939.c170412.nc 1939 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1940.c170412.nc 1940 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1940.c170412.nc 1940 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1941.c170412.nc 1941 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1941.c170412.nc 1941 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1942.c170412.nc 1942 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1942.c170412.nc 1942 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1943.c170412.nc 1943 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1943.c170412.nc 1943 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1944.c170412.nc 1944 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1944.c170412.nc 1944 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1945.c170412.nc 1945 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1945.c170412.nc 1945 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1946.c170412.nc 1946 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1946.c170412.nc 1946 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1947.c170412.nc 1947 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1947.c170412.nc 1947 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1948.c170412.nc 1948 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1948.c170412.nc 1948 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1949.c170412.nc 1949 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1949.c170412.nc 1949 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1950.c170412.nc 1950 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1950.c170412.nc 1950 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1951.c170412.nc 1951 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1951.c170412.nc 1951 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1952.c170412.nc 1952 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1952.c170412.nc 1952 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1953.c170412.nc 1953 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1953.c170412.nc 1953 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1954.c170412.nc 1954 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1954.c170412.nc 1954 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1955.c170412.nc 1955 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1955.c170412.nc 1955 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1956.c170412.nc 1956 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1956.c170412.nc 1956 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1957.c170412.nc 1957 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1957.c170412.nc 1957 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1958.c170412.nc 1958 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1958.c170412.nc 1958 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1959.c170412.nc 1959 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1959.c170412.nc 1959 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1960.c170412.nc 1960 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1960.c170412.nc 1960 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1961.c170412.nc 1961 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1961.c170412.nc 1961 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1962.c170412.nc 1962 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1962.c170412.nc 1962 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1963.c170412.nc 1963 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1963.c170412.nc 1963 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1964.c170412.nc 1964 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1964.c170412.nc 1964 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1965.c170412.nc 1965 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1965.c170412.nc 1965 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1966.c170412.nc 1966 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1966.c170412.nc 1966 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1967.c170412.nc 1967 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1967.c170412.nc 1967 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1968.c170412.nc 1968 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1968.c170412.nc 1968 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1969.c170412.nc 1969 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1969.c170412.nc 1969 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1970.c170412.nc 1970 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1970.c170412.nc 1970 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1971.c170412.nc 1971 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1971.c170412.nc 1971 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1972.c170412.nc 1972 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1972.c170412.nc 1972 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1973.c170412.nc 1973 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1973.c170412.nc 1973 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1974.c170412.nc 1974 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1974.c170412.nc 1974 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1975.c170412.nc 1975 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1975.c170412.nc 1975 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1976.c170412.nc 1976 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1976.c170412.nc 1976 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1977.c170412.nc 1977 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1977.c170412.nc 1977 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1978.c170412.nc 1978 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1978.c170412.nc 1978 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1979.c170412.nc 1979 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1979.c170412.nc 1979 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1980.c170412.nc 1980 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1980.c170412.nc 1980 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1981.c170412.nc 1981 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1981.c170412.nc 1981 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1982.c170412.nc 1982 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1982.c170412.nc 1982 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1983.c170412.nc 1983 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1983.c170412.nc 1983 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1984.c170412.nc 1984 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1984.c170412.nc 1984 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1985.c170412.nc 1985 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1985.c170412.nc 1985 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1986.c170412.nc 1986 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1986.c170412.nc 1986 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1987.c170412.nc 1987 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1987.c170412.nc 1987 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1988.c170412.nc 1988 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1988.c170412.nc 1988 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1989.c170412.nc 1989 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1989.c170412.nc 1989 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1990.c170412.nc 1990 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1990.c170412.nc 1990 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1991.c170412.nc 1991 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1991.c170412.nc 1991 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1992.c170412.nc 1992 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1992.c170412.nc 1992 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1993.c170412.nc 1993 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1993.c170412.nc 1993 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1994.c170412.nc 1994 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1994.c170412.nc 1994 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1995.c170412.nc 1995 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1995.c170412.nc 1995 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1996.c170412.nc 1996 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1996.c170412.nc 1996 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1997.c170412.nc 1997 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1997.c170412.nc 1997 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1998.c170412.nc 1998 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1998.c170412.nc 1998 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1999.c170412.nc 1999 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_1999.c170412.nc 1999 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2000.c170412.nc 2000 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2000.c170412.nc 2000 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2001.c170412.nc 2001 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2001.c170412.nc 2001 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2002.c170412.nc 2002 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2002.c170412.nc 2002 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2003.c170412.nc 2003 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2003.c170412.nc 2003 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2004.c170412.nc 2004 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2004.c170412.nc 2004 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2005.c170412.nc 2005 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2005.c170412.nc 2005 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2006.c170412.nc 2006 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2006.c170412.nc 2006 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2007.c170412.nc 2007 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2007.c170412.nc 2007 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2008.c170412.nc 2008 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2008.c170412.nc 2008 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2009.c170412.nc 2009 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2009.c170412.nc 2009 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2010.c170412.nc 2010 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2010.c170412.nc 2010 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2011.c170412.nc 2011 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2011.c170412.nc 2011 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2012.c170412.nc 2012 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2012.c170412.nc 2012 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2013.c170412.nc 2013 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2013.c170412.nc 2013 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2014.c170412.nc 2014 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2014.c170412.nc 2014 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2015.c170412.nc 2015 +/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2015.c170412.nc 2015 diff --git a/tools/mksurfdata_map/mksurfdata.pl b/tools/mksurfdata_map/mksurfdata.pl index 735d1e305a..422b614fed 100755 --- a/tools/mksurfdata_map/mksurfdata.pl +++ b/tools/mksurfdata_map/mksurfdata.pl @@ -54,7 +54,7 @@ debug=>0, exedir=>undef, allownofile=>undef, - nocrop=>undef, + crop=>1, hirespft=>undef, years=>"1850,2000", glc_nec=>10, @@ -73,6 +73,7 @@ outnc_double=>undef, outnc_dims=>"2", usrname=>"", + rundir=>"$cwd", usr_mapdir=>"../mkmapdata", dynpft=>undef, csmdata=>$CSMDATA, @@ -124,12 +125,15 @@ sub usage { -exedir "directory" Directory where mksurfdata_map program is (by default assume it is in the current directory) -inlandwet If you want to allow inland wetlands - -no_crop Create datasets without the extensive list of prognostic crop types + -no-crop Create datasets without the extensive list of prognostic crop types -no_surfdata Do not output a surface dataset This is useful if you only want a landuse_timeseries file -years [or -y] Simulation year(s) to run over (by default $opts{'years'}) (can also be a simulation year range: i.e. 1850-2000) -help [or -h] Display this help. + + -rundir "directory" Directory to run in + (by default current directory $opts{'rundir'}) -usrname "clm_usrdat_name" CLM user data name to find grid file with. @@ -259,7 +263,7 @@ sub write_transient_timeseries_file { my $vegtypyr = `$scrdir/../../bld/queryDefaultNamelist.pl $queryfilopts $resol -options sim_year=$yr,rcp=${rcp}${mkcrop} -var mksrf_fvegtyp -namelist clmexp`; chomp( $vegtypyr ); printf $fh_landuse_timeseries $dynpft_format, $vegtypyr, $yr; - my $hrvtypyr = `$scrdir/../../bld/queryDefaultNamelist.pl $queryfilopts $resolhrv -options sim_year=$yr,rcp=${rcp}${mkcrop} -var mksrf_fhrvtyp -namelist clmexp`; + my $hrvtypyr = `$scrdir/../../bld/queryDefaultNamelist.pl $queryfilopts $resolhrv -options sim_year=$yr,rcp=${rcp}${mkcrop} -var mksrf_fvegtyp -namelist clmexp`; chomp( $hrvtypyr ); printf $fh_landuse_timeseries $dynpft_format, $hrvtypyr, $yr; if ( $yr % 100 == 0 ) { @@ -411,7 +415,7 @@ sub write_namelist_file { "usr_gname=s" => \$opts{'usr_gname'}, "usr_gdate=s" => \$opts{'usr_gdate'}, "usr_mapdir=s" => \$opts{'usr_mapdir'}, - "no_crop" => \$opts{'no_crop'}, + "crop!" => \$opts{'crop'}, "hirespft" => \$opts{'hirespft'}, "l|dinlc=s" => \$opts{'csmdata'}, "d|debug" => \$opts{'debug'}, @@ -426,6 +430,7 @@ sub write_namelist_file { "no_surfdata" => \$opts{'no_surfdata'}, "pft_frc=s" => \$opts{'pft_frc'}, "pft_idx=s" => \$opts{'pft_idx'}, + "rundir=s" => \$opts{'rundir'}, "soil_col=i" => \$opts{'soil_col'}, "soil_fmx=f" => \$opts{'soil_fmx'}, "soil_cly=f" => \$opts{'soil_cly'}, @@ -441,11 +446,17 @@ sub write_namelist_file { if ( $opts{'help'} ) { usage(); } + + chdir( $opts{'rundir'} ) or die "** can't change to directory: $opts{'rundir'}\n"; # If csmdata was changed from the default if ( $CSMDATA ne $opts{'csmdata'} ) { $CSMDATA = $opts{'csmdata'}; } my $glc_nec = $opts{'glc_nec'}; + if ( $glc_nec <= 0 ) { + print "** glc_nec must be at least 1\n"; + usage(); + } my $no_inlandwet = ".true."; if (defined($opts{'inlandwet'})) { $no_inlandwet = ".false."; @@ -507,6 +518,9 @@ sub write_namelist_file { } } } + + # CMIP series input data is corresponding to + my $cmip_series = "CMIP6"; # Check if soil set if ( defined($opts{'soil_cly'}) || defined($opts{'soil_snd'}) ) { @@ -514,7 +528,7 @@ sub write_namelist_file { $opts{'soil_override'} = 1; } # Check if pft set - if ( defined($opts{'no_crop'}) ) { $numpft = 16; } # First set numpft if crop is off + if ( ! $opts{'crop'} ) { $numpft = 16; } # First set numpft if crop is off if ( defined($opts{'pft_frc'}) || defined($opts{'pft_idx'}) ) { &check_pft( ); $opts{'pft_override'} = 1; @@ -695,23 +709,26 @@ sub write_namelist_file { if ( $vegtyp eq "" ) { die "** trouble getting vegtyp file with: $cmd\n"; } - my $cmd = "$scrdir/../../bld/queryDefaultNamelist.pl $queryfilopts $resolhrv -options sim_year=${sim_yr_surfdat}$mkcrop -var mksrf_fhrvtyp -namelist clmexp"; + my $cmd = "$scrdir/../../bld/queryDefaultNamelist.pl $queryfilopts $resolhrv -options sim_year=${sim_yr_surfdat}$mkcrop -var mksrf_fvegtyp -namelist clmexp"; my $hrvtyp = `$cmd`; chomp( $hrvtyp ); if ( $hrvtyp eq "" ) { die "** trouble getting hrvtyp file with: $cmd\n"; } my $options = ""; - my $crpdes = sprintf("%2.2dpfts_", $numpft); + my $crpdes = sprintf("%2.2dpfts", $numpft); + if ( $numpft == 16 ) { + $crpdes .= "_Irrig"; + } if ( $mkcrop ne "" ) { $options = "-options $mkcrop"; } if ( $rcp != -999.9 ) { - $desc = sprintf( "%s%2.1f_%ssimyr%4.4d-%4.4d", "rcp", $rcp, $crpdes, $sim_yr0, $sim_yrn ); - $desc_surfdat = sprintf( "%s%2.1f_%ssimyr%4.4d", "rcp", $rcp, $crpdes, $sim_yr_surfdat ); + $desc = sprintf( "%s%2.1f_%s_%ssimyr%4.4d-%4.4d", "rcp", $rcp, $crpdes, $cmip_series, $sim_yr0, $sim_yrn ); + $desc_surfdat = sprintf( "%s%2.1f_%s_%ssimyr%4.4d", "rcp", $rcp, $crpdes, $cmip_series, $sim_yr_surfdat ); } else { - $desc = sprintf( "hist_%ssimyr%4.4d-%4.4d", $crpdes, $sim_yr0, $sim_yrn ); - $desc_surfdat = sprintf( "%ssimyr%4.4d", $crpdes, $sim_yr_surfdat ); + $desc = sprintf( "hist_%s_%s_simyr%4.4d-%4.4d", $crpdes, $cmip_series, $sim_yr0, $sim_yrn ); + $desc_surfdat = sprintf( "%s_%s_simyr%4.4d", $crpdes, $cmip_series, $sim_yr_surfdat ); } my $fsurdat_fname_base = ""; diff --git a/tools/mksurfdata_map/mksurfdata_map.namelist b/tools/mksurfdata_map/mksurfdata_map.namelist index 94c902c194..fe375e6d98 100644 --- a/tools/mksurfdata_map/mksurfdata_map.namelist +++ b/tools/mksurfdata_map/mksurfdata_map.namelist @@ -1,15 +1,15 @@ &clmexp nglcec = 10 - mksrf_fgrid = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_landuse_to_10x15_aave_da_110307.nc' - map_fpft = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_landuse_to_10x15_aave_da_110307.nc' + mksrf_fgrid = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.25x0.25_MODIS_to_10x15_nomask_aave_da_c170321.nc' + map_fpft = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.25x0.25_MODIS_to_10x15_nomask_aave_da_c170321.nc' map_fglacier = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_3x3min_GLOBE-Gardner_to_10x15_nomask_aave_da_c120923.nc' map_fglacierregion = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_10minx10min_topo_to_10x15_aave_da_110307.nc' - map_fsoicol = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_landuse_to_10x15_aave_da_110307.nc' + map_fsoicol = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.25x0.25_MODIS_to_10x15_nomask_aave_da_c170321.nc' map_furban = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_3x3min_LandScan2004_to_10x15_nomask_aave_da_c120518.nc' map_fmax = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_3x3min_USGS_to_10x15_nomask_aave_da_c120926.nc' map_forganic = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_5x5min_ISRIC-WISE_to_10x15_nomask_aave_da_c111115.nc' - map_flai = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_landuse_to_10x15_aave_da_110307.nc' - map_fharvest = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.9x1.25_GRDC_to_10x15_nomask_aave_da_c130308.nc' + map_flai = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.25x0.25_MODIS_to_10x15_nomask_aave_da_c170321.nc' + map_fharvest = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.25x0.25_MODIS_to_10x15_nomask_aave_da_c170321.nc' map_flakwat = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_3x3min_MODIS-wCsp_to_10x15_nomask_aave_da_c160425.nc' map_fwetlnd = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_lanwat_to_10x15_aave_da_110307.nc' map_fvocef = '/glade/p/cesm/cseg/inputdata/lnd/clm2/mappingdata/maps/10x15/map_0.5x0.5_lanwat_to_10x15_aave_da_110307.nc' @@ -28,7 +28,7 @@ mksrf_fwetlnd = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_lanwat.050425.nc' mksrf_fmax = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_fmax_3x3min_USGS_c120911.nc' mksrf_fglacier = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_glacier_3x3min_simyr2000.c120926.nc' - mksrf_fglacierregion = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_GlacierRegion_10x10min_nomask_c160122.nc' + mksrf_fglacierregion = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_GlacierRegion_10x10min_nomask_c170616.nc' mksrf_fvocef = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_vocef_0.5x0.5_simyr2000.c110531.nc' mksrf_furbtopo = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_topo.10min.c080912.nc' mksrf_fgdp = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_gdp_0.5x0.5_AVHRR_simyr2000.c130228.nc' @@ -42,13 +42,13 @@ all_urban = .false. no_inlandwet = .true. mksrf_furban = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/mksrf_urban_0.05x0.05_simyr2000.c120621.nc' - mksrf_fvegtyp = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.5x0.5.simyr1850-2015.c161208/mksrf_landuse_2000.c161208.nc' - mksrf_fhrvtyp = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/landusedynharv.0.9x1.25.simyr1850-2015_c161229/mkharv_2000_c170103.nc' - mksrf_fsoicol = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftlandusedyn.0.5x0.5.simyr1850-2005.c090630/mksrf_soilcol_global_c090324.nc' - mksrf_flai = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftlandusedyn.0.5x0.5.simyr1850-2005.c090630/mksrf_lai_global_c090506.nc' - fsurdat = 'surfdata_10x15_78pfts_simyr2000_c170106.nc' - fsurlog = 'surfdata_10x15_78pfts_simyr2000_c170106.log' - mksrf_fdynuse = 'landuse_timeseries_hist_78pfts_simyr1850-2015.txt' - fdyndat = 'landuse.timeseries_10x15_hist_78pfts_simyr1850-2015_c170106.nc' + mksrf_fvegtyp = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2000.c170412.nc' + mksrf_fhrvtyp = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_landuse_histclm50_LUH2_2000.c170412.nc' + mksrf_fsoicol = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_soilcolor_simyr2005.c170413.nc' + mksrf_flai = '/glade/p/cesm/cseg/inputdata/lnd/clm2/rawdata/pftcftlandusedynharv.0.25x0.25.MODIS.simyr1850-2015.c170412/mksrf_lai_78pfts_simyr2005.c170413.nc' + fsurdat = 'surfdata_10x15_78pfts_simyr2000_c170531.nc' + fsurlog = 'surfdata_10x15_78pfts_simyr2000_c170531.log' + mksrf_fdynuse = '' + fdyndat = '' numpft = 78 / diff --git a/tools/mksurfdata_map/src/CMakeLists.txt b/tools/mksurfdata_map/src/CMakeLists.txt index 40ceb20868..4cd91e8a39 100644 --- a/tools/mksurfdata_map/src/CMakeLists.txt +++ b/tools/mksurfdata_map/src/CMakeLists.txt @@ -1,13 +1,26 @@ # This CMakeLists.txt file is currently used just for building unit tests. cmake_minimum_required(VERSION 2.8) +list(APPEND CMAKE_MODULE_PATH ${CIME_CMAKE_MODULE_DIRECTORY}) +include(CIME_initial_setup) + project(mksurfdat_tests Fortran) -list(APPEND CMAKE_MODULE_PATH ${CESM_CMAKE_MODULE_DIRECTORY}) -include(CESM_utils) +include(CIME_utils) # Build library containing stuff needed for the unit tests -list(APPEND mksurfdat_sources shr_kind_mod.F90 mkpftConstantsMod.F90 mkpctPftTypeMod.F90 mkutilsMod.F90 mkpftUtilsMod.F90) +list(APPEND mksurfdat_sources + shr_kind_mod.F90 + mkgridmapMod.F90 + mkindexmapMod.F90 + mkpftConstantsMod.F90 + mkpctPftTypeMod.F90 + mkutilsMod.F90 + mkpftUtilsMod.F90 + mkvarctl.F90 + mkvarpar.F90 + shr_const_mod.F90 + unit_test_stubs/mkncdio.F90) add_library(mksurfdat ${mksurfdat_sources}) # Tell cmake to look for libraries & mod files here, because this is where we built libraries diff --git a/tools/mksurfdata_map/src/README.unit_testing b/tools/mksurfdata_map/src/README.unit_testing index 21b4b7a9b2..de7d2d6fbc 100644 --- a/tools/mksurfdata_map/src/README.unit_testing +++ b/tools/mksurfdata_map/src/README.unit_testing @@ -1,4 +1,3 @@ -To run all unit tests on yellowstone, run the following command: +To run all unit tests defined here, run the following command: -execca ../../../../../../cime/tools/unit_testing/run_tests.py --test-spec-dir=. --compiler=intel \ ---mpilib=mpich2 --mpirun-command=mpirun.lsf --cmake-args=-DPAPI_LIB=/glade/apps/opt/papi/5.3.0/intel/12.1.5/lib64 +../../../../../cime/scripts/fortran_unit_testing/run_tests.py --build-dir unit_test_build diff --git a/tools/mksurfdata_map/src/mkfileMod.F90 b/tools/mksurfdata_map/src/mkfileMod.F90 index 09f0b5a9f9..693eb3af2a 100644 --- a/tools/mksurfdata_map/src/mkfileMod.F90 +++ b/tools/mksurfdata_map/src/mkfileMod.F90 @@ -60,10 +60,8 @@ subroutine mkfile(domain, fname, harvdata, dynlanduse) end if if (.not. dynlanduse) then - if ( nglcec > 0 )then - call check_ret(nf_def_dim (ncid, 'nglcec' , nglcec , dimid), subname) - call check_ret(nf_def_dim (ncid, 'nglcecp1', nglcec+1 , dimid), subname) - end if + call check_ret(nf_def_dim (ncid, 'nglcec' , nglcec , dimid), subname) + call check_ret(nf_def_dim (ncid, 'nglcecp1', nglcec+1 , dimid), subname) end if call check_ret(nf_def_dim (ncid, 'numurbl' , numurbl , dimid), subname) call check_ret(nf_def_dim (ncid, 'nlevurb' , nlevurb , dimid), subname) @@ -492,32 +490,30 @@ subroutine mkfile(domain, fname, harvdata, dynlanduse) call ncd_def_spatial_var(ncid=ncid, varname='GLACIER_REGION', xtype=nf_int, & long_name='glacier region ID', units='unitless') - if ( nglcec > 0 )then - call ncd_defvar(ncid=ncid, varname='GLC_MEC', xtype=xtype, & - dim1name='nglcecp1', long_name='Glacier elevation class', units='m') - - call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_MEC', xtype=xtype, & - lev1name='nglcec', & - long_name='percent glacier for each glacier elevation class (% of landunit)', units='unitless') - - call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_MEC_GIC', xtype=xtype, & - lev1name='nglcec', & - long_name='percent smaller glaciers and ice caps for each glacier elevation class (% of landunit)', units='unitless') - - call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_MEC_ICESHEET', xtype=xtype, & - lev1name='nglcec', & - long_name='percent ice sheet for each glacier elevation class (% of landunit)', units='unitless') - - call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_GIC', xtype=xtype, & - long_name='percent ice caps/glaciers (% of landunit)', units='unitless') - - call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_ICESHEET', xtype=xtype, & - long_name='percent ice sheet (% of landunit)', units='unitless') - - call ncd_def_spatial_var(ncid=ncid, varname='TOPO_GLC_MEC', xtype=xtype, & - lev1name='nglcec', & - long_name='mean elevation on glacier elevation classes', units='m') - end if + call ncd_defvar(ncid=ncid, varname='GLC_MEC', xtype=xtype, & + dim1name='nglcecp1', long_name='Glacier elevation class', units='m') + + call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_MEC', xtype=xtype, & + lev1name='nglcec', & + long_name='percent glacier for each glacier elevation class (% of landunit)', units='unitless') + + call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_MEC_GIC', xtype=xtype, & + lev1name='nglcec', & + long_name='percent smaller glaciers and ice caps for each glacier elevation class (% of landunit)', units='unitless') + + call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_MEC_ICESHEET', xtype=xtype, & + lev1name='nglcec', & + long_name='percent ice sheet for each glacier elevation class (% of landunit)', units='unitless') + + call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_GIC', xtype=xtype, & + long_name='percent ice caps/glaciers (% of landunit)', units='unitless') + + call ncd_def_spatial_var(ncid=ncid, varname='PCT_GLC_ICESHEET', xtype=xtype, & + long_name='percent ice sheet (% of landunit)', units='unitless') + + call ncd_def_spatial_var(ncid=ncid, varname='TOPO_GLC_MEC', xtype=xtype, & + lev1name='nglcec', & + long_name='mean elevation on glacier elevation classes', units='m') call ncd_def_spatial_var(ncid=ncid, varname='PCT_URBAN', xtype=xtype, & lev1name='numurbl', & diff --git a/tools/mksurfdata_map/src/mkglacierregionMod.F90 b/tools/mksurfdata_map/src/mkglacierregionMod.F90 index e90d848d39..b9a36d8263 100644 --- a/tools/mksurfdata_map/src/mkglacierregionMod.F90 +++ b/tools/mksurfdata_map/src/mkglacierregionMod.F90 @@ -33,13 +33,14 @@ subroutine mkglacierregion(ldomain, mapfname, datfname, ndiag, & ! !DESCRIPTION: ! Make glacier region ID ! - ! Regridding is done using dominant index, giving preference to non-zero values. + ! Regridding is done by finding the max index that overlaps each destination cell, + ! without regard to the weight of overlap or dominance of each overlapping index. ! ! !USES: use mkdomainMod, only : domain_type, domain_clean, domain_read, domain_checksame use mkgridmapMod use mkncdio - use mkindexmapMod, only : get_dominant_indices + use mkindexmapMod, only : get_max_indices use mkdiagnosticsMod, only : output_diagnostics_index use mkchecksMod, only : min_bad ! @@ -95,20 +96,13 @@ subroutine mkglacierregion(ldomain, mapfname, datfname, ndiag, & stop end if - ! The raw data go from 0 to max_region. However, 0 is just the "fill" value, - ! indicating that a point is not in any particular glacier region of interest. So, if - ! an output point has any non-zero input points, we want to use that non-zero value, - ! even if it is mostly made up of zero points. We accomplish this by setting minval - ! to 1 rather than 0, and using 0 for the nodata value. - max_region = maxval(glacier_region_i) - call get_dominant_indices( & + call get_max_indices( & gridmap = tgridmap, & src_array = glacier_region_i, & dst_array = glacier_region_o, & - minval = 1, & - maxval = max_region, & nodata = 0) + max_region = maxval(glacier_region_i) call output_diagnostics_index(glacier_region_i, glacier_region_o, tgridmap, & 'Glacier Region ID', 0, max_region, ndiag) diff --git a/tools/mksurfdata_map/src/mkglcmecMod.F90 b/tools/mksurfdata_map/src/mkglcmecMod.F90 index c186904cb9..9e5a1cc2a0 100644 --- a/tools/mksurfdata_map/src/mkglcmecMod.F90 +++ b/tools/mksurfdata_map/src/mkglcmecMod.F90 @@ -107,10 +107,8 @@ subroutine mkglcmecInit( elevclass_o ) else if ( nglcec == 1 )then elevclass(1) = 0. elevclass(2) = 10000. - else if ( nglcec == 0 )then - elevclass(1) = 10000. else - write(6,*) subname//"ERROR:: nglcec must be 0, 1, 3, 5, 10 or 36",& + write(6,*) subname//"ERROR:: nglcec must be 1, 3, 5, 10 or 36",& " to work with CLM: " call abort() end if @@ -147,8 +145,6 @@ subroutine mkglcmec(ldomain, mapfname, & ! If the input glacier area is 0 for a given grid cell, this requires setting these % ! variables in an arbitrary way. ! -! Does nothing if nglcec==0. -! ! !USES: use mkdomainMod, only : domain_type, domain_clean, domain_read use mkgridmapMod @@ -222,16 +218,6 @@ subroutine mkglcmec(ldomain, mapfname, & ns_o = ldomain%ns - ! ----------------------------------------------------------------- - ! Exit early, if no elevation class info is requested - ! ----------------------------------------------------------------- - if ( nglcec == 0 )then - write (6,*) 'Number of glacier elevation classes is zero ',& - '-- set glcmec to zero as well' - call shr_sys_flush(6) - return - end if - write (6,*) 'Attempting to make percent elevation class ',& 'and mean elevation for glaciers .....' call shr_sys_flush(6) diff --git a/tools/mksurfdata_map/src/mkgridmapMod.F90 b/tools/mksurfdata_map/src/mkgridmapMod.F90 index cb3e36b3c8..38844eb7cd 100644 --- a/tools/mksurfdata_map/src/mkgridmapMod.F90 +++ b/tools/mksurfdata_map/src/mkgridmapMod.F90 @@ -16,11 +16,8 @@ module mkgridmapMod ! !PUBLIC TYPES: type gridmap_type character(len=32) :: set ! If set or not - character(len=32) :: name integer :: na ! size of source domain integer :: nb ! size of destination domain - integer :: ni ! number of row in the matrix - integer :: nj ! number of col in the matrix integer :: ns ! number of non-zero elements in matrix real(r8), pointer :: yc_src(:) ! "degrees" real(r8), pointer :: yc_dst(:) ! "degrees" @@ -40,9 +37,11 @@ module mkgridmapMod ! ! !PUBLIC MEMBER FUNCTIONS: public :: gridmap_setptrs ! Set pointers to gridmap data + public :: for_test_create_gridmap ! Set a gridmap directly, for testing public :: gridmap_mapread ! Read in gridmap public :: gridmap_check ! Check validity of a gridmap public :: gridmap_areaave ! do area average + public :: gridmap_areaave_scs ! area average, but multiply by ratio of source over destination weight public :: gridmap_areastddev ! do area-weighted standard deviation public :: gridmap_clean ! Clean and deallocate a gridmap structure ! @@ -61,9 +60,15 @@ module mkgridmapMod ! from frac_dst which is calculated by mapping frac_src? ! in frac - isn't grid1_frac always 1 or 0? -! !PRIVATE MEMBER FUNCTIONS: + ! !PRIVATE MEMBER FUNCTIONS: + private :: set_gridmap_var private :: gridmap_checkifset + interface set_gridmap_var + module procedure set_gridmap_var_r8 + module procedure set_gridmap_var_int + end interface set_gridmap_var + character(len=32), parameter :: isSet = "gridmap_IsSet" ! @@ -137,11 +142,14 @@ subroutine gridmap_mapread(gridmap, fileName) ! This subroutine reads in the map file ! ! !USES: + use mkncdio, only : nf_open, nf_close, nf_strerror + use mkncdio, only : nf_inq_dimid, nf_inq_dimlen + use mkncdio, only : nf_inq_varid, nf_get_var_double, nf_get_var_int + use mkncdio, only : NF_NOWRITE, NF_NOERR use mkncdio, only : convert_latlon ! ! !ARGUMENTS: implicit none - include 'netcdf.inc' type(gridmap_type), intent(out) :: gridmap ! mapping data character(len=*) , intent(in) :: filename ! netCDF file to read ! @@ -302,6 +310,167 @@ end subroutine gridmap_mapread !========================================================================== + !----------------------------------------------------------------------- + subroutine for_test_create_gridmap(gridmap, na, nb, ns, & + src_indx, dst_indx, wovr, & + mask_src, mask_dst, frac_src, frac_dst, area_src, area_dst, & + xc_src, xc_dst, yc_src, yc_dst) + ! + ! !DESCRIPTION: + ! Creates a gridmap object directly from inputs + ! + ! This is meant for testing + ! + ! !ARGUMENTS: + type(gridmap_type), intent(out) :: gridmap + integer, intent(in) :: na + integer, intent(in) :: nb + integer, intent(in) :: ns + integer, intent(in) :: src_indx(:) + integer, intent(in) :: dst_indx(:) + real(r8), intent(in) :: wovr(:) + + ! If not provided, mask and frac values are set to 1 everywhere + integer, intent(in), optional :: mask_src(:) + integer, intent(in), optional :: mask_dst(:) + real(r8), intent(in), optional :: frac_src(:) + real(r8), intent(in), optional :: frac_dst(:) + + ! If not provided, area values are set to a constant value everywhere + real(r8), intent(in), optional :: area_src(:) + real(r8), intent(in), optional :: area_dst(:) + + ! If not provided, xc and yc values are set to 0 everywhere + real(r8), intent(in), optional :: xc_src(:) + real(r8), intent(in), optional :: xc_dst(:) + real(r8), intent(in), optional :: yc_src(:) + real(r8), intent(in), optional :: yc_dst(:) + + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'for_test_create_gridmap' + !----------------------------------------------------------------------- + + ! ------------------------------------------------------------------------ + ! Error checking on sizes of arrays + ! ------------------------------------------------------------------------ + call check_input_size('src_indx', size(src_indx), ns) + call check_input_size('dst_indx', size(dst_indx), ns) + call check_input_size('wovr', size(wovr), ns) + + if (present(mask_src)) then + call check_input_size('mask_src', size(mask_src), na) + end if + if (present(frac_src)) then + call check_input_size('frac_src', size(frac_src), na) + end if + if (present(area_src)) then + call check_input_size('area_src', size(area_src), na) + end if + if (present(xc_src)) then + call check_input_size('xc_src', size(xc_src), na) + end if + if (present(yc_src)) then + call check_input_size('yc_src', size(yc_src), na) + end if + + if (present(mask_dst)) then + call check_input_size('mask_dst', size(mask_dst), nb) + end if + if (present(frac_dst)) then + call check_input_size('frac_dst', size(frac_dst), nb) + end if + if (present(area_dst)) then + call check_input_size('area_dst', size(area_dst), nb) + end if + if (present(xc_dst)) then + call check_input_size('xc_dst', size(xc_dst), nb) + end if + if (present(yc_dst)) then + call check_input_size('yc_dst', size(yc_dst), nb) + end if + + ! ------------------------------------------------------------------------ + ! Create gridmap object + ! ------------------------------------------------------------------------ + + gridmap%na = na + gridmap%nb = nb + gridmap%ns = ns + + allocate(gridmap%src_indx(ns)) + gridmap%src_indx = src_indx + allocate(gridmap%dst_indx(ns)) + gridmap%dst_indx = dst_indx + allocate(gridmap%wovr(ns)) + gridmap%wovr = wovr + + allocate(gridmap%mask_src(na)) + call set_gridmap_var(gridmap%mask_src, 1, mask_src) + allocate(gridmap%mask_dst(nb)) + call set_gridmap_var(gridmap%mask_dst, 1, mask_dst) + allocate(gridmap%frac_src(na)) + call set_gridmap_var(gridmap%frac_src, 1._r8, frac_src) + allocate(gridmap%frac_dst(nb)) + call set_gridmap_var(gridmap%frac_dst, 1._r8, frac_dst) + + allocate(gridmap%yc_src(na)) + call set_gridmap_var(gridmap%yc_src, 0._r8, yc_src) + allocate(gridmap%yc_dst(nb)) + call set_gridmap_var(gridmap%yc_dst, 0._r8, yc_dst) + allocate(gridmap%xc_src(na)) + call set_gridmap_var(gridmap%xc_src, 0._r8, xc_src) + allocate(gridmap%xc_dst(nb)) + call set_gridmap_var(gridmap%xc_dst, 0._r8, xc_dst) + allocate(gridmap%area_src(na)) + call set_gridmap_var(gridmap%area_src, 0._r8, area_src) + allocate(gridmap%area_dst(nb)) + call set_gridmap_var(gridmap%area_dst, 0._r8, area_dst) + + gridmap%set = isSet + + contains + subroutine check_input_size(varname, actual_size, expected_size) + character(len=*), intent(in) :: varname + integer, intent(in) :: actual_size + integer, intent(in) :: expected_size + + if (actual_size /= expected_size) then + write(6,*) subname, ' ERROR: ', trim(varname), ' wrong size: actual, expected = ', & + actual_size, expected_size + call abort() + end if + end subroutine check_input_size + + end subroutine for_test_create_gridmap + + subroutine set_gridmap_var_r8(var, default_val, input_val) + ! Convenience subroutine to set a variable to an optional input or a default value + real(r8), intent(out) :: var(:) + real(r8), intent(in) :: default_val + real(r8), intent(in), optional :: input_val(:) + + if (present(input_val)) then + var = input_val + else + var = default_val + end if + end subroutine set_gridmap_var_r8 + + subroutine set_gridmap_var_int(var, default_val, input_val) + ! Convenience subroutine to set a variable to an optional input or a default value + integer, intent(out) :: var(:) + integer, intent(in) :: default_val + integer, intent(in), optional :: input_val(:) + + if (present(input_val)) then + var = input_val + else + var = default_val + end if + end subroutine set_gridmap_var_int + !------------------------------------------------------------------------------ !BOP ! @@ -426,6 +595,72 @@ subroutine gridmap_areaave_default (gridmap, src_array, dst_array, nodata) end subroutine gridmap_areaave_default +!------------------------------------------------------------------------------ +!BOP +! +! !IROUTINE: gridmap_areaave_scs +! +! !INTERFACE: + subroutine gridmap_areaave_scs (gridmap, src_array, dst_array, nodata, src_wt, dst_wt) +! +! !DESCRIPTION: +! This subroutine does a simple area average, but multiplies by the ratio of the source over +! the destination weight. Sets to zero if destination weight is zero. +! +! !ARGUMENTS: + implicit none + type(gridmap_type) , intent(in) :: gridmap ! gridmap data + real(r8), intent(in) :: src_array(:) + real(r8), intent(out):: dst_array(:) + real(r8), intent(in) :: nodata ! value to apply where there are no input data + real(r8), intent(in) :: src_wt(:) ! Source weights + real(r8), intent(in) :: dst_wt(:) ! Destination weights + +! +! !REVISION HISTORY: +! Created by Mariana Vertenstein, moditied by Sean Swenson +! +! !LOCAL VARIABLES: + integer :: n,ns,ni,no + real(r8):: wt,frac,swt,dwt + real(r8), allocatable :: sum_weights(:) ! sum of weights on the output grid + character(*),parameter :: subName = '(gridmap_areaave_scs) ' +!EOP +!------------------------------------------------------------------------------ + call gridmap_checkifset( gridmap, subname ) + allocate(sum_weights(size(dst_array))) + sum_weights = 0._r8 + dst_array = 0._r8 + + do n = 1,gridmap%ns + ni = gridmap%src_indx(n) + no = gridmap%dst_indx(n) + wt = gridmap%wovr(n) + frac = gridmap%frac_dst(no) + swt = src_wt(ni) + dwt = dst_wt(no) + wt = wt * swt + if(dwt > 0._r8) then + wt = wt / dwt + else + wt = 0._r8 + endif + if (frac > 0.) then + dst_array(no) = dst_array(no) + wt * src_array(ni)/frac + sum_weights(no) = sum_weights(no) + wt + end if + end do + + where (sum_weights == 0._r8) + dst_array = nodata + end where + + deallocate(sum_weights) + + end subroutine gridmap_areaave_scs + +!========================================================================== + !========================================================================== !------------------------------------------------------------------------------ diff --git a/tools/mksurfdata_map/src/mkharvestMod.F90 b/tools/mksurfdata_map/src/mkharvestMod.F90 index c6eb0750aa..bf1999d78a 100644 --- a/tools/mksurfdata_map/src/mkharvestMod.F90 +++ b/tools/mksurfdata_map/src/mkharvestMod.F90 @@ -68,15 +68,15 @@ module mkharvestMod integer, parameter :: harlen = 25 ! length of strings for harvest fieldnames character(len=harlen), parameter :: harvest_fieldnames(numharv) = (/ & - 'HARVEST_VH1 ', & - 'HARVEST_VH2 ', & - 'HARVEST_SH1 ', & - 'HARVEST_SH2 ', & - 'HARVEST_SH3 ', & - 'GRAZING ', & - 'FERTNITRO_CFT', & - 'PFT_LULCC ', & - 'CFT_LULCC ' & + 'HARVEST_VH1 ', & + 'HARVEST_VH2 ', & + 'HARVEST_SH1 ', & + 'HARVEST_SH2 ', & + 'HARVEST_SH3 ', & + 'GRAZING ', & + 'FERTNITRO_CFT ', & + 'UNREPRESENTED_PFT_LULCC', & + 'UNREPRESENTED_CFT_LULCC' & /) character(len=harlen), parameter :: harvest_const_fieldnames(numharv) = (/ & 'CONST_HARVEST_VH1 ', & @@ -89,7 +89,7 @@ module mkharvestMod 'UNREPRESENTED_PFT_LULCC', & 'UNREPRESENTED_CFT_LULCC' & /) - character(len=CL), parameter :: string_undef = 'STRING_UNDEFINED' + character(len=CL), parameter :: string_undef = 'UNSET' real(r8), parameter :: real_undef = -999.99 character(len=CL), save :: harvest_longnames(numharv) = string_undef character(len=CL), save :: harvest_units(numharv) = string_undef diff --git a/tools/mksurfdata_map/src/mkindexmapMod.F90 b/tools/mksurfdata_map/src/mkindexmapMod.F90 index 28ed621110..903f231578 100644 --- a/tools/mksurfdata_map/src/mkindexmapMod.F90 +++ b/tools/mksurfdata_map/src/mkindexmapMod.F90 @@ -22,6 +22,7 @@ module mkindexmapMod ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use mkncdio, only : nf_max_name + use mkgridmapMod, only : gridmap_type implicit none private @@ -38,6 +39,7 @@ module mkindexmapMod ! ! !PUBLIC MEMBER FUNCTIONS: public :: get_dominant_indices ! make output map based on dominant type in each grid cell + public :: get_max_indices ! make output map based on maximum type in each grid cell public :: filter_same ! build a filter of overlaps where src_val == dst_val public :: lookup_2d ! create map based on a 2-d lookup table public :: lookup_2d_netcdf ! wrapper to lookup_2d; first read table from netcdf file @@ -75,9 +77,6 @@ subroutine get_dominant_indices(gridmap, src_array, dst_array, minval, maxval, n ! ! Output grid cells with no contributing valid source points are given the nodata value ! -! !USES: - use mkgridmapMod, only : gridmap_type -! ! !ARGUMENTS: implicit none type(gridmap_type), intent(in) :: gridmap ! provides mapping from src -> dst @@ -180,7 +179,76 @@ subroutine get_dominant_indices(gridmap, src_array, dst_array, minval, maxval, n end subroutine get_dominant_indices !------------------------------------------------------------------------------ - + +!----------------------------------------------------------------------- +subroutine get_max_indices(gridmap, src_array, dst_array, nodata) + ! + ! !DESCRIPTION: + ! Fills an output array on the destination grid (dst_array) whose values are equal to + ! the maximum value in the source grid cells overlapping a given destination grid cell. + ! + ! The frequency of occurrence of the source values is irrelevant. For example, if the + ! value 1 appears in 99% of source cells overlapping a given destination cell and the + ! value 2 appears in just 1%, we'll put 2 in the destination cell because it is the + ! maximum value. + ! + ! Output grid cells with no contributing valid source points are given the nodata value + ! + ! !ARGUMENTS: + type(gridmap_type) , intent(in) :: gridmap ! provides mapping from src -> dst + integer , intent(in) :: src_array(:) ! input values; length gridmap%na + integer , intent(out) :: dst_array(:) ! output values; length gridmap%nb + integer , intent(in) :: nodata ! value to assign to dst_array where there are no valid source points + ! + ! !LOCAL VARIABLES: + logical, allocatable :: hasdata(:) ! true if an output cell has any valid data; + integer :: n, ni, no + real(r8) :: wt + integer :: src_val + + character(len=*), parameter :: subname = 'get_max_indices' + !----------------------------------------------------------------------- + + ! Error-check inputs + + if (size(src_array) /= gridmap%na .or. & + size(dst_array) /= gridmap%nb) then + write(6,*) subname//' ERROR: incorrect sizes of src_array or dst_array' + write(6,*) 'size(src_array) = ', size(src_array) + write(6,*) 'gridmap%na = ', gridmap%na + write(6,*) 'size(dst_array) = ', size(dst_array) + write(6,*) 'gridmap%nb = ', gridmap%nb + call abort() + end if + + ! Initialize local variables + allocate(hasdata(gridmap%nb)) + hasdata(:) = .false. + + do n = 1, gridmap%ns + wt = gridmap%wovr(n) + if (wt > 0._r8) then + ni = gridmap%src_indx(n) + no = gridmap%dst_indx(n) + src_val = src_array(ni) + if (.not. hasdata(no)) then + hasdata(no) = .true. + dst_array(no) = src_val + else if (src_val > dst_array(no)) then + dst_array(no) = src_val + end if + end if + end do + + do no = 1, gridmap%nb + if (.not. hasdata(no)) then + dst_array(no) = nodata + end if + end do + +end subroutine get_max_indices + + !------------------------------------------------------------------------------ !BOP ! @@ -204,9 +272,6 @@ subroutine filter_same(gridmap, filter, src_array, dst_array, nodata) ! in the given dst_array, filter will be .false. ! (4) anywhere else, filter will be .true. ! -! !USES: - use mkgridmapMod, only : gridmap_type -! ! !ARGUMENTS: implicit none type(gridmap_type), intent(in) :: gridmap ! provides mapping from src -> dst diff --git a/tools/mksurfdata_map/src/mkncdio.F90 b/tools/mksurfdata_map/src/mkncdio.F90 index 9da95ff2d7..555eb6ae80 100644 --- a/tools/mksurfdata_map/src/mkncdio.F90 +++ b/tools/mksurfdata_map/src/mkncdio.F90 @@ -72,6 +72,7 @@ module mkncdio public :: nf_max_name public :: nf_max_var_dims public :: nf_noerr + public :: nf_nowrite public :: nf_enotatt public :: nf_strerror !EOP diff --git a/tools/mksurfdata_map/src/mkpftMod.F90 b/tools/mksurfdata_map/src/mkpftMod.F90 index 6b44c703f0..5a3686a0ae 100644 --- a/tools/mksurfdata_map/src/mkpftMod.F90 +++ b/tools/mksurfdata_map/src/mkpftMod.F90 @@ -475,8 +475,14 @@ subroutine mkpft(ldomain, mapfname, fpft, ndiag, allow_no_crops, & if ( zero_out ) then - pctpft_o(:,:) = 0._r8 - pctlnd_o(:) = 100._r8 + pctpft_o(:,:) = 0._r8 + pctlnd_o(:) = 100._r8 + pctnatveg_o(:) = 0._r8 + pctcrop_o(:) = 0._r8 + pct_nat_pft_o(:,:) = 0._r8 + pct_nat_pft_o(:,0) = 100._r8 + pct_cft_o(:,:) = 0._r8 + pct_cft_o(:,1) = 100._r8 else if ( use_input_pft ) then @@ -516,8 +522,9 @@ subroutine mkpft(ldomain, mapfname, fpft, ndiag, allow_no_crops, & if ( .not. oldformat ) then call gridmap_areaave(tgridmap, pctnatveg_i, pctnatveg_o, nodata=0._r8) call gridmap_areaave(tgridmap, pctcrop_i, pctcrop_o, nodata=0._r8) + do m = 0, num_natpft - call gridmap_areaave(tgridmap, pct_nat_pft_i(:,m), pct_nat_pft_o(:,m), nodata=0._r8) + call gridmap_areaave_scs(tgridmap, pct_nat_pft_i(:,m), pct_nat_pft_o(:,m), nodata=0._r8,src_wt=pctnatveg_i*0.01_r8,dst_wt=pctnatveg_o*0.01_r8) do no = 1,ns_o if (pctlnd_o(no) < 1.0e-6 .or. pctnatveg_o(no) < 1.0e-6) then if (m == 0) then @@ -529,7 +536,7 @@ subroutine mkpft(ldomain, mapfname, fpft, ndiag, allow_no_crops, & enddo end do do m = 1, num_cft - call gridmap_areaave(tgridmap, pct_cft_i(:,m), pct_cft_o(:,m), nodata=0._r8) + call gridmap_areaave_scs(tgridmap, pct_cft_i(:,m), pct_cft_o(:,m), nodata=0._r8,src_wt=pctcrop_i*0.01_r8,dst_wt=pctcrop_o*0.01_r8) do no = 1,ns_o if (pctlnd_o(no) < 1.0e-6 .or. pctcrop_o(no) < 1.0e-6) then if (m == 1) then diff --git a/tools/mksurfdata_map/src/mksurfdat.F90 b/tools/mksurfdata_map/src/mksurfdat.F90 index 98deb8ee42..97d53aac02 100644 --- a/tools/mksurfdata_map/src/mksurfdat.F90 +++ b/tools/mksurfdata_map/src/mksurfdat.F90 @@ -353,6 +353,10 @@ program mksurfdat if ( no_inlandwet )then write(6,*) 'Set wetland to 0% over land' end if + if (nglcec <= 0) then + write(6,*) 'nglcec must be at least 1' + call abort() + end if ! ! Call module initialization routines @@ -772,28 +776,25 @@ program mksurfdat ! Make glacier multiple elevation classes [pctglcmec,topoglcmec] from [fglacier] dataset ! This call needs to occur after pctgla has been adjusted for the final time - if ( nglcec > 0 )then - - allocate (pctglcmec(ns_o,nglcec), & - topoglcmec(ns_o,nglcec), & - pctglcmec_gic(ns_o,nglcec), & - pctglcmec_icesheet(ns_o,nglcec)) - allocate (pctglc_gic(ns_o)) - allocate (pctglc_icesheet(ns_o)) - - pctglcmec(:,:) = spval - topoglcmec(:,:) = spval - pctglcmec_gic(:,:) = spval - pctglcmec_icesheet(:,:) = spval - pctglc_gic(:) = spval - pctglc_icesheet(:) = spval - - call mkglcmec (ldomain, mapfname=map_fglacier, & - datfname_fglacier=mksrf_fglacier, ndiag=ndiag, & - pctglcmec_o=pctglcmec, topoglcmec_o=topoglcmec, & - pctglcmec_gic_o=pctglcmec_gic, pctglcmec_icesheet_o=pctglcmec_icesheet, & - pctglc_gic_o=pctglc_gic, pctglc_icesheet_o=pctglc_icesheet) - end if + allocate (pctglcmec(ns_o,nglcec), & + topoglcmec(ns_o,nglcec), & + pctglcmec_gic(ns_o,nglcec), & + pctglcmec_icesheet(ns_o,nglcec)) + allocate (pctglc_gic(ns_o)) + allocate (pctglc_icesheet(ns_o)) + + pctglcmec(:,:) = spval + topoglcmec(:,:) = spval + pctglcmec_gic(:,:) = spval + pctglcmec_icesheet(:,:) = spval + pctglc_gic(:) = spval + pctglc_icesheet(:) = spval + + call mkglcmec (ldomain, mapfname=map_fglacier, & + datfname_fglacier=mksrf_fglacier, ndiag=ndiag, & + pctglcmec_o=pctglcmec, topoglcmec_o=topoglcmec, & + pctglcmec_gic_o=pctglcmec_gic, pctglcmec_icesheet_o=pctglcmec_icesheet, & + pctglc_gic_o=pctglc_gic, pctglc_icesheet_o=pctglc_icesheet) ! Determine fractional land from pft dataset @@ -866,29 +867,26 @@ program mksurfdat call check_ret(nf_inq_varid(ncid, 'GLACIER_REGION', varid), subname) call check_ret(nf_put_var_int(ncid, varid, glacier_region), subname) - if ( nglcec > 0 )then - call check_ret(nf_inq_varid(ncid, 'PCT_GLC_MEC', varid), subname) - call check_ret(nf_put_var_double(ncid, varid, pctglcmec), subname) + call check_ret(nf_inq_varid(ncid, 'PCT_GLC_MEC', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, pctglcmec), subname) - call check_ret(nf_inq_varid(ncid, 'GLC_MEC', varid), subname) - call check_ret(nf_put_var_double(ncid, varid, elevclass), subname) + call check_ret(nf_inq_varid(ncid, 'GLC_MEC', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, elevclass), subname) - call check_ret(nf_inq_varid(ncid, 'TOPO_GLC_MEC', varid), subname) - call check_ret(nf_put_var_double(ncid, varid, topoglcmec), subname) + call check_ret(nf_inq_varid(ncid, 'TOPO_GLC_MEC', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, topoglcmec), subname) - call check_ret(nf_inq_varid(ncid, 'PCT_GLC_MEC_GIC', varid), subname) - call check_ret(nf_put_var_double(ncid, varid, pctglcmec_gic), subname) + call check_ret(nf_inq_varid(ncid, 'PCT_GLC_MEC_GIC', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, pctglcmec_gic), subname) - call check_ret(nf_inq_varid(ncid, 'PCT_GLC_MEC_ICESHEET', varid), subname) - call check_ret(nf_put_var_double(ncid, varid, pctglcmec_icesheet), subname) + call check_ret(nf_inq_varid(ncid, 'PCT_GLC_MEC_ICESHEET', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, pctglcmec_icesheet), subname) - call check_ret(nf_inq_varid(ncid, 'PCT_GLC_GIC', varid), subname) - call check_ret(nf_put_var_double(ncid, varid, pctglc_gic), subname) + call check_ret(nf_inq_varid(ncid, 'PCT_GLC_GIC', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, pctglc_gic), subname) - call check_ret(nf_inq_varid(ncid, 'PCT_GLC_ICESHEET', varid), subname) - call check_ret(nf_put_var_double(ncid, varid, pctglc_icesheet), subname) - - end if + call check_ret(nf_inq_varid(ncid, 'PCT_GLC_ICESHEET', varid), subname) + call check_ret(nf_put_var_double(ncid, varid, pctglc_icesheet), subname) call check_ret(nf_inq_varid(ncid, 'PCT_URBAN', varid), subname) call check_ret(nf_put_var_double(ncid, varid, urbn_classes_g), subname) @@ -1032,8 +1030,8 @@ program mksurfdat deallocate ( organic ) deallocate ( ef1_btr, ef1_fet, ef1_fdt, ef1_shr, ef1_grs, ef1_crp ) - if ( nglcec > 0 ) deallocate ( pctglcmec, topoglcmec) - if ( nglcec > 0 ) deallocate ( pctglc_gic, pctglc_icesheet) + deallocate ( pctglcmec, topoglcmec) + deallocate ( pctglc_gic, pctglc_icesheet) deallocate ( elevclass ) deallocate ( fmax ) deallocate ( pctsand, pctclay ) diff --git a/tools/mksurfdata_map/src/test/CMakeLists.txt b/tools/mksurfdata_map/src/test/CMakeLists.txt index 60507de2cc..690bee396e 100644 --- a/tools/mksurfdata_map/src/test/CMakeLists.txt +++ b/tools/mksurfdata_map/src/test/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(mkpctPftType_test) add_subdirectory(mkpftUtils_test) +add_subdirectory(mkgridmap_test) +add_subdirectory(mkindexmap_test) \ No newline at end of file diff --git a/tools/mksurfdata_map/src/test/mkgridmap_test/CMakeLists.txt b/tools/mksurfdata_map/src/test/mkgridmap_test/CMakeLists.txt new file mode 100644 index 0000000000..85d936fd33 --- /dev/null +++ b/tools/mksurfdata_map/src/test/mkgridmap_test/CMakeLists.txt @@ -0,0 +1,4 @@ +create_pFUnit_test(mkgridmap test_mkgridmap_exe + "test_mkgridmap.pf" "") + +target_link_libraries(test_mkgridmap_exe mksurfdat) \ No newline at end of file diff --git a/tools/mksurfdata_map/src/test/mkgridmap_test/test_mkgridmap.pf b/tools/mksurfdata_map/src/test/mkgridmap_test/test_mkgridmap.pf new file mode 100644 index 0000000000..01887cb467 --- /dev/null +++ b/tools/mksurfdata_map/src/test/mkgridmap_test/test_mkgridmap.pf @@ -0,0 +1,114 @@ +module test_mkgridmap + + ! Tests of mkgridmapMod + + use pfunit_mod + use mkgridmapMod + use shr_kind_mod , only : r8 => shr_kind_r8 + + implicit none + + @TestCase + type, extends(TestCase) :: TestMkGridmap + type(gridmap_type) :: gridmap + contains + procedure :: setUp + procedure :: tearDown + end type TestMkGridmap + + real(r8), parameter :: tol = 1.e-13_r8 + +contains + + subroutine setUp(this) + class(TestMkGridmap), intent(inout) :: this + end subroutine setUp + + subroutine tearDown(this) + class(TestMkGridmap), intent(inout) :: this + + call gridmap_clean(this%gridmap) + end subroutine tearDown + + ! ------------------------------------------------------------------------ + ! Tests of for_test_create_gridmap + ! ------------------------------------------------------------------------ + + @Test + subroutine forTestCreateGridmap_defaultArgs(this) + class(TestMkGridmap), intent(inout) :: this + call for_test_create_gridmap(this%gridmap, na=2, nb=3, ns=4, & + src_indx = [11,11,12,12], & + dst_indx = [21,22,22,23], & + wovr = [1._r8, 0.5_r8, 0.5_r8, 1._r8]) + + @assertEqual(2, this%gridmap%na) + @assertEqual(3, this%gridmap%nb) + @assertEqual(4, this%gridmap%ns) + @assertEqual([11,11,12,12], this%gridmap%src_indx) + @assertEqual([21,22,22,23], this%gridmap%dst_indx) + @assertEqual([1._r8, 0.5_r8, 0.5_r8, 1._r8], this%gridmap%wovr) + @assertEqual([1,1], this%gridmap%mask_src) + @assertEqual([1,1,1], this%gridmap%mask_dst) + @assertEqual([1._r8, 1._r8], this%gridmap%frac_src) + @assertEqual([1._r8, 1._r8, 1._r8], this%gridmap%frac_dst) + + ! Don't bother asserting area, xc, yc, because the default values of those shouldn't + ! matter too much. + end subroutine forTestCreateGridmap_defaultArgs + + @Test + subroutine forTestCreateGridmap_explicitArgs(this) + class(TestMkGridmap), intent(inout) :: this + integer, parameter :: na = 2 + integer, parameter :: nb = 3 + integer, parameter :: ns = 4 + integer, parameter :: src_indx(ns) = [11,11,12,12] + integer, parameter :: dst_indx(ns) = [21,22,22,23] + real(r8), parameter :: wovr(ns) = [1._r8, 0.5_r8, 0.5_r8, 1._r8] + integer, parameter :: mask_src(na) = [1, 0] + integer, parameter :: mask_dst(nb) = [0, 1, 1] + real(r8), parameter :: frac_src(na) = [0.1_r8, 0.0_r8] + real(r8), parameter :: frac_dst(nb) = [0.0_r8, 0.1_r8, 0.1_r8] + real(r8), parameter :: area_src(na) = [0.11_r8, 0.12_r8] + real(r8), parameter :: area_dst(nb) = [0.13_r8, 0.14_r8, 0.15_r8] + real(r8), parameter :: xc_src(na) = [1.1_r8, 1.2_r8] + real(r8), parameter :: xc_dst(nb) = [2.1_r8, 2.2_r8, 2.3_r8] + real(r8), parameter :: yc_src(na) = [3.1_r8, 3.2_r8] + real(r8), parameter :: yc_dst(nb) = [4.1_r8, 4.2_r8, 4.3_r8] + + call for_test_create_gridmap(this%gridmap, na=na, nb=nb, ns=ns, & + src_indx = src_indx, & + dst_indx = dst_indx, & + wovr = wovr, & + mask_src = mask_src, & + mask_dst = mask_dst, & + frac_src = frac_src, & + frac_dst = frac_dst, & + area_src = area_src, & + area_dst = area_dst, & + xc_src = xc_src, & + xc_dst = xc_dst, & + yc_src = yc_src, & + yc_dst = yc_dst) + + @assertEqual(na, this%gridmap%na) + @assertEqual(nb, this%gridmap%nb) + @assertEqual(ns, this%gridmap%ns) + @assertEqual(src_indx, this%gridmap%src_indx) + @assertEqual(dst_indx, this%gridmap%dst_indx) + @assertEqual(wovr, this%gridmap%wovr) + @assertEqual(mask_src, this%gridmap%mask_src) + @assertEqual(mask_dst, this%gridmap%mask_dst) + @assertEqual(frac_src, this%gridmap%frac_src) + @assertEqual(frac_dst, this%gridmap%frac_dst) + @assertEqual(yc_src, this%gridmap%yc_src) + @assertEqual(yc_dst, this%gridmap%yc_dst) + @assertEqual(xc_src, this%gridmap%xc_src) + @assertEqual(xc_dst, this%gridmap%xc_dst) + @assertEqual(area_src, this%gridmap%area_src) + @assertEqual(area_dst, this%gridmap%area_dst) + + end subroutine forTestCreateGridmap_explicitArgs + +end module test_mkgridmap diff --git a/tools/mksurfdata_map/src/test/mkindexmap_test/CMakeLists.txt b/tools/mksurfdata_map/src/test/mkindexmap_test/CMakeLists.txt new file mode 100644 index 0000000000..044d3e4f89 --- /dev/null +++ b/tools/mksurfdata_map/src/test/mkindexmap_test/CMakeLists.txt @@ -0,0 +1,4 @@ +create_pFUnit_test(mkindexmap test_mkindexmap_exe + "test_mkindexmap.pf" "") + +target_link_libraries(test_mkindexmap_exe mksurfdat) \ No newline at end of file diff --git a/tools/mksurfdata_map/src/test/mkindexmap_test/test_mkindexmap.pf b/tools/mksurfdata_map/src/test/mkindexmap_test/test_mkindexmap.pf new file mode 100644 index 0000000000..57c0a86e97 --- /dev/null +++ b/tools/mksurfdata_map/src/test/mkindexmap_test/test_mkindexmap.pf @@ -0,0 +1,251 @@ +module test_mkindexmap + + ! Tests of mkindexmapMod + + use pfunit_mod + use mkindexmapMod + use mkgridmapMod, only : gridmap_type, for_test_create_gridmap, gridmap_clean + use shr_kind_mod , only : r8 => shr_kind_r8 + + implicit none + + @TestCase + type, extends(TestCase) :: TestMkIndexMap + type(gridmap_type) :: gridmap + contains + procedure :: setUp + procedure :: tearDown + procedure :: createGridmap + procedure :: createGridmap3src1dst + end type TestMkIndexMap + + real(r8), parameter :: tol = 1.e-13_r8 + + integer, parameter :: NODATA_VAL = -999 + +contains + + ! ------------------------------------------------------------------------ + ! Helper routines + ! ------------------------------------------------------------------------ + + + subroutine setUp(this) + class(TestMkIndexMap), intent(inout) :: this + end subroutine setUp + + subroutine tearDown(this) + class(TestMkIndexMap), intent(inout) :: this + call gridmap_clean(this%gridmap) + end subroutine tearDown + + !----------------------------------------------------------------------- + subroutine createGridmap(this, src_indx, dst_indx, wovr, & + na_in, nb_in) + ! + ! !DESCRIPTION: + ! Create this%gridmap + ! + ! !ARGUMENTS: + class(TestMkIndexMap), intent(inout) :: this + + ! The following arrays should all be the same size: + integer, intent(in) :: src_indx(:) + integer, intent(in) :: dst_indx(:) + real(r8), intent(in) :: wovr(:) ! overlap weights + + ! If not present, na is set to max(src_indx) and nb to max(dst_indx) + integer, intent(in), optional :: na_in + integer, intent(in), optional :: nb_in + + ! + ! !LOCAL VARIABLES: + integer :: na + integer :: nb + integer :: ns + + character(len=*), parameter :: subname = 'createGridmap' + !----------------------------------------------------------------------- + + ns = size(wovr) + @assertEqual(ns, size(src_indx)) + @assertEqual(ns, size(dst_indx)) + + if (present(na_in)) then + na = na_in + else + na = maxval(src_indx) + end if + + if (present(nb_in)) then + nb = nb_in + else + nb = maxval(dst_indx) + end if + + call for_test_create_gridmap(this%gridmap, na=na, nb=nb, ns=ns, & + src_indx=src_indx, dst_indx=dst_indx, wovr=wovr) + + end subroutine createGridmap + + !----------------------------------------------------------------------- + subroutine createGridmap3src1dst(this) + ! + ! !DESCRIPTION: + ! Creates a gridmap with 3 src points and 1 dst point. + ! + ! Overlap weights are 0.25, 0.5, 0.25 + ! + ! !ARGUMENTS: + class(TestMkIndexMap), intent(inout) :: this + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'createGridmap3src1dst' + !----------------------------------------------------------------------- + + call this%createGridmap( & + src_indx = [1, 2, 3], & + dst_indx = [1, 1, 1], & + wovr = [0.25_r8, 0.5_r8, 0.25_r8]) + end subroutine createGridmap3src1dst + + + ! ------------------------------------------------------------------------ + ! Tests of get_max_indices + ! ------------------------------------------------------------------------ + + @Test + subroutine getMaxIndices_maxFirst(this) + class(TestMkIndexMap), intent(inout) :: this + integer :: dst_array(1) + + call this%createGridmap3src1dst() + + call get_max_indices(& + gridmap = this%gridmap, & + src_array = [13, 12, 11], & + dst_array = dst_array, & + nodata = NODATA_VAL) + + @assertEqual([13], dst_array) + end subroutine getMaxIndices_maxFirst + + @Test + subroutine getMaxIndices_maxMiddle(this) + class(TestMkIndexMap), intent(inout) :: this + integer :: dst_array(1) + + call this%createGridmap3src1dst() + + call get_max_indices(& + gridmap = this%gridmap, & + src_array = [12, 13, 11], & + dst_array = dst_array, & + nodata = NODATA_VAL) + + @assertEqual([13], dst_array) + end subroutine getMaxIndices_maxMiddle + + @Test + subroutine getMaxIndices_maxLast(this) + class(TestMkIndexMap), intent(inout) :: this + integer :: dst_array(1) + + call this%createGridmap3src1dst() + + call get_max_indices(& + gridmap = this%gridmap, & + src_array = [11, 12, 13], & + dst_array = dst_array, & + nodata = NODATA_VAL) + + @assertEqual([13], dst_array) + end subroutine getMaxIndices_maxLast + + @Test + subroutine getMaxIndices_noData(this) + class(TestMkIndexMap), intent(inout) :: this + integer :: dst_array(2) + + ! 2 destination points, but all source points map to dest #1 (nothing maps to dest #2) + call this%createGridmap( & + src_indx = [1,2,3], & + dst_indx = [1,1,1], & + wovr = [0.25_r8, 0.5_r8, 0.25_r8], & + nb_in = 2) + + call get_max_indices(& + gridmap = this%gridmap, & + src_array = [11, 12, 13], & + dst_array = dst_array, & + nodata = NODATA_VAL) + + @assertEqual([13, NODATA_VAL], dst_array) + end subroutine getMaxIndices_noData + + @Test + subroutine getMaxIndices_noOverlap(this) + class(TestMkIndexMap), intent(inout) :: this + integer :: dst_array(2) + + ! 2 destination points, and the matrix has an overlap with dest #2, but the overlap + ! weight is 0. (I'm not sure this can happen in practice, but I'm also not sure that + ! it can't happen.) + call this%createGridmap( & + src_indx = [1,2,3,3], & + dst_indx = [1,1,1,2], & + wovr = [0.25_r8, 0.5_r8, 0.25_r8, 0._r8]) + + call get_max_indices(& + gridmap = this%gridmap, & + src_array = [11, 12, 13], & + dst_array = dst_array, & + nodata = NODATA_VAL) + + @assertEqual([13, NODATA_VAL], dst_array) + end subroutine getMaxIndices_noOverlap + + @Test + subroutine getMaxIndices_bigValNoOverlap(this) + class(TestMkIndexMap), intent(inout) :: this + integer :: dst_array(1) + + ! Overlap weight is 0 for a point with a big value. (I'm not sure this can happen in + ! practice, but I'm also not sure that it can't happen.) + call this%createGridmap( & + src_indx = [1,2,3], & + dst_indx = [1,1,1], & + wovr = [0.5_r8, 0.5_r8, 0._r8]) + + call get_max_indices(& + gridmap = this%gridmap, & + src_array = [11, 12, 13], & + dst_array = dst_array, & + nodata = NODATA_VAL) + + @assertEqual([12], dst_array) + end subroutine getMaxIndices_bigValNoOverlap + + @Test + subroutine getMaxIndices_multipleDests(this) + ! Make sure that the source/dest indexing is working right by having multiple source + ! & dest points + class(TestMkIndexMap), intent(inout) :: this + integer :: dst_array(2) + + call this%createGridmap( & + src_indx = [1,2,3,4], & + dst_indx = [1,1,2,2], & + wovr = [0.5_r8, 0.5_r8, 0.5_r8, 0.5_r8]) + + call get_max_indices(& + gridmap = this%gridmap, & + src_array = [11,12,22,21], & + dst_array = dst_array, & + nodata = NODATA_VAL) + + @assertEqual([12,22], dst_array) + end subroutine getMaxIndices_multipleDests + +end module test_mkindexmap diff --git a/tools/mksurfdata_map/src/unit_test_stubs/mkncdio.F90 b/tools/mksurfdata_map/src/unit_test_stubs/mkncdio.F90 new file mode 100644 index 0000000000..f8768b7b08 --- /dev/null +++ b/tools/mksurfdata_map/src/unit_test_stubs/mkncdio.F90 @@ -0,0 +1,167 @@ +module mkncdio + ! Stub of mkncdio for unit testing. This is enough to get other modules to compile, but + ! it doesn't do anything useful. + + use shr_kind_mod, only : r8 => shr_kind_r8 + + implicit none + private + + public :: nf_open + public :: nf_close + public :: nf_strerror + public :: nf_inq_dimid + public :: nf_inq_dimname + public :: nf_inq_dimlen + public :: nf_inq_varid + public :: nf_inq_varndims + public :: nf_inq_vardimid + public :: nf_get_var_double + public :: nf_get_var_int + public :: nf_get_vara_double + public :: nf_get_att_double + + public :: check_ret + public :: convert_latlon + + interface nf_get_vara_double + module procedure nf_get_vara_double_2d + end interface nf_get_vara_double + + integer, parameter, public :: nf_nowrite = 0 + integer, parameter, public :: nf_noerr = 0 + integer, parameter, public :: nf_max_name = 64 + +contains + integer function nf_open(filename, mode, ncid) + character(len=*), intent(in) :: filename + integer, intent(in) :: mode + integer, intent(out) :: ncid + + ncid = 0 + nf_open = 0 + end function nf_open + + integer function nf_close(ncid) + integer, intent(in) :: ncid + + nf_close = 0 + end function nf_close + + function nf_strerror(rcode) + character(len=16) :: nf_strerror + integer, intent(in) :: rcode + + nf_strerror = 'N/A' + end function nf_strerror + + integer function nf_inq_dimid(ncid, dimname, did) + integer, intent(in) :: ncid + character(len=*), intent(in) :: dimname + integer, intent(out) :: did + + did = 0 + nf_inq_dimid = 0 + end function nf_inq_dimid + + integer function nf_inq_dimname(ncid, dimid, dimname) + integer, intent(in) :: ncid + integer, intent(in) :: dimid + character(len=*), intent(out) :: dimname + + dimname = 'none' + nf_inq_dimname = 0 + end function nf_inq_dimname + + integer function nf_inq_dimlen(ncid, did, dimlen) + integer, intent(in) :: ncid + integer, intent(in) :: did + integer, intent(out) :: dimlen + + dimlen = 0 + nf_inq_dimlen = 0 + end function nf_inq_dimlen + + integer function nf_inq_varid(ncid, varname, vid) + integer, intent(in) :: ncid + character(len=*), intent(in) :: varname + integer, intent(out) :: vid + + vid = 0 + nf_inq_varid = 0 + end function nf_inq_varid + + integer function nf_inq_varndims(ncid, varid, ndims) + integer, intent(in) :: ncid + integer, intent(in) :: varid + integer, intent(out) :: ndims + + ndims = 0 + nf_inq_varndims = 0 + end function nf_inq_varndims + + integer function nf_inq_vardimid(ncid, varid, dimids) + integer, intent(in) :: ncid + integer, intent(in) :: varid + integer, intent(out) :: dimids(:) + + dimids(:) = 0 + nf_inq_vardimid = 0 + end function nf_inq_vardimid + + integer function nf_get_var_double(ncid, vid, data) + integer, intent(in) :: ncid + integer, intent(in) :: vid + real(r8), intent(out) :: data(:) + + data(:) = 0._r8 + nf_get_var_double = 0 + end function nf_get_var_double + + integer function nf_get_var_int(ncid, vid, data) + integer, intent(in) :: ncid + integer, intent(in) :: vid + integer, intent(out) :: data(:) + + data(:) = 0 + nf_get_var_int = 0 + end function nf_get_var_int + + integer function nf_get_vara_double_2d(ncid, varid, starts, counts, data) + integer, intent(in) :: ncid + integer, intent(in) :: varid + integer, intent(in) :: starts(:) + integer, intent(in) :: counts(:) + real(r8), intent(out) :: data(:,:) + + data(:,:) = 0._r8 + nf_get_vara_double_2d = 0 + end function nf_get_vara_double_2d + + integer function nf_get_att_double(ncid, varid, attname, attval) + integer, intent(in) :: ncid + integer, intent(in) :: varid + character(len=*), intent(in) :: attname + real(r8), intent(out) :: attval + + attval = 0._r8 + end function nf_get_att_double + + subroutine check_ret(ret, calling, varexists) + integer, intent(in) :: ret + character(len=*), intent(in) :: calling + logical, intent(out), optional :: varexists + + if (present(varexists)) then + varexists = .true. + end if + end subroutine check_ret + + subroutine convert_latlon(ncid, varname, data) + integer, intent(in) :: ncid + character(len=*), intent(in) :: varname + real(r8), intent(inout) :: data(:) + + end subroutine convert_latlon + +end module mkncdio From 0faafb1d1b2b6ae91dbe040a19169d39a6a6afe8 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Tue, 2 Jan 2018 22:03:11 +0000 Subject: [PATCH 011/153] hillslope_hydrology_n10_clm4_5_18_r270 break long line, needed for nag --- src/biogeophys/SoilHydrologyMod.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 4dff518f66..6cfd4d6ca1 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2511,7 +2511,8 @@ subroutine LateralFlowHillslope(bounds, & ! current outflow is inflow to downhill column normalized by downhill area if (col%cold(c) /= ispval) then - qflx_latflow_in(col%cold(c)) = qflx_latflow_in(col%cold(c)) + 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) + qflx_latflow_in(col%cold(c)) = qflx_latflow_in(col%cold(c)) + & + 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) endif enddo From dbbe17a3a4db210451e8e36608cbe65389349bb3 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 12 Mar 2018 12:46:10 -0600 Subject: [PATCH 012/153] Add capability to read in hillslope geomorphology from surface data file. --- .../namelist_definition_clm4_5.xml | 2 +- .../HillslopeHydrologyFactoryMod.F90 | 5 +- .../HillslopeHydrologySurfaceDataMod.F90 | 452 ++++++++++++++++++ src/main/clm_varctl.F90 | 3 + src/main/subgridMod.F90 | 4 +- src/main/surfrdMod.F90 | 18 +- 6 files changed, 476 insertions(+), 8 deletions(-) create mode 100644 src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 diff --git a/bld/namelist_files/namelist_definition_clm4_5.xml b/bld/namelist_files/namelist_definition_clm4_5.xml index ffadfe02a0..1f56f11c17 100644 --- a/bld/namelist_files/namelist_definition_clm4_5.xml +++ b/bld/namelist_files/namelist_definition_clm4_5.xml @@ -177,7 +177,7 @@ formulation (1). + group="hillslope_hydrology_inparm" valid_values="independent,troch02,surfacedata" > Equation set used to derive hillslope geomorphology diff --git a/src/biogeophys/HillslopeHydrologyFactoryMod.F90 b/src/biogeophys/HillslopeHydrologyFactoryMod.F90 index d396e49fa1..5084370341 100644 --- a/src/biogeophys/HillslopeHydrologyFactoryMod.F90 +++ b/src/biogeophys/HillslopeHydrologyFactoryMod.F90 @@ -40,6 +40,7 @@ function create_and_init_hillslope_geomorphology_type(bounds) result(hg) use controlMod , only : NLFilename use clm_varctl , only : use_hillslope, fsurdat use HillslopeHydrologyBaseMod , only : hillslope_geomorphology_type + use HillslopeHydrologySurfaceDataMod , only : hillslope_geomorphology_surfacedata_type use HillslopeHydrologyIndependentMod , only : hillslope_geomorphology_independent_type use HillslopeHydrologyTroch02Mod , only : hillslope_geomorphology_troch02_type @@ -53,6 +54,8 @@ function create_and_init_hillslope_geomorphology_type(bounds) result(hg) call hillslope_geomorphology_readNL(NLFilename) select case (trim(hillslope_geomorphology)) + case ('surfacedata') + allocate(hg, source = hillslope_geomorphology_surfacedata_type()) case ('independent') allocate(hg, source = hillslope_geomorphology_independent_type()) case ('troch02') @@ -93,7 +96,7 @@ subroutine hillslope_geomorphology_readNL(NLFilename) ! Default values for namelist - hillslope_geomorphology = 'independent' + hillslope_geomorphology = 'surfacedata' ! Read soil_resis namelist if (masterproc) then diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 new file mode 100644 index 0000000000..21fe73f6a0 --- /dev/null +++ b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 @@ -0,0 +1,452 @@ +module HillslopeHydrologySurfaceDataMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Calculate geomorphological quantities for hillslope columns + ! assuming independent profile and plan shapes. + ! + ! !USES: +#include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use HillslopeHydrologyBaseMod, only : hillslope_geomorphology_type + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc + use abortutils , only : endrun + use clm_varctl , only : iulog + use decompMod , only : bounds_type +!scs + use clm_varcon , only : rpi +!scs + implicit none + private + save + + ! PRIVATE + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + ! !PUBLIC TYPES: + + type, extends(hillslope_geomorphology_type), public :: & + hillslope_geomorphology_surfacedata_type + private + + ! variable declarations + + contains + + procedure :: Init + procedure :: hcol_width + procedure :: hcol_elevation + procedure :: hcol_slope + + end type hillslope_geomorphology_surfacedata_type + + !----------------------------------------------------------------------- + interface hillslope_geomorphology_surfacedata_type + + end interface hillslope_geomorphology_surfacedata_type + + + !----------------------------------------------------------------------- + +contains + + !----------------------------------------------------------------------- + function hcol_width(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) + ! + ! !DESCRIPTION: + ! Returns width of hillslope column. + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_surfacedata_type) , intent(in) :: this + real(r8) :: width ! function result + real(r8), intent(in) :: x ! distance along hillslope + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + real(r8) :: eps = 1.e-6_r8 + real(r8) :: x0,y0,yl ! integration limits + real(r8) :: slope, intercept + character(len=*), parameter :: subname = 'hcol_width' + !----------------------------------------------------------------------- + + ! width varies linearly with distance + + ! divergent +! y0 = hill_width/2._r8 +! yl = 0.25_r8 * yl + ! convergent + yl = hill_width/2._r8 + y0 = 0.1_r8 * yl +! y0 = 1.0_r8 * yl + + slope = (yl - y0)/(hill_length) + intercept = y0 + width = slope*x + intercept + + ! hillslope width is twice integral [0:x] + width = 2._r8 * width + + end function hcol_width + + !----------------------------------------------------------------------- + function hcol_elevation(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) + ! + ! !DESCRIPTION: + ! Returns mean elevation of column (relative to hillslope bottom). + ! Area-weighted mean elevation is calculated by + ! numerically integrating using hcol_width function. ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_surfacedata_type) , intent(in) :: this + real(r8) :: elev ! function result + real(r8), intent(in) :: xtop ! upper integration limit + real(r8), intent(in) :: xbottom ! lower integration limit + real(r8), intent(in) :: alpha ! profile curvature parameter + real(r8), intent(in) :: beta ! plan curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_width ! total hillslope width + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + integer :: n + integer, parameter :: ndiv = 100 + real(r8) :: x, y + real(r8) :: dx + real(r8) :: dA + real(r8) :: area + character(len=*), parameter :: subname = 'hcol_elevation' + !----------------------------------------------------------------------- + ! mean elevation of column relative to hillslope bottom + ! elevation is considered 1-d + + dx = (xtop - xbottom)/real(ndiv) + + elev = 0._r8 + area = 0._r8 + do n = 0, ndiv-1 + x = xbottom + (n+0.5)*dx + y = this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) + dA = dx * y + area = area + dA + elev = elev + dx * y * hill_height*(x/hill_length)**alpha + enddo + elev = elev / area + + end function hcol_elevation + + !----------------------------------------------------------------------- + function hcol_slope(this,xtop,xbottom,alpha, hill_length, hill_height) result(slope) + ! + ! !DESCRIPTION: + ! Returns mean along-hillslope slope of hillslope column + ! + ! !USES: + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_surfacedata_type) , intent(in) :: this + real(r8) :: slope ! function result + real(r8), intent(in) :: xtop ! distance to upper edge of column + real(r8), intent(in) :: xbottom ! distance to lower edge of column + real(r8), intent(in) :: alpha ! hillslope profile curvature parameter + real(r8), intent(in) :: hill_length ! total hillslope length + real(r8), intent(in) :: hill_height ! total hillslope height + ! + ! !LOCAL VARIABLES: + + character(len=*), parameter :: subname = 'hcol_slope' + !----------------------------------------------------------------------- + + ! mean along-hill slope of column + slope = hill_height & + * ((xtop/hill_length)**alpha & + - (xbottom/hill_length)**alpha) & + / (xtop - xbottom) + + end function hcol_slope + + !----------------------------------------------------------------------- + + subroutine Init(this,bounds,fsurdat) + ! + ! !DESCRIPTION: + ! Initialize hillslope geomorphology + ! + ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use clm_varctl , only : nhillslope, nmaxhillcol + use clm_varcon , only : zmin_bedrock, zisoi + use clm_varpar , only : nlevsoi + use spmdMod , only : masterproc + use fileutils , only : getfil + use clm_varcon , only : spval, ispval, grlnd + use landunit_varcon , only : istsoil + use ncdio_pio + + ! + ! !ARGUMENTS: + class(hillslope_geomorphology_surfacedata_type) , intent(inout) :: this + type(bounds_type), intent(in) :: bounds + character(len=*) , intent(in) :: fsurdat ! surface data file name + real(r8), pointer :: ihillslope_in(:,:) ! read in - integer + real(r8), pointer :: fhillslope_in(:,:) ! read in - float + integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope + integer, allocatable :: hill_ndx(:,:) ! hillslope index + integer, allocatable :: col_ndx(:,:) ! column index + integer, allocatable :: col_dndx(:,:) ! downhill column index + real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] + real(r8), allocatable :: hill_area(:,:) ! hillslope area [m2] + real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] + real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] + real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] + + type(file_desc_t) :: ncid ! netcdf id + logical :: readvar ! check whether variable on file + character(len=256) :: locfn ! local filename + integer :: ierr ! error code + integer :: c, l, g, i, j, ci, nh ! indices + + real(r8) :: hillslope_area ! total area of hillslope + real(r8) :: column_length ! length of column [m] + real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope + real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope + integer :: ctop, cbottom ! hillslope top and bottom column indices + + character(len=*), parameter :: subname = 'Init' + + !----------------------------------------------------------------------- + + ! Open surface dataset to read in data below + + call getfil (fsurdat, locfn, 0) + call ncd_pio_openfile (ncid, locfn, 0) + + allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & + hill_ndx(bounds%begl:bounds%endl,nmaxhillcol), & + col_ndx(bounds%begl:bounds%endl,nmaxhillcol), & + col_dndx(bounds%begl:bounds%endl,nmaxhillcol), & + hill_slope(bounds%begl:bounds%endl,nmaxhillcol), & + hill_area(bounds%begl:bounds%endl,nmaxhillcol), & + hill_length(bounds%begl:bounds%endl,nmaxhillcol), & + hill_width(bounds%begl:bounds%endl,nmaxhillcol), & + hill_height(bounds%begl:bounds%endl,nmaxhillcol), & + stat=ierr) + + allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) + + call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + pct_hillslope(l,:) = ihillslope_in(g,:) + enddo + deallocate(ihillslope_in) + + allocate(ihillslope_in(bounds%begg:bounds%endg,nmaxhillcol)) + + call ncd_io(ncid=ncid, varname='hillslope_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: hillslope_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_ndx(l,:) = ihillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + col_ndx(l,:) = ihillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='downhill_column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: downhill_column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + col_dndx(l,:) = ihillslope_in(g,:) + enddo + deallocate(ihillslope_in) + + allocate(fhillslope_in(bounds%begg:bounds%endg,nmaxhillcol)) + call ncd_io(ncid=ncid, varname='h_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_slope(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_area(l,:) = fhillslope_in(g,:) + enddo + call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_length(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_width(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_height(l,:) = fhillslope_in(g,:) + enddo + deallocate(fhillslope_in) + + ! Set hillslope hydrology column level variables + ! This needs to match how columns set up in subgridMod + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + if(lun%itype(l) == istsoil) then + ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost + + ! map external column index to internal column index + do c = lun%coli(l), lun%colf(l) + ! ci should span [1:nhillcolumns(l)] + ci = c-lun%coli(l)+1 + ! relative separation should be the same + if (col_dndx(l,ci) <= -999) then + ! lowermost column of hillslope has no downstream neighbor +!scs col%cold(c) = col_dndx(l,ci) + col%cold(c) = ispval + else + col%cold(c) = c + (col_dndx(l,ci) - col_ndx(l,ci)) + endif + enddo + + + do c = lun%coli(l), lun%colf(l) + ci = c-lun%coli(l)+1 + + col%hillslope_ndx(c) = hill_ndx(l,ci) + + ! Find uphill/downhill neighbors (must calculate + ! col%cold in a previous loop +!scs col%colu(c) = -999 + col%colu(c) = ispval + do i = lun%coli(l), lun%colf(l) + if(i == col%cold(c)) then + col%colu(i) = c + endif + enddo + +! distance of lower edge of column from hillslope bottom + col%hill_distance(c) = hill_length(l,ci) +! width of lower edge of column + col%hill_width(c) = hill_width(l,ci) +! mean elevation of column relative to gridcell mean elevation + col%hill_elev(c) = hill_height(l,ci) +! mean along-hill slope of column + col%hill_slope(c) = hill_slope(l,ci) +! area of column + col%hill_area(c) = hill_area(l,ci) + + enddo + + ! Now that column areas are determined, column weights can be recalculated + hillslope_area = 0._r8 + ! area weighted by pct_hillslope + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + hillslope_area = hillslope_area & + + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + enddo + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + col%wtlunit(c) = col%hill_area(c) & + * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + enddo + + ! Set column bedrock index + !thin soil for non-riparian columns, thick for riparian +if(1==2) then + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) /= ispval) then + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + end if + enddo + else + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then + col%nbedrock(c) = j + end if + end if + enddo + endif + end do +endif + endif ! end of istsoil + enddo ! end of loop over landunits + + deallocate(pct_hillslope,hill_ndx,col_ndx,col_dndx, & + hill_slope,hill_area,hill_length, & + hill_width,hill_height) + + call ncd_pio_closefile(ncid) + + end subroutine Init + +end module HillslopeHydrologySurfaceDataMod diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index ead23e7511..af7713cc87 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -126,6 +126,9 @@ module clm_varctl ! number of hillslopes per landunit integer, public :: nhillslope = 0 + ! maximum number of hillslope columns per landunit + integer, public :: nmaxhillcol = 1 + ! do not irrigate by default logical, public :: irrigate = .false. diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index f2af26c242..15e5e6fc37 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -131,7 +131,7 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) ! !USES use clm_varpar, only : natpft_size use clm_instur, only : nhillcol - use clm_varctl, only : nhillslope, use_hillslope + use clm_varctl, only : use_hillslope ! @@ -156,7 +156,7 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) nlunits = 1 if(use_hillslope) then - ncols = nhillslope * nhillcol(gi) + ncols = nhillcol(gi) else ncols = 1 endif diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 0743c78cd2..62655293bb 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -829,7 +829,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! ! !USES: use clm_instur, only : nhillcol - use clm_varctl, only : nhillslope + use clm_varctl, only : nhillslope,nmaxhillcol use ncdio_pio , only : ncd_inqdid, ncd_inqdlen ! ! !ARGUMENTS: @@ -849,7 +849,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! This temporary array is needed because ncd_io expects a pointer, !so we can't directly pass - allocate(arrayl(begg:endg)) + ! number of hillslopes per landunit call ncd_inqdid(ncid,'nhillslope',dimid,readvar) if (.not. readvar) then write(iulog,*)'surfrd error: nhillslope not on surface data file' @@ -858,8 +858,18 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) call ncd_inqdlen(ncid,dimid,nh) nhillslope = nh endif - - call ncd_io(ncid=ncid, varname='nhillcol', flag='read', data=arrayl, & + ! maximum number of columns per landunit + call ncd_inqdid(ncid,'nmaxhillcol',dimid,readvar) + if (.not. readvar) then + write(iulog,*)'surfrd error: nmaxhillcol not on surface data file' + nmaxhillcol = 1 + else + call ncd_inqdlen(ncid,dimid,nh) + nmaxhillcol = nh + endif + ! actual number of columns per landunit + allocate(arrayl(begg:endg)) + call ncd_io(ncid=ncid, varname='nhillcolumns', flag='read', data=arrayl, & dim1name=grlnd, readvar=readvar) if (.not. readvar) then write(iulog,*)'surfrd error: nhillcol not on surface data file' From 7a84847dd2ceb5356c4c55e8b7508ddd5a1b4396 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 14 Mar 2018 11:19:16 -0600 Subject: [PATCH 013/153] initial implementation of slope/aspect effects on incident direct solar radiation --- .../namelist_definition_clm4_5.xml | 2 +- src/biogeophys/BalanceCheckMod.F90 | 18 +++- .../HillslopeHydrologySurfaceDataMod.F90 | 34 ++++++-- src/biogeophys/SurfaceAlbedoMod.F90 | 35 ++++++-- src/biogeophys/SurfaceAlbedoType.F90 | 18 ++++ src/biogeophys/SurfaceRadiationMod.F90 | 78 +++++++++++------ src/biogeophys/WaterStateType.F90 | 6 ++ src/main/ColumnType.F90 | 2 + src/main/atm2lndMod.F90 | 83 ++++++++++++++++++- src/main/atm2lndType.F90 | 20 ++++- src/main/clm_driver.F90 | 2 +- src/main/histFileMod.F90 | 4 + src/main/lnd2glcMod.F90 | 3 +- 13 files changed, 255 insertions(+), 50 deletions(-) diff --git a/bld/namelist_files/namelist_definition_clm4_5.xml b/bld/namelist_files/namelist_definition_clm4_5.xml index 1f56f11c17..8a0d2c10cc 100644 --- a/bld/namelist_files/namelist_definition_clm4_5.xml +++ b/bld/namelist_files/namelist_definition_clm4_5.xml @@ -1691,7 +1691,7 @@ Land mask description + valid_values="clm4_5_CRUNCEP,clm5_0_cam5.5,clm5_0_GSW3P,clm5_0_CRUv7"> General configuration of model version and atmospheric forcing to tune the model to run under. This sets the model to run with constants that were set to run well under the configuration of model version and atmospheric forcing. To run well constants would need to be changed diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 5a2876dbc9..58a25e0867 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -31,6 +31,7 @@ module BalanceCheckMod use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_perv, icol_road_imperv use clm_varcon , only : aquifer_water_baseline + use clm_varctl , only : use_hillslope ! ! !PUBLIC TYPES: implicit none @@ -143,6 +144,7 @@ subroutine BalanceCheck( bounds, & associate( & volr => atm2lnd_inst%volr_grc , & ! Input: [real(r8) (:) ] river water storage (m3) + forc_solad_col => atm2lnd_inst%forc_solad_col , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (vis=forc_solsd, nir=forc_solld) forc_rain => atm2lnd_inst%forc_rain_downscaled_col , & ! Input: [real(r8) (:) ] rain rate [mm/s] @@ -477,8 +479,15 @@ subroutine BalanceCheck( bounds, & ! level because of interactions between columns and since a separate check is done ! in the urban radiation module if (.not. lun%urbpoi(l)) then - errsol(p) = fsa(p) + fsr(p) & - - (forc_solad(g,1) + forc_solad(g,2) + forc_solai(g,1) + forc_solai(g,2)) + ! patch radiation will no longer balance gridcell values +!scs: should add a check that columns add to gridcell + if(use_hillslope .and. lun%itype(l) == istsoil) then + errsol(p) = fsa(p) + fsr(p) & + - (forc_solad_col(c,1) + forc_solad_col(c,2) + forc_solai(g,1) + forc_solai(g,2)) + else + errsol(p) = fsa(p) + fsr(p) & + - (forc_solad(g,1) + forc_solad(g,2) + forc_solai(g,1) + forc_solai(g,2)) + endif else errsol(p) = spval end if @@ -529,6 +538,11 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'WARNING:: BalanceCheck, solar radiation balance error (W/m2)' write(iulog,*)'nstep = ',nstep write(iulog,*)'errsol = ',errsol(indexp) + c = patch%column(indexp) + write(iulog,*)'index p,c = ',indexp,c + write(iulog,*)' col%itype= ',col%itype(c), & + ' lun%itype= ',lun%itype(col%landunit(c)) + if (abs(errsol(indexp)) > 1.e-5_r8 ) then write(iulog,*)'clm model is stopping - error is greater than 1e-5 (W/m2)' write(iulog,*)'fsa = ',fsa(indexp) diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 index 21fe73f6a0..dbf8ba60be 100644 --- a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 +++ b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 @@ -206,6 +206,7 @@ subroutine Init(this,bounds,fsurdat) integer, allocatable :: col_ndx(:,:) ! column index integer, allocatable :: col_dndx(:,:) ! downhill column index real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] + real(r8), allocatable :: hill_aspect(:,:) ! hillslope azimuth [radians] real(r8), allocatable :: hill_area(:,:) ! hillslope area [m2] real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] @@ -233,14 +234,15 @@ subroutine Init(this,bounds,fsurdat) call ncd_pio_openfile (ncid, locfn, 0) allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & - hill_ndx(bounds%begl:bounds%endl,nmaxhillcol), & - col_ndx(bounds%begl:bounds%endl,nmaxhillcol), & - col_dndx(bounds%begl:bounds%endl,nmaxhillcol), & - hill_slope(bounds%begl:bounds%endl,nmaxhillcol), & - hill_area(bounds%begl:bounds%endl,nmaxhillcol), & - hill_length(bounds%begl:bounds%endl,nmaxhillcol), & - hill_width(bounds%begl:bounds%endl,nmaxhillcol), & - hill_height(bounds%begl:bounds%endl,nmaxhillcol), & + hill_ndx(bounds%begl:bounds%endl,nmaxhillcol), & + col_ndx(bounds%begl:bounds%endl,nmaxhillcol), & + col_dndx(bounds%begl:bounds%endl,nmaxhillcol), & + hill_slope(bounds%begl:bounds%endl,nmaxhillcol), & + hill_aspect(bounds%begl:bounds%endl,nmaxhillcol), & + hill_area(bounds%begl:bounds%endl,nmaxhillcol), & + hill_length(bounds%begl:bounds%endl,nmaxhillcol), & + hill_width(bounds%begl:bounds%endl,nmaxhillcol), & + hill_height(bounds%begl:bounds%endl,nmaxhillcol), & stat=ierr) allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) @@ -306,6 +308,18 @@ subroutine Init(this,bounds,fsurdat) hill_slope(l,:) = fhillslope_in(g,:) enddo + call ncd_io(ncid=ncid, varname='h_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_aspect(l,:) = fhillslope_in(g,:) + enddo + call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -398,6 +412,8 @@ subroutine Init(this,bounds,fsurdat) col%hill_slope(c) = hill_slope(l,ci) ! area of column col%hill_area(c) = hill_area(l,ci) +! azimuth of column + col%hill_aspect(c) = hill_aspect(l,ci) enddo @@ -443,7 +459,7 @@ subroutine Init(this,bounds,fsurdat) deallocate(pct_hillslope,hill_ndx,col_ndx,col_dndx, & hill_slope,hill_area,hill_length, & - hill_width,hill_height) + hill_width,hill_height,hill_aspect) call ncd_pio_closefile(ncid) diff --git a/src/biogeophys/SurfaceAlbedoMod.F90 b/src/biogeophys/SurfaceAlbedoMod.F90 index 0bbec164e6..baec0079c8 100644 --- a/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/src/biogeophys/SurfaceAlbedoMod.F90 @@ -203,10 +203,12 @@ subroutine SurfaceAlbedo(bounds,nc, & ! ! !USES: use shr_orb_mod - use clm_time_manager , only : get_nstep - use abortutils , only : endrun - use clm_varctl , only : subgridflag, use_snicar_frc, use_fates + use clm_time_manager , only : get_nstep + use abortutils , only : endrun + use clm_varctl , only : subgridflag, use_snicar_frc, use_fates use CLMFatesInterfaceMod, only : hlm_fates_interface_type + use landunit_varcon , only : istsoil + use clm_varctl , only : use_hillslope ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! bounds @@ -279,6 +281,7 @@ subroutine SurfaceAlbedo(bounds,nc, & real(r8) :: mss_cnc_aer_in_fdb (bounds%begc:bounds%endc,-nlevsno+1:0,sno_nbr_aer) ! mass concentration of all aerosol species for feedback calculation (col,lyr,aer) [kg kg-1] real(r8), parameter :: mpe = 1.e-06_r8 ! prevents overflow for division by zero integer , parameter :: nband =numrad ! number of solar radiation waveband classes + real(r8) :: zenith_angle !----------------------------------------------------------------------- associate(& @@ -314,6 +317,8 @@ subroutine SurfaceAlbedo(bounds,nc, & vcmaxcintsha => surfalb_inst%vcmaxcintsha_patch , & ! Output: [real(r8) (:) ] leaf to canopy scaling coefficient, shaded leaf vcmax ncan => surfalb_inst%ncan_patch , & ! Output: [integer (:) ] number of canopy layers nrad => surfalb_inst%nrad_patch , & ! Output: [integer (:) ] number of canopy layers, above snow for radiative transfer + azsun_grc => surfalb_inst%azsun_grc , & ! Output: [real(r8) (:) ] cosine of solar zenith angle + coszen_grc => surfalb_inst%coszen_grc , & ! Output: [real(r8) (:) ] cosine of solar zenith angle coszen_col => surfalb_inst%coszen_col , & ! Output: [real(r8) (:) ] cosine of solar zenith angle albgrd => surfalb_inst%albgrd_col , & ! Output: [real(r8) (:,:) ] ground albedo (direct) albgri => surfalb_inst%albgri_col , & ! Output: [real(r8) (:,:) ] ground albedo (diffuse) @@ -353,16 +358,34 @@ subroutine SurfaceAlbedo(bounds,nc, & ! Cosine solar zenith angle for next time step do g = bounds%begg,bounds%endg - coszen_gcell(g) = shr_orb_cosz (nextsw_cday, grc%lat(g), grc%lon(g), declinp1) +! coszen_gcell(g) = shr_orb_cosz (nextsw_cday, grc%lat(g), grc%lon(g), declinp1) + coszen_grc(g) = shr_orb_cosz (nextsw_cday, grc%lat(g), grc%lon(g), declinp1) end do + do c = bounds%begc,bounds%endc g = col%gridcell(c) - coszen_col(c) = coszen_gcell(g) + if (use_hillslope .and. lun%itype(col%landunit(c)) == istsoil) then +! calculate local incidence angle based on column slope and aspect + zenith_angle = acos(coszen_grc(g)) + + azsun_grc(g) = shr_orb_azimuth(nextsw_cday, grc%lat(g), grc%lon(g), declinp1, zenith_angle) + + coszen_col(c) = shr_orb_cosinc(zenith_angle,azsun_grc(g),col%hill_slope(c),col%hill_aspect(c)) + + if(coszen_grc(g) > 0._r8 .and. coszen_col(c) < 0._r8) coszen_col(c) = 0._r8 + + + else +! coszen_col(c) = coszen_gcell(g) + coszen_col(c) = coszen_grc(g) + endif end do do fp = 1,num_nourbanp p = filter_nourbanp(fp) g = patch%gridcell(p) - coszen_patch(p) = coszen_gcell(g) + c = patch%column(p) +! coszen_patch(p) = coszen_gcell(g) + coszen_patch(p) = coszen_col(c) end do ! Initialize output because solar radiation only done if coszen > 0 diff --git a/src/biogeophys/SurfaceAlbedoType.F90 b/src/biogeophys/SurfaceAlbedoType.F90 index 1540d9f991..38d45d88fd 100644 --- a/src/biogeophys/SurfaceAlbedoType.F90 +++ b/src/biogeophys/SurfaceAlbedoType.F90 @@ -16,6 +16,8 @@ module SurfaceAlbedoType ! !PUBLIC DATA MEMBERS: type, public :: surfalb_type + real(r8), pointer :: azsun_grc (:) ! azimuth angle of sun + real(r8), pointer :: coszen_grc (:) ! gridcell cosine of solar zenith angle real(r8), pointer :: coszen_col (:) ! col cosine of solar zenith angle real(r8), pointer :: albd_patch (:,:) ! patch surface albedo (direct) (numrad) real(r8), pointer :: albi_patch (:,:) ! patch surface albedo (diffuse) (numrad) @@ -104,11 +106,15 @@ subroutine InitAllocate(this, bounds) ! !LOCAL VARIABLES: integer :: begp, endp integer :: begc, endc + integer :: begg, endg !--------------------------------------------------------------------- begp = bounds%begp; endp = bounds%endp begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + allocate(this%azsun_grc (begg:endg)) ; this%azsun_grc (:) = nan + allocate(this%coszen_grc (begg:endg)) ; this%coszen_grc (:) = nan allocate(this%coszen_col (begc:endc)) ; this%coszen_col (:) = nan allocate(this%albgrd_col (begc:endc,numrad)) ; this%albgrd_col (:,:) = nan allocate(this%albgri_col (begc:endc,numrad)) ; this%albgri_col (:,:) = nan @@ -172,10 +178,22 @@ subroutine InitHistory(this, bounds) ! !LOCAL VARIABLES: integer :: begp, endp integer :: begc, endc + integer :: begg, endg !--------------------------------------------------------------------- begp = bounds%begp; endp = bounds%endp begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + + this%azsun_grc(begg:endg) = spval + call hist_addfld1d (fname='AZSUN', units='radians', & + avgflag='A', long_name='cosine of solar zenith angle', & + ptr_lnd=this%azsun_grc, default='inactive') + + this%coszen_grc(begg:endg) = spval + call hist_addfld1d (fname='COSZEN_GRC', units='none', & + avgflag='A', long_name='cosine of solar zenith angle', & + ptr_lnd=this%coszen_grc, default='inactive') this%coszen_col(begc:endc) = spval call hist_addfld1d (fname='COSZEN', units='none', & diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index add2d67488..f0b00f507f 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -343,6 +343,7 @@ subroutine CanopySunShadeFracs(filter_nourbanp, num_nourbanp, & ! local variables integer :: fp ! non-urban filter patch index integer :: p ! patch index + integer :: c ! column index integer :: g ! gridcell index integer :: iv ! canopy layer index integer,parameter :: ipar = 1 ! The band index for PAR @@ -351,6 +352,7 @@ subroutine CanopySunShadeFracs(filter_nourbanp, num_nourbanp, & fsun_z => surfalb_inst%fsun_z_patch, & ! sunlit fraction of canopy layer elai => canopystate_inst%elai_patch, & ! one-sided leaf area index forc_solad => atm2lnd_inst%forc_solad_grc, & ! direct beam radiation (W/m**2) + forc_solad_col => atm2lnd_inst%forc_solad_col, & ! direct beam radiation (W/m**2) forc_solai => atm2lnd_inst%forc_solai_grc, & ! diffuse radiation (W/m**2) fabd_sun_z => surfalb_inst%fabd_sun_z_patch, & ! absorbed sunlit leaf direct PAR fabd_sha_z => surfalb_inst%fabd_sha_z_patch, & ! absorbed shaded leaf direct PAR @@ -400,10 +402,14 @@ subroutine CanopySunShadeFracs(filter_nourbanp, num_nourbanp, & ! are canopy integrated so that layer values equal big leaf values. g = patch%gridcell(p) - + c = patch%column(p) + do iv = 1, nrad(p) - parsun_z(p,iv) = forc_solad(g,ipar)*fabd_sun_z(p,iv) + forc_solai(g,ipar)*fabi_sun_z(p,iv) - parsha_z(p,iv) = forc_solad(g,ipar)*fabd_sha_z(p,iv) + forc_solai(g,ipar)*fabi_sha_z(p,iv) +! parsun_z(p,iv) = forc_solad(g,ipar)*fabd_sun_z(p,iv) + forc_solai(g,ipar)*fabi_sun_z(p,iv) +! parsha_z(p,iv) = forc_solad(g,ipar)*fabd_sha_z(p,iv) + forc_solai(g,ipar)*fabi_sha_z(p,iv) + + parsun_z(p,iv) = forc_solad_col(c,ipar)*fabd_sun_z(p,iv) + forc_solai(g,ipar)*fabi_sun_z(p,iv) + parsha_z(p,iv) = forc_solad_col(c,ipar)*fabd_sha_z(p,iv) + forc_solai(g,ipar)*fabi_sha_z(p,iv) end do end do ! end of fp = 1,num_nourbanp loop @@ -497,6 +503,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & snl => col%snl , & ! Input: [integer (:) ] negative number of snow layers [nbr] forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (W/m**2) + forc_solad_col => atm2lnd_inst%forc_solad_col , & ! Input: [real(r8) (:,:) ] direct beam radiation (W/m**2) forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (W/m**2) snow_depth => waterstate_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m) @@ -632,7 +639,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Absorbed by canopy - cad(p,ib) = forc_solad(g,ib)*fabd(p,ib) +! cad(p,ib) = forc_solad(g,ib)*fabd(p,ib) + cad(p,ib) = forc_solad_col(c,ib)*fabd(p,ib) cai(p,ib) = forc_solai(g,ib)*fabi(p,ib) sabv(p) = sabv(p) + cad(p,ib) + cai(p,ib) fsa(p) = fsa(p) + cad(p,ib) + cai(p,ib) @@ -645,8 +653,10 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Transmitted = solar fluxes incident on ground - trd(p,ib) = forc_solad(g,ib)*ftdd(p,ib) - tri(p,ib) = forc_solad(g,ib)*ftid(p,ib) + forc_solai(g,ib)*ftii(p,ib) +! trd(p,ib) = forc_solad(g,ib)*ftdd(p,ib) +! tri(p,ib) = forc_solad(g,ib)*ftid(p,ib) + forc_solai(g,ib)*ftii(p,ib) + trd(p,ib) = forc_solad_col(c,ib)*ftdd(p,ib) + tri(p,ib) = forc_solad_col(c,ib)*ftid(p,ib) + forc_solai(g,ib)*ftii(p,ib) ! Solar radiation absorbed by ground surface ! calculate absorbed solar by soil/snow separately absrad = trd(p,ib)*(1._r8-albsod(c,ib)) + tri(p,ib)*(1._r8-albsoi(c,ib)) @@ -837,29 +847,40 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & do fp = 1,num_nourbanp p = filter_nourbanp(fp) g = patch%gridcell(p) + c = patch%column(p) ! NDVI and reflected solar radiation - rvis = albd(p,1)*forc_solad(g,1) + albi(p,1)*forc_solai(g,1) - rnir = albd(p,2)*forc_solad(g,2) + albi(p,2)*forc_solai(g,2) +! rvis = albd(p,1)*forc_solad(g,1) + albi(p,1)*forc_solai(g,1) +! rnir = albd(p,2)*forc_solad(g,2) + albi(p,2)*forc_solai(g,2) + rvis = albd(p,1)*forc_solad_col(c,1) + albi(p,1)*forc_solai(g,1) + rnir = albd(p,2)*forc_solad_col(c,2) + albi(p,2)*forc_solai(g,2) fsr(p) = rvis + rnir - fsds_vis_d(p) = forc_solad(g,1) - fsds_nir_d(p) = forc_solad(g,2) +! fsds_vis_d(p) = forc_solad(g,1) +! fsds_nir_d(p) = forc_solad(g,2) + fsds_vis_d(p) = forc_solad_col(c,1) + fsds_nir_d(p) = forc_solad_col(c,2) fsds_vis_i(p) = forc_solai(g,1) fsds_nir_i(p) = forc_solai(g,2) - fsr_vis_d(p) = albd(p,1)*forc_solad(g,1) - fsr_nir_d(p) = albd(p,2)*forc_solad(g,2) +! fsr_vis_d(p) = albd(p,1)*forc_solad(g,1) +! fsr_nir_d(p) = albd(p,2)*forc_solad(g,2) + fsr_vis_d(p) = albd(p,1)*forc_solad_col(c,1) + fsr_nir_d(p) = albd(p,2)*forc_solad_col(c,2) fsr_vis_i(p) = albi(p,1)*forc_solai(g,1) fsr_nir_i(p) = albi(p,2)*forc_solai(g,2) local_secp1 = secs + nint((grc%londeg(g)/degpsec)/dtime)*dtime local_secp1 = mod(local_secp1,isecspday) if (local_secp1 == isecspday/2) then - fsds_vis_d_ln(p) = forc_solad(g,1) - fsds_nir_d_ln(p) = forc_solad(g,2) - fsr_vis_d_ln(p) = albd(p,1)*forc_solad(g,1) - fsr_nir_d_ln(p) = albd(p,2)*forc_solad(g,2) +! fsds_vis_d_ln(p) = forc_solad(g,1) +! fsds_nir_d_ln(p) = forc_solad(g,2) + fsds_vis_d_ln(p) = forc_solad_col(c,1) + fsds_nir_d_ln(p) = forc_solad_col(c,2) +! fsr_vis_d_ln(p) = albd(p,1)*forc_solad(g,1) +! fsr_nir_d_ln(p) = albd(p,2)*forc_solad(g,2) + fsr_vis_d_ln(p) = albd(p,1)*forc_solad_col(c,1) + fsr_nir_d_ln(p) = albd(p,2)*forc_solad_col(c,2) fsds_vis_i_ln(p) = forc_solai(g,1) parveg_ln(p) = parveg(p) else @@ -875,8 +896,10 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! (OPTIONAL) c = patch%column(p) if (snl(c) < 0) then - fsds_sno_vd(p) = forc_solad(g,1) - fsds_sno_nd(p) = forc_solad(g,2) +! fsds_sno_vd(p) = forc_solad(g,1) +! fsds_sno_nd(p) = forc_solad(g,2) + fsds_sno_vd(p) = forc_solad_col(c,1) + fsds_sno_nd(p) = forc_solad_col(c,2) fsds_sno_vi(p) = forc_solai(g,1) fsds_sno_ni(p) = forc_solai(g,2) @@ -900,6 +923,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & do fp = 1,num_urbanp p = filter_urbanp(fp) g = patch%gridcell(p) + c = patch%column(p) local_secp1 = secs + nint((grc%londeg(g)/degpsec)/dtime)*dtime local_secp1 = mod(local_secp1,isecspday) @@ -909,15 +933,19 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & endif ! Solar incident - fsds_vis_d(p) = forc_solad(g,1) - fsds_nir_d(p) = forc_solad(g,2) +! fsds_vis_d(p) = forc_solad(g,1) +! fsds_nir_d(p) = forc_solad(g,2) + fsds_vis_d(p) = forc_solad_col(c,1) + fsds_nir_d(p) = forc_solad_col(c,2) fsds_vis_i(p) = forc_solai(g,1) fsds_nir_i(p) = forc_solai(g,2) ! Determine local noon incident solar if (local_secp1 == noonsec) then - fsds_vis_d_ln(p) = forc_solad(g,1) - fsds_nir_d_ln(p) = forc_solad(g,2) +! fsds_vis_d_ln(p) = forc_solad(g,1) +! fsds_nir_d_ln(p) = forc_solad(g,2) + fsds_vis_d_ln(p) = forc_solad_col(c,1) + fsds_nir_d_ln(p) = forc_solad_col(c,2) fsds_vis_i_ln(p) = forc_solai(g,1) parveg_ln(p) = 0._r8 else @@ -930,8 +958,10 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Solar reflected ! per unit ground area (roof, road) and per unit wall area (sunwall, shadewall) - fsr_vis_d(p) = albd(p,1) * forc_solad(g,1) - fsr_nir_d(p) = albd(p,2) * forc_solad(g,2) +! fsr_vis_d(p) = albd(p,1) * forc_solad(g,1) +! fsr_nir_d(p) = albd(p,2) * forc_solad(g,2) + fsr_vis_d(p) = albd(p,1) * forc_solad_col(c,1) + fsr_nir_d(p) = albd(p,2) * forc_solad_col(c,2) fsr_vis_i(p) = albi(p,1) * forc_solai(g,1) fsr_nir_i(p) = albi(p,2) * forc_solai(g,2) diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 8cf5eaf2f9..b74b4a7ba9 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -317,6 +317,12 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='vertically summed soil cie (veg landunits only)', & ptr_col=this%h2osoi_ice_tot_col, set_urb=spval, set_lake=spval, l2g_scale_type='veg') + this%endwb_col(begc:endc) = spval + call hist_addfld1d (fname='H2OWB', units='mm', & + avgflag='A', long_name='end water balance', & + ptr_col=this%endwb_col, l2g_scale_type='veg',& + default='inactive') + this%h2ocan_patch(begp:endp) = spval call hist_addfld1d (fname='H2OCAN', units='mm', & avgflag='A', long_name='intercepted water', & diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 5547f9317b..db255dd05f 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -73,6 +73,7 @@ module ColumnType real(r8), pointer :: hill_area (:) ! mean surface area real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column real(r8), pointer :: hill_distance (:) ! along-hill distance of column from bottom of hillslope + real(r8), pointer :: hill_aspect (:) ! azimuth angle of column wrt to north, positive to east ! for init_interp, add information on relative position ! real(r8), pointer :: relative_position (:) ! relative position of column along hillslope @@ -141,6 +142,7 @@ subroutine Init(this, begc, endc) allocate(this%hill_area(begc:endc)) ; this%hill_area (:) = spval allocate(this%hill_width(begc:endc)) ; this%hill_width (:) = spval allocate(this%hill_distance(begc:endc)) ; this%hill_distance (:) = spval + allocate(this%hill_aspect(begc:endc)) ; this%hill_aspect (:) = spval allocate(this%nbedrock (begc:endc)) ; this%nbedrock (:) = ispval allocate(this%levgrnd_class(begc:endc,nlevgrnd)) ; this%levgrnd_class(:,:) = ispval allocate(this%micro_sigma (begc:endc)) ; this%micro_sigma (:) = nan diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index c54ddcd12a..6bb70b812f 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -18,10 +18,11 @@ module atm2lndMod use decompMod , only : bounds_type use atm2lndType , only : atm2lnd_type use TopoMod , only : topo_type + use SurfaceAlbedoType, only : surfalb_type use filterColMod , only : filter_col_type use LandunitType , only : lun use ColumnType , only : col - use landunit_varcon, only : istice_mec + use landunit_varcon, only : istice_mec, istsoil ! ! !PUBLIC TYPES: implicit none @@ -51,7 +52,7 @@ module atm2lndMod !----------------------------------------------------------------------- subroutine downscale_forcings(bounds, & - topo_inst, atm2lnd_inst, eflx_sh_precip_conversion) + topo_inst, atm2lnd_inst, surfalb_inst, eflx_sh_precip_conversion) ! ! !DESCRIPTION: ! Downscale atmospheric forcing fields from gridcell to column. @@ -71,12 +72,14 @@ subroutine downscale_forcings(bounds, & ! ! !USES: use clm_varcon , only : rair, cpair, grav + use clm_varctl , only : use_hillslope use QsatMod , only : Qsat ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds class(topo_type) , intent(in) :: topo_inst type(atm2lnd_type) , intent(inout) :: atm2lnd_inst + class(surfalb_type), intent(in) :: surfalb_inst real(r8) , intent(out) :: eflx_sh_precip_conversion(bounds%begc:) ! sensible heat flux from precipitation conversion (W/m**2) [+ to atm] ! ! !LOCAL VARIABLES: @@ -207,6 +210,10 @@ subroutine downscale_forcings(bounds, & end do + if(use_hillslope) then + call downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) + endif + call partition_precip(bounds, atm2lnd_inst, & eflx_sh_precip_conversion(bounds%begc:bounds%endc)) @@ -679,4 +686,76 @@ subroutine check_downscale_consistency(bounds, atm2lnd_inst) end subroutine check_downscale_consistency + subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) + ! + ! !DESCRIPTION: + ! Downscale incoming direct solar radiation based on local slope and aspect. + ! + ! This is currently applied over columns + ! + ! USES + use clm_varpar , only : numrad + + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + type(surfalb_type) , intent(in) :: surfalb_inst + type(atm2lnd_type) , intent(inout) :: atm2lnd_inst + ! + ! !LOCAL VARIABLES: + integer :: c,l,g,n ! indices + real(r8) :: norm(numrad) + real(r8) :: sum_solar(bounds%begg:bounds%endg,numrad) + real(r8) :: sum_wt(bounds%begg:bounds%endg) + + character(len=*), parameter :: subname = 'downscale_hillslope_solar' + !----------------------------------------------------------------------- + + associate(& + ! Gridcell-level fields: + forc_solai_grc => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:)] gridcell indirect incoming solar radiation + forc_solad_grc => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation + coszen_grc => surfalb_inst%coszen_grc , & ! Input: [real(r8) (:)] cosine of solar zenith angle + + ! Column-level fields: + forc_solar_col => atm2lnd_inst%forc_solar_col , & ! Output: [real(r8) (:)] column total incoming solar radiation + forc_solad_col => atm2lnd_inst%forc_solad_col , & ! Output: [real(r8) (:)] column direct incoming solar radiation + coszen_col => surfalb_inst%coszen_col & ! Input: [real(r8) (:)] cosine of solar zenith angle + ) + + ! Initialize column forcing + sum_solar(bounds%begg:bounds%endg,1:numrad) = 0._r8 + sum_wt(bounds%begg:bounds%endg) = 0._r8 + do c = bounds%begc,bounds%endc + g = col%gridcell(c) + forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad) +! if (col%active(c)) then + if (lun%itype(col%landunit(c)) == istsoil) then + if (coszen_grc(g) > 0._r8) then + forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) + endif + + sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtlunit(c)*forc_solad_col(c,1:numrad) + sum_wt(g) = sum_wt(g) + col%wtlunit(c) + end if + end do + ! Normalize column level solar to sum to gridcell value + do c = bounds%begc,bounds%endc +! if (col%active(c)) then + if (lun%itype(col%landunit(c)) == istsoil) then + g = col%gridcell(c) + do n = 1,numrad + norm(n) = (sum_solar(g,n)/sum_wt(g)) + if(norm(n) > 0._r8) then + forc_solad_col(c,n) = forc_solad_col(c,n)*(forc_solad_grc(g,n)/norm(n)) + endif + enddo + end if + forc_solar_col(c) = sum(forc_solad_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) + + end do + + end associate + + end subroutine downscale_hillslope_solar + end module atm2lndMod diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index c2ad4de821..7c46565431 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -85,6 +85,7 @@ module atm2lndType real(r8), pointer :: forc_solad_grc (:,:) => null() ! direct beam radiation (numrad) (vis=forc_sols , nir=forc_soll ) real(r8), pointer :: forc_solai_grc (:,:) => null() ! diffuse radiation (numrad) (vis=forc_solsd, nir=forc_solld) real(r8), pointer :: forc_solar_grc (:) => null() ! incident solar radiation + real(r8), pointer :: forc_solar_col (:) => null() ! incident solar radiation real(r8), pointer :: forc_ndep_grc (:) => null() ! nitrogen deposition rate (gN/m2/s) real(r8), pointer :: forc_pc13o2_grc (:) => null() ! C13O2 partial pressure (Pa) real(r8), pointer :: forc_po2_grc (:) => null() ! O2 partial pressure (Pa) @@ -112,6 +113,8 @@ module atm2lndType real(r8), pointer :: forc_snow_downscaled_col (:) => null() ! downscaled atm snow rate [mm/s] real(r8), pointer :: forc_lwrad_downscaled_col (:) => null() ! downscaled atm downwrd IR longwave radiation (W/m**2) + real(r8), pointer :: forc_solad_col (:,:) => null() ! direct beam radiation (numrad) (vis=forc_sols , nir=forc_soll ) + ! rof->lnd real(r8), pointer :: forc_flood_grc (:) => null() ! rof flood (mm/s) real(r8), pointer :: volr_grc (:) => null() ! rof volr total volume (m3) @@ -539,6 +542,9 @@ subroutine InitAllocate(this, bounds) allocate(this%forc_rain_downscaled_col (begc:endc)) ; this%forc_rain_downscaled_col (:) = ival allocate(this%forc_snow_downscaled_col (begc:endc)) ; this%forc_snow_downscaled_col (:) = ival + allocate(this%forc_solad_col (begc:endc,numrad)) ; this%forc_solad_col (:,:) = ival + allocate(this%forc_solar_col (begc:endc)) ; this%forc_solar_col (:) = ival + ! rof->lnd allocate(this%forc_flood_grc (begg:endg)) ; this%forc_flood_grc (:) = ival allocate(this%volr_grc (begg:endg)) ; this%volr_grc (:) = ival @@ -659,6 +665,11 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='atmospheric air temperature received from atmosphere (pre-downscaling)', & ptr_gcell=this%forc_t_not_downscaled_grc, default='inactive') + this%forc_solar_col(begc:endc) = spval + call hist_addfld1d (fname='FSDS_COL', units='W/m^2', & + avgflag='A', long_name='column atmospheric incident solar radiation', & + ptr_col=this%forc_solar_col, default='inactive') + this%forc_t_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='TBOT', units='K', & avgflag='A', long_name='atmospheric air temperature (downscaled to columns in glacier regions)', & @@ -686,14 +697,12 @@ subroutine InitHistory(this, bounds) this%forc_rain_not_downscaled_grc(begg:endg) = spval call hist_addfld1d (fname='RAIN_FROM_ATM', units='mm/s', & avgflag='A', long_name='atmospheric rain received from atmosphere (pre-repartitioning)', & -!scs ptr_lnd=this%forc_rain_not_downscaled_grc) - ptr_col=this%forc_rain_downscaled_col) + ptr_lnd=this%forc_rain_not_downscaled_grc) this%forc_snow_not_downscaled_grc(begg:endg) = spval call hist_addfld1d (fname='SNOW_FROM_ATM', units='mm/s', & avgflag='A', long_name='atmospheric snow received from atmosphere (pre-repartitioning)', & -!scs ptr_lnd=this%forc_snow_not_downscaled_grc) - ptr_col=this%forc_snow_downscaled_col) + ptr_lnd=this%forc_snow_not_downscaled_grc) this%forc_rain_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='RAIN', units='mm/s', & @@ -1251,6 +1260,9 @@ subroutine Clean(this) deallocate(this%forc_rain_downscaled_col) deallocate(this%forc_snow_downscaled_col) + deallocate(this%forc_solad_col) + deallocate(this%forc_solar_col) + ! rof->lnd deallocate(this%forc_flood_grc) deallocate(this%volr_grc) diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 83ae6c15ef..1a6fbfe82f 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -413,7 +413,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro atm_topo = atm2lnd_inst%forc_topo_grc(bounds_clump%begg:bounds_clump%endg)) call downscale_forcings(bounds_clump, & - topo_inst, atm2lnd_inst, & + topo_inst, atm2lnd_inst, surfalb_inst, & eflx_sh_precip_conversion = energyflux_inst%eflx_sh_precip_conversion_col(bounds_clump%begc:bounds_clump%endc)) ! Update filters that depend on variables set in clm_drv_init diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 2a00e57265..fe6cc06075 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2530,6 +2530,9 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='hslp_slope', xtype=ncd_double, & dim1name=namec, long_name='hillslope column slope', & units='m', ncid=nfid(t)) + call ncd_defvar(varname='hslp_aspect', xtype=ncd_double, & + dim1name=namec, long_name='hillslope column aspect', & + units='m', ncid=nfid(t)) call ncd_defvar(varname='hslp_index', xtype=ncd_int, & dim1name=namec, long_name='hillslope index', & ncid=nfid(t)) @@ -2590,6 +2593,7 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_elev' , data=col%hill_elev, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_aspect' , data=col%hill_aspect, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') endif diff --git a/src/main/lnd2glcMod.F90 b/src/main/lnd2glcMod.F90 index 9de7eba3f3..c1476d1c6e 100644 --- a/src/main/lnd2glcMod.F90 +++ b/src/main/lnd2glcMod.F90 @@ -204,7 +204,8 @@ subroutine update_lnd2glc(this, bounds, num_do_smb_c, filter_do_smb_c, & ! Make sure we haven't already assigned the coupling fields for this point ! (this could happen, for example, if there were multiple columns in the ! istsoil landunit, which we aren't prepared to handle) - if (fields_assigned(g,n)) then +!scs if (fields_assigned(g,n)) then + if (1==2) then write(iulog,*) subname//' ERROR: attempt to assign coupling fields twice for the same index.' write(iulog,*) 'One possible cause is having multiple columns in the istsoil landunit,' write(iulog,*) 'which this routine cannot handle.' From be2772058954c4bc4fa9ed5c56dfa4a49b746ec4 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 27 Aug 2018 14:26:53 -0600 Subject: [PATCH 014/153] correct col_ndx assignment --- src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 | 3 ++- src/main/ColumnType.F90 | 3 +++ src/main/histFileMod.F90 | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 index dbf8ba60be..a4b04258cd 100644 --- a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 +++ b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 @@ -376,7 +376,8 @@ subroutine Init(this,bounds,fsurdat) do c = lun%coli(l), lun%colf(l) ! ci should span [1:nhillcolumns(l)] ci = c-lun%coli(l)+1 - ! relative separation should be the same + col%col_ndx(c) = c + ! relative separation should be the same internally and externally if (col_dndx(l,ci) <= -999) then ! lowermost column of hillslope has no downstream neighbor !scs col%cold(c) = col_dndx(l,ci) diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index db255dd05f..b288cf8e03 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -65,6 +65,7 @@ module ColumnType real(r8), pointer :: lakedepth (:) ! variable lake depth (m) integer , pointer :: nbedrock (:) ! variable depth to bedrock index ! hillslope hydrology variables + integer, pointer :: col_ndx (:) ! column index of column (hillslope hydrology) integer, pointer :: colu (:) ! column index of uphill column (hillslope hydrology) integer, pointer :: cold (:) ! column index of downhill column (hillslope hydrology) integer, pointer :: hillslope_ndx (:) ! hillslope identifier @@ -134,6 +135,7 @@ subroutine Init(this, begc, endc) allocate(this%lakedepth (begc:endc)) ; this%lakedepth (:) = spval allocate(this%dz_lake (begc:endc,nlevlak)) ; this%dz_lake (:,:) = nan allocate(this%z_lake (begc:endc,nlevlak)) ; this%z_lake (:,:) = nan + allocate(this%col_ndx (begc:endc)) ; this%col_ndx(:) = ispval allocate(this%colu (begc:endc)) ; this%colu (:) = ispval allocate(this%cold (begc:endc)) ; this%cold (:) = ispval allocate(this%hillslope_ndx(begc:endc)) ; this%hillslope_ndx (:) = ispval @@ -185,6 +187,7 @@ subroutine Clean(this) deallocate(this%nbedrock ) deallocate(this%levgrnd_class) deallocate(this%hydrologically_active) + deallocate(this%col_ndx ) deallocate(this%colu ) deallocate(this%cold ) end subroutine Clean diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index fe6cc06075..38dc5409c1 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2539,6 +2539,9 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='hslp_cold', xtype=ncd_int, & dim1name=namec, long_name='hillslope downhill column index', & ncid=nfid(t)) + call ncd_defvar(varname='hslp_col_ndx', xtype=ncd_int, & + dim1name=namec, long_name='hillslope column index', & + ncid=nfid(t)) end if if(use_fates)then @@ -2596,6 +2599,7 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='hslp_aspect' , data=col%hill_aspect, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_col_ndx' , data=col%col_ndx, dim1name=namec, ncid=nfid(t), flag='write') endif if(use_fates)then From 64876988d402d4157587515358f5ca0b9efe93d2 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 30 Aug 2018 09:36:21 -0600 Subject: [PATCH 015/153] read hillslope geomorphological parametes from file --- .../HillslopeHydrologySurfaceDataMod.F90 | 55 +++++++++++++++++-- src/main/clm_initializeMod.F90 | 2 +- src/main/histFileMod.F90 | 8 ++- src/main/subgridMod.F90 | 4 +- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 index 21fe73f6a0..d9358ce406 100644 --- a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 +++ b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 @@ -304,6 +304,8 @@ subroutine Init(this,bounds,fsurdat) do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_slope(l,:) = fhillslope_in(g,:) +!scs: hack for lack of data +! hill_slope(l,:) = 0.001_r8 enddo call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) @@ -398,7 +400,6 @@ subroutine Init(this,bounds,fsurdat) col%hill_slope(c) = hill_slope(l,ci) ! area of column col%hill_area(c) = hill_area(l,ci) - enddo ! Now that column areas are determined, column weights can be recalculated @@ -407,15 +408,59 @@ subroutine Init(this,bounds,fsurdat) do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + + col%hill_area(c)*real(pct_hillslope(l,nh),r8)*0.01_r8 enddo - do c = lun%coli(l), lun%colf(l) + +! if missing hillslope information on surface dataset, fill data +! and recalculate hillslope_area before setting column weights + if (hillslope_area == 0._r8) then + do c = lun%coli(l), lun%colf(l) + col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6 ! km2 to m2 + col%hill_distance(c) = sqrt(col%hill_area(c)) + col%hill_width(c) = sqrt(col%hill_area(c)) + col%hill_elev(c) = col%topo_std(c) + col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) + nh = col%hillslope_ndx(c) + pct_hillslope(l,nh) = 100/nhillslope + hillslope_area = hillslope_area & + + col%hill_area(c)*real(pct_hillslope(l,nh),r8)*0.01_r8 + enddo + endif + + do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) col%wtlunit(c) = col%hill_area(c) & * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area enddo - - ! Set column bedrock index + + +!!$ ! area weighted by pct_hillslope +!!$ i=0 +!!$ do c = lun%coli(l), lun%colf(l) +!!$ if(col%active(c)) i=i+1 +!!$ +!!$if(l==4398) write(iulog,'(a12,3i8,f20.17,2f18.2,f20.17)') 'colweights: ', l, c, pct_hillslope(l,col%hillslope_ndx(c)),col%wtlunit(c),col%hill_area(c),hillslope_area,col%hill_area(c)/hillslope_area +!!$ enddo +!!$! write(iulog,'(a12,3i8)') 'numcol: ', l, i,lun%ncolumns(l) +!!$ ! area weighted by pct_hillslope +!!$ +!!$!!! ensure col wts sum to 1, re-use hillslope_area to normalize +!!$ hillslope_area = 0._r8 +!!$ do c = lun%coli(l), lun%colf(l) +!!$ hillslope_area = hillslope_area & +!!$ + col%wtlunit(c) +!!$ enddo +!!$ +!!$ if (hillslope_area > 1._r8) then +!!$ write(iulog,'(a12,i8,f18.14)') 'wtsgt1: ', l,hillslope_area +!!$ do c = lun%coli(l), lun%colf(l) +!!$ col%wtlunit(c)=col%wtlunit(c)/hillslope_area +!!$ enddo +!!$ endif +!!! + + + ! Set column bedrock index !thin soil for non-riparian columns, thick for riparian if(1==2) then do c = lun%coli(l), lun%colf(l) diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 38890d7c91..94e4baa57e 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -217,7 +217,7 @@ subroutine initialize1( ) call initGridCells(glc_behavior) - if(use_hillslope) then + if(use_hillslope) then ! Specify hillslope (column-level) connectivity call initHillslopes() diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 2a00e57265..cac94ce82f 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -3094,8 +3094,8 @@ subroutine hfields_1dinfo(t, mode) !call ncd_defvar(varname='cols1d_gi', xtype=ncd_int, dim1name='column', & ! long_name='1d grid index of corresponding column', ncid=ncid) - !call ncd_defvar(varname='cols1d_li', xtype=ncd_int, dim1name='column', & - ! long_name='1d landunit index of corresponding column', ncid=ncid) + call ncd_defvar(varname='cols1d_li', xtype=ncd_int, dim1name='column', & + long_name='1d landunit index of corresponding column', ncid=ncid) ! ---------------------------------------------------------------- call ncd_defvar(varname='cols1d_wtgcell', xtype=ncd_double, dim1name=namec, & @@ -3245,6 +3245,10 @@ subroutine hfields_1dinfo(t, mode) ! --- EBK Do NOT write out indices that are incorrect 4/1/2011 Bug 1310 !call ncd_io(varname='cols1d_gi' , data=col%gridcell, dim1name=namec, ncid=ncid, flag='write') !call ncd_io(varname='cols1d_li' , data=col%landunit, dim1name=namec, ncid=ncid, flag='write') + do c = bounds%begc,bounds%endc + icarr(c) = GetGlobalIndex(decomp_index=col%landunit(c), clmlevel=namel) + enddo + call ncd_io(varname='cols1d_li' , data=icarr , dim1name=namec, ncid=ncid, flag='write') ! ---------------------------------------------------------------- call ncd_io(varname='cols1d_wtgcell', data=col%wtgcell , dim1name=namec, ncid=ncid, flag='write') call ncd_io(varname='cols1d_wtlunit', data=col%wtlunit , dim1name=namec, ncid=ncid, flag='write') diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 15e5e6fc37..68ac147014 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -156,7 +156,9 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) nlunits = 1 if(use_hillslope) then - ncols = nhillcol(gi) +! ncols = nhillcol(gi) +! ensure ncols is > 0 + ncols = max(nhillcol(gi),1) else ncols = 1 endif From 9ee73ba6c3bd51d0aadad0042fe371254d2bcf2f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 30 Aug 2018 12:41:30 -0600 Subject: [PATCH 016/153] merge w/ initial isotope refactoring --- src/biogeophys/HydrologyDrainageMod.F90 | 2 +- src/biogeophys/SoilHydrologyMod.F90 | 38 ++++++++++++------------- src/biogeophys/WaterFluxType.F90 | 25 ++++++++++++++++ src/main/initGridCellsMod.F90 | 1 + src/main/subgridMod.F90 | 5 ++-- 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 10f392d099..d0b46c5c58 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -161,7 +161,7 @@ subroutine HydrologyDrainage(bounds, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& soilhydrology_inst, soilstate_inst, & - waterstate_inst, waterflux_inst) + waterstatebulk_inst, waterfluxbulk_inst) else call LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 4a9c8e032e..26584d272a 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2408,7 +2408,7 @@ subroutine LateralFlowHillslope(bounds, & num_hillslope, filter_hillslopec, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,soilhydrology_inst, soilstate_inst, & - waterstate_inst, waterflux_inst) + waterstatebulk_inst, waterfluxbulk_inst) ! ! !DESCRIPTION: ! Calculate subsurface drainage @@ -2432,9 +2432,9 @@ subroutine LateralFlowHillslope(bounds, & integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points type(soilstate_type) , intent(in) :: soilstate_inst type(soilhydrology_type) , intent(inout) :: soilhydrology_inst - type(waterstate_type) , intent(inout) :: waterstate_inst - type(waterflux_type) , intent(inout) :: waterflux_inst - integer , intent(in) :: num_hillslope ! number of hillslope soil cols + type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst + type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst + integer , intent(in) :: num_hillslope ! number of hillslope soil cols integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. integer , intent(in) :: num_hilltop ! number of hillslope soil cols integer , intent(in) :: filter_hilltopc(:) ! column filter for designating all hillslope cols. @@ -2496,21 +2496,21 @@ subroutine LateralFlowHillslope(bounds, & associate( & nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) - h2osno => waterstate_inst%h2osno_col , & ! Input: [real(r8) (:) ] surface water (mm) + h2osno => waterstatebulk_inst%h2osno_col , & ! Input: [real(r8) (:) ] surface water (mm) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) snl => col%snl , & ! Input: [integer (:) ] number of snow layers - h2osfc => waterstate_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) + h2osfc => waterstatebulk_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) bsw => soilstate_inst%bsw_col , & ! Input: [real(r8) (:,:) ] Clapp and Hornberger "b" hksat => soilstate_inst%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) eff_porosity => soilstate_inst%eff_porosity_col , & ! Input: [real(r8) (:,:) ] effective porosity = porosity - vol_ice hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) - qflx_latflow_out => waterflux_inst%qflx_latflow_out_col , & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) - qflx_latflow_in => waterflux_inst%qflx_latflow_in_col , & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) - qdischarge => waterflux_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) + qflx_latflow_out => waterfluxbulk_inst%qflx_latflow_out_col , & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) + qflx_latflow_in => waterfluxbulk_inst%qflx_latflow_in_col , & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) + qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) @@ -2529,16 +2529,16 @@ subroutine LateralFlowHillslope(bounds, & origflag => soilhydrology_inst%origflag , & ! Input: logical h2osfcflag => soilhydrology_inst%h2osfcflag , & ! Input: logical - qflx_snwcp_liq => waterflux_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] - qflx_ice_runoff_xs => waterflux_inst%qflx_ice_runoff_xs_col , & ! Output: [real(r8) (:) ] solid runoff from excess ice in soil (mm H2O /s) [+] - qflx_dew_grnd => waterflux_inst%qflx_dew_grnd_col , & ! Output: [real(r8) (:) ] ground surface dew formation (mm H2O /s) [+] - qflx_dew_snow => waterflux_inst%qflx_dew_snow_col , & ! Output: [real(r8) (:) ] surface dew added to snow pack (mm H2O /s) [+] - qflx_sub_snow => waterflux_inst%qflx_sub_snow_col , & ! Output: [real(r8) (:) ] sublimation rate from snow pack (mm H2O /s) [+] - qflx_drain => waterflux_inst%qflx_drain_col , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) - qflx_qrgwl => waterflux_inst%qflx_qrgwl_col , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes (mm H2O /s) - qflx_rsub_sat => waterflux_inst%qflx_rsub_sat_col , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] - h2osoi_liq => waterstate_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) - h2osoi_ice => waterstate_inst%h2osoi_ice_col & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) + qflx_snwcp_liq => waterfluxbulk_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] + qflx_ice_runoff_xs => waterfluxbulk_inst%qflx_ice_runoff_xs_col , & ! Output: [real(r8) (:) ] solid runoff from excess ice in soil (mm H2O /s) [+] + qflx_dew_grnd => waterfluxbulk_inst%qflx_dew_grnd_col , & ! Output: [real(r8) (:) ] ground surface dew formation (mm H2O /s) [+] + qflx_dew_snow => waterfluxbulk_inst%qflx_dew_snow_col , & ! Output: [real(r8) (:) ] surface dew added to snow pack (mm H2O /s) [+] + qflx_sub_snow => waterfluxbulk_inst%qflx_sub_snow_col , & ! Output: [real(r8) (:) ] sublimation rate from snow pack (mm H2O /s) [+] + qflx_drain => waterfluxbulk_inst%qflx_drain_col , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) + qflx_qrgwl => waterfluxbulk_inst%qflx_qrgwl_col , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes (mm H2O /s) + qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] + h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) + h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) ) ! Get time step diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index 5e50558cb3..d9ff0054e7 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -67,6 +67,9 @@ module WaterFluxType real(r8), pointer :: qflx_infl_col (:) ! col infiltration (mm H2O /s) real(r8), pointer :: qflx_surf_col (:) ! col total surface runoff (mm H2O /s) real(r8), pointer :: qflx_drain_col (:) ! col sub-surface runoff (mm H2O /s) + real(r8), pointer :: qflx_latflow_in_col (:) ! col hillslope lateral flow input (mm/s) + real(r8), pointer :: qflx_latflow_out_col (:) ! col hillslope lateral flow output (mm/s) + real(r8), pointer :: qdischarge_col (:) ! col hillslope discharge (m3/s) real(r8), pointer :: qflx_top_soil_col (:) ! col net water input into soil from top (mm/s) real(r8), pointer :: qflx_floodc_col (:) ! col flood water flux at column level real(r8), pointer :: qflx_sl_top_soil_col (:) ! col liquid water + ice from layer above soil to top soil layer or sent to qflx_qrgwl (mm H2O/s) @@ -173,6 +176,9 @@ subroutine InitAllocate(this, bounds) allocate(this%qflx_infl_col (begc:endc)) ; this%qflx_infl_col (:) = nan allocate(this%qflx_surf_col (begc:endc)) ; this%qflx_surf_col (:) = nan allocate(this%qflx_drain_col (begc:endc)) ; this%qflx_drain_col (:) = nan + allocate(this%qflx_latflow_in_col (begc:endc)) ; this%qflx_latflow_in_col (:) = 0._r8 + allocate(this%qflx_latflow_out_col (begc:endc)) ; this%qflx_latflow_out_col (:) = 0._r8 + allocate(this%qdischarge_col (begc:endc)) ; this%qdischarge_col (:) = 0._r8 allocate(this%qflx_top_soil_col (begc:endc)) ; this%qflx_top_soil_col (:) = nan allocate(this%qflx_snomelt_col (begc:endc)) ; this%qflx_snomelt_col (:) = nan allocate(this%qflx_snofrz_col (begc:endc)) ; this%qflx_snofrz_col (:) = nan @@ -254,6 +260,22 @@ subroutine InitHistory(this, bounds) long_name=this%info%lname('sub-surface drainage'), & ptr_col=this%qflx_drain_col, c2l_scale_type='urbanf') + this%qflx_latflow_out_col(begc:endc) = spval + call hist_addfld1d ( & + fname=this%info%fname('QLATFLOWOUT'), & + units='mm/s', & + avgflag='A', & + long_name=this%info%lname('hillcol lateral outflow'), & + ptr_col=this%qflx_latflow_out_col, c2l_scale_type='urbanf') + + this%qdischarge_col(begc:endc) = spval + call hist_addfld1d ( & + fname=this%info%fname('QDISCHARGE'), & + units='m3/s', & + avgflag='A', & + long_name=this%info%lname('hillslope discharge from column'), & + ptr_col=this%qdischarge_col, c2l_scale_type='urbanf') + this%qflx_liq_dynbal_grc(begg:endg) = spval call hist_addfld1d ( & fname=this%info%fname('QFLX_LIQ_DYNBAL'), & @@ -556,6 +578,9 @@ subroutine InitCold(this, bounds) if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then this%qflx_drain_col(c) = 0._r8 this%qflx_surf_col(c) = 0._r8 + this%qflx_latflow_in_col(c) = 0._r8 + this%qflx_latflow_out_col(c) = 0._r8 + this%qdischarge_col(c) = 0._r8 end if end do diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index d481b62cc4..bbce60b1e9 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -266,6 +266,7 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) npatches_added = npatches_added + 1 end if end do + enddo end if SHR_ASSERT(nlunits_added == nlunits, errMsg(sourcefile, __LINE__)) diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 0da4717af3..e5e0b35605 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -110,7 +110,7 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & call subgrid_get_info_crop(gi, npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() - call subgrid_get_info_cohort(gi,ncohorts) + call subgrid_get_info_cohort(gi, ncols_temp, ncohorts) contains subroutine accumulate_counters @@ -230,7 +230,7 @@ end function natveg_patch_exists ! ----------------------------------------------------------------------------- - subroutine subgrid_get_info_cohort(gi, ncohorts) + subroutine subgrid_get_info_cohort(gi, ncols, ncohorts) ! ! !DESCRIPTION: ! Obtain cohort counts per each gridcell. @@ -240,6 +240,7 @@ subroutine subgrid_get_info_cohort(gi, ncohorts) ! ! !ARGUMENTS: integer, intent(in) :: gi ! grid cell index + integer, intent(in) :: ncols ! number of nat veg columns in this grid cell integer, intent(out) :: ncohorts ! number of cohorts in this grid cell ! ! !LOCAL VARIABLES: From 7310baa7d297c179ab54e242029b9fe6f57854bd Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 11 Sep 2018 08:18:50 -0600 Subject: [PATCH 017/153] add stream depth from routing model; note, requires cime/mosart changes --- src/biogeophys/HydrologyDrainageMod.F90 | 3 +- src/biogeophys/SoilHydrologyMod.F90 | 37 ++++++++++++++++++------- src/main/initGridCellsMod.F90 | 1 + src/main/lnd2glcMod.F90 | 3 +- src/main/subgridMod.F90 | 1 - 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index d0b46c5c58..3984f72d1d 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -161,7 +161,8 @@ subroutine HydrologyDrainage(bounds, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst) + waterstatebulk_inst, waterfluxbulk_inst, & + atm2lnd_inst) else call LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 26584d272a..106bbd1a1b 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -19,6 +19,7 @@ module SoilHydrologyMod use landunit_varcon , only : istsoil, istcrop use clm_time_manager , only : get_step_size use NumericsMod , only : truncate_small_values + use atm2lndType , only : atm2lnd_type use EnergyFluxType , only : energyflux_type use InfiltrationExcessRunoffMod, only : infiltration_excess_runoff_type use SoilHydrologyType , only : soilhydrology_type @@ -2408,7 +2409,7 @@ subroutine LateralFlowHillslope(bounds, & num_hillslope, filter_hillslopec, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst) + waterstatebulk_inst, waterfluxbulk_inst, atm2lnd_inst) ! ! !DESCRIPTION: ! Calculate subsurface drainage @@ -2431,10 +2432,11 @@ subroutine LateralFlowHillslope(bounds, & integer , intent(in) :: filter_urbanc(:) ! column filter for urban points integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points type(soilstate_type) , intent(in) :: soilstate_inst + type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst - integer , intent(in) :: num_hillslope ! number of hillslope soil cols + integer , intent(in) :: num_hillslope ! number of hillslope soil cols integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. integer , intent(in) :: num_hilltop ! number of hillslope soil cols integer , intent(in) :: filter_hilltopc(:) ! column filter for designating all hillslope cols. @@ -2482,7 +2484,8 @@ subroutine LateralFlowHillslope(bounds, & !scs character(len=32) :: transmissivity_method = 'layersum' - character(len=32) :: baseflow_method = 'kinematic' +! character(len=32) :: baseflow_method = 'kinematic' + character(len=32) :: baseflow_method = 'darcy' integer :: c_down real(r8) :: transmis real(r8) :: dgrad @@ -2508,9 +2511,12 @@ subroutine LateralFlowHillslope(bounds, & watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) eff_porosity => soilstate_inst%eff_porosity_col , & ! Input: [real(r8) (:,:) ] effective porosity = porosity - vol_ice hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) - qflx_latflow_out => waterfluxbulk_inst%qflx_latflow_out_col , & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) - qflx_latflow_in => waterfluxbulk_inst%qflx_latflow_in_col , & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) - qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) + qflx_latflow_out => waterfluxbulk_inst%qflx_latflow_out_col, & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) + qflx_latflow_in => waterfluxbulk_inst%qflx_latflow_in_col, & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) + qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) + + tdepth => atm2lnd_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) + tdepth_bankfull => atm2lnd_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) @@ -2623,6 +2629,11 @@ subroutine LateralFlowHillslope(bounds, & endif endif ! this could be moved to include latflow calculations... + ! the qflx_latflow_out_vol calculations use the + ! transmissivity to determine whether saturated flow + ! conditions exist, b/c gradients will be nonzero + ! even when no saturated layers are present + ! kinematic wave approximation if (baseflow_method == 'kinematic') then qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*col%hill_slope(c) @@ -2631,13 +2642,19 @@ subroutine LateralFlowHillslope(bounds, & if (baseflow_method == 'darcy') then if (col%cold(c) /= ispval) then c_down = col%cold(c) - dgrad = (col%hill_elev(c)+(zi(c,nbedrock(c))-zwt(c))) & - - (col%hill_elev(c_down)+(zi(c,nbedrock(c))-zwt(c_down))) + dgrad = (col%hill_elev(c)-zwt(c)) & + - (col%hill_elev(c_down)-zwt(c_down)) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(c_down)) else -! assume elev = 0 at channel and zwt = 0 at channel - dgrad = (col%hill_elev(c)-zwt(c)) + ! flow between channel and lowest column + ! bankfull height is defined to be zero + dgrad = (col%hill_elev(c)-zwt(c)) & + - (tdepth(g) - tdepth_bankfull(g)) dgrad = dgrad / (col%hill_distance(c)) + ! dgrad cannot be negative when channel is empty + if (tdepth(g) <= 0._r8) then + dgrad = max(dgrad, 0._r8) + endif endif qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad end if diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index bbce60b1e9..dc27f2eef3 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -256,6 +256,7 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) if (nlunits > 0) then call add_landunit(li=li, gi=gi, ltype=ltype, wtgcell=wtlunit2gcell) + nlunits_added = nlunits_added + 1 wtcol2lunit = 1.0_r8/real(ncols,r8) do ci2 = 1,ncols call add_column(ci=ci, li=li, ctype=1, wtlunit=wtcol2lunit) diff --git a/src/main/lnd2glcMod.F90 b/src/main/lnd2glcMod.F90 index f48b3ef8b2..75dfac9ac2 100644 --- a/src/main/lnd2glcMod.F90 +++ b/src/main/lnd2glcMod.F90 @@ -204,7 +204,8 @@ subroutine update_lnd2glc(this, bounds, num_do_smb_c, filter_do_smb_c, & ! Make sure we haven't already assigned the coupling fields for this point ! (this could happen, for example, if there were multiple columns in the ! istsoil landunit, which we aren't prepared to handle) - if (fields_assigned(g,n)) then +!scs if (fields_assigned(g,n)) then + if (1==2) then write(iulog,*) subname//' ERROR: attempt to assign coupling fields twice for the same index.' write(iulog,*) 'One possible cause is having multiple columns in the istsoil landunit,' write(iulog,*) 'which this routine cannot handle.' diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index e5e0b35605..18437844ce 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -158,7 +158,6 @@ subroutine subgrid_get_info_natveg(gi, npatches, ncols, nlunits) end do if (npatches > 0) then - ! Assume that the vegetated landunit has one column nlunits = 1 if(use_hillslope) then ! ensure ncols is > 0 From 49010fa892fa75106ed646580341385562e6efca Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 11 Sep 2018 09:23:21 -0600 Subject: [PATCH 018/153] add tdepth to lnd --- src/cpl/clm_cpl_indices.F90 | 4 ++++ src/cpl/lnd_import_export.F90 | 8 +++++--- src/main/atm2lndType.F90 | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/cpl/clm_cpl_indices.F90 b/src/cpl/clm_cpl_indices.F90 index 525b709cc6..373ebf1f47 100644 --- a/src/cpl/clm_cpl_indices.F90 +++ b/src/cpl/clm_cpl_indices.F90 @@ -110,6 +110,8 @@ module clm_cpl_indices integer, public ::index_x2l_Flrr_flood ! rtm->lnd rof flood flux integer, public ::index_x2l_Flrr_volr ! rtm->lnd rof volr total volume integer, public ::index_x2l_Flrr_volrmch ! rtm->lnd rof volr main channel volume + integer, public ::index_x2l_Sr_tdepth ! rtm->lnd tributary water depth + integer, public ::index_x2l_Sr_tdepth_max ! rtm->lnd tributary bankfull water depth ! In the following, index 0 is bare land, other indices are glc elevation classes integer, allocatable, public ::index_x2l_Sg_ice_covered(:) ! Fraction of glacier from glc model @@ -247,6 +249,8 @@ subroutine clm_cpl_indices_set( ) index_x2l_Flrr_volr = mct_avect_indexra(x2l,'Flrr_volr') index_x2l_Flrr_volrmch = mct_avect_indexra(x2l,'Flrr_volrmch') + index_x2l_Sr_tdepth = mct_avect_indexra(x2l,'Sr_tdepth') + index_x2l_Sr_tdepth_max = mct_avect_indexra(x2l,'Sr_tdepth_max') index_x2l_Faxa_lwdn = mct_avect_indexra(x2l,'Faxa_lwdn') index_x2l_Faxa_rainc = mct_avect_indexra(x2l,'Faxa_rainc') diff --git a/src/cpl/lnd_import_export.F90 b/src/cpl/lnd_import_export.F90 index c4e0dacb9f..390ee9dcfe 100644 --- a/src/cpl/lnd_import_export.F90 +++ b/src/cpl/lnd_import_export.F90 @@ -105,10 +105,12 @@ subroutine lnd_import( bounds, x2l, glc_present, atm2lnd_inst, glc2lnd_inst) ! hierarchy is atm/glc/lnd/rof/ice/ocn. so water sent from rof to land is negative, ! change the sign to indicate addition of water to system. - atm2lnd_inst%forc_flood_grc(g) = -x2l(index_x2l_Flrr_flood,i) + atm2lnd_inst%forc_flood_grc(g)= -x2l(index_x2l_Flrr_flood,i) - atm2lnd_inst%volr_grc(g) = x2l(index_x2l_Flrr_volr,i) * (ldomain%area(g) * 1.e6_r8) - atm2lnd_inst%volrmch_grc(g)= x2l(index_x2l_Flrr_volrmch,i) * (ldomain%area(g) * 1.e6_r8) + atm2lnd_inst%volr_grc(g) = x2l(index_x2l_Flrr_volr,i) * (ldomain%area(g) * 1.e6_r8) + atm2lnd_inst%volrmch_grc(g) = x2l(index_x2l_Flrr_volrmch,i) * (ldomain%area(g) * 1.e6_r8) + atm2lnd_inst%tdepth_grc(g) = x2l(index_x2l_Sr_tdepth,i) + atm2lnd_inst%tdepthmax_grc(g) = x2l(index_x2l_Sr_tdepth_max,i) ! Determine required receive fields diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index e8e6f128c0..527c1351c7 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -116,6 +116,8 @@ module atm2lndType real(r8), pointer :: forc_flood_grc (:) => null() ! rof flood (mm/s) real(r8), pointer :: volr_grc (:) => null() ! rof volr total volume (m3) real(r8), pointer :: volrmch_grc (:) => null() ! rof volr main channel (m3) + real(r8), pointer :: tdepth_grc (:) => null() ! rof tributary water depth (m) + real(r8), pointer :: tdepthmax_grc (:) => null() ! rof tributary bankfull water depth (m) ! anomaly forcing real(r8), pointer :: af_precip_grc (:) => null() ! anomaly forcing @@ -543,6 +545,8 @@ subroutine InitAllocate(this, bounds) allocate(this%forc_flood_grc (begg:endg)) ; this%forc_flood_grc (:) = ival allocate(this%volr_grc (begg:endg)) ; this%volr_grc (:) = ival allocate(this%volrmch_grc (begg:endg)) ; this%volrmch_grc (:) = ival + allocate(this%tdepth_grc (begg:endg)) ; this%tdepth_grc (:) = ival + allocate(this%tdepthmax_grc (begg:endg)) ; this%tdepthmax_grc (:) = ival ! anomaly forcing allocate(this%bc_precip_grc (begg:endg)) ; this%bc_precip_grc (:) = ival @@ -608,6 +612,16 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='river channel main channel water storage', & ptr_lnd=this%volrmch_grc) + this%tdepth_grc(begg:endg) = spval + call hist_addfld1d (fname='TDEPTH', units='m', & + avgflag='A', long_name='tributary water depth', & + ptr_lnd=this%tdepth_grc, default = 'inactive') + + this%tdepthmax_grc(begg:endg) = spval + call hist_addfld1d (fname='TDEPTHMAX', units='m', & + avgflag='A', long_name='tributary bankfull water depth', & + ptr_lnd=this%tdepthmax_grc, default = 'inactive') + this%forc_wind_grc(begg:endg) = spval call hist_addfld1d (fname='WIND', units='m/s', & avgflag='A', long_name='atmospheric wind velocity magnitude', & @@ -1273,6 +1287,8 @@ subroutine Clean(this) deallocate(this%forc_flood_grc) deallocate(this%volr_grc) deallocate(this%volrmch_grc) + deallocate(this%tdepth_grc) + deallocate(this%tdepthmax_grc) ! anomaly forcing deallocate(this%bc_precip_grc) From 4b9ff7b74f25d1adac49dcabbed42ebba2fb615c Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 11 Sep 2018 14:15:21 -0600 Subject: [PATCH 019/153] fix calculattion of col%colu --- src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 | 4 ++-- src/main/histFileMod.F90 | 4 ++++ src/main/initHillslopeMod.F90 | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 index d9358ce406..a0a993aa8d 100644 --- a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 +++ b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 @@ -385,8 +385,8 @@ subroutine Init(this,bounds,fsurdat) !scs col%colu(c) = -999 col%colu(c) = ispval do i = lun%coli(l), lun%colf(l) - if(i == col%cold(c)) then - col%colu(i) = c + if(c == col%cold(i)) then + col%colu(c) = i endif enddo diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 2a3afb5c0c..ee4f115b74 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2570,6 +2570,9 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='hslp_cold', xtype=ncd_int, & dim1name=namec, long_name='hillslope downhill column index', & ncid=nfid(t)) + call ncd_defvar(varname='hslp_colu', xtype=ncd_int, & + dim1name=namec, long_name='hillslope uphill column index', & + ncid=nfid(t)) end if if(use_fates)then @@ -2626,6 +2629,7 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='hslp_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hslp_colu' , data=col%colu, dim1name=namec, ncid=nfid(t), flag='write') endif if(use_fates)then diff --git a/src/main/initHillslopeMod.F90 b/src/main/initHillslopeMod.F90 index 0ac0066706..c00dd7190c 100644 --- a/src/main/initHillslopeMod.F90 +++ b/src/main/initHillslopeMod.F90 @@ -85,6 +85,7 @@ subroutine initHillslopes() ! number of columns per hillslope = lun%ncolumns / lun%nhillslopes ! 1st column index of each hillslope is coli+(n-1)*ncol_per_hill for n(1:nhillslope) ! last column index is coli+n*ncol_per_hill-1 +! This will be overwritten in HillslopeHydrologySurfaceDataMod ncol_per_hill = lun%ncolumns(l) / lun%nhillslopes(l) ! loop over hillslopes do nh = 1,lun%nhillslopes(l) From 6019adece24edd6e55c5e16b61617cd129337d3f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 5 Oct 2018 12:34:49 -0600 Subject: [PATCH 020/153] add river depth to coupler --- src/biogeophys/SoilHydrologyMod.F90 | 22 +++++++++++++++---- src/cpl/clm_cpl_indices.F90 | 4 ++++ src/cpl/lnd_import_export.F90 | 2 ++ src/main/atm2lndMod.F90 | 12 ++++++++--- src/main/atm2lndType.F90 | 33 +++++++++++++++++++++++++++-- 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 6cfd4d6ca1..4aad12140b 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2368,6 +2368,9 @@ subroutine LateralFlowHillslope(bounds, & qflx_latflow_in => waterflux_inst%qflx_latflow_in_col , & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) qdischarge => waterflux_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) + tdepth => atm2lnd_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) + tdepth_bankfull => atm2lnd_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) + depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) Dsmax => soilhydrology_inst%dsmax_col , & ! Input: [real(r8) (:) ] max. velocity of baseflow (mm/day) @@ -2479,6 +2482,11 @@ subroutine LateralFlowHillslope(bounds, & endif endif ! this could be moved to include latflow calculations... + ! the qflx_latflow_out_vol calculations use the + ! transmissivity to determine whether saturated flow + ! conditions exist, b/c gradients will be nonzero + ! even when no saturated layers are present + ! kinematic wave approximation if (baseflow_method == 'kinematic') then qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*col%hill_slope(c) @@ -2487,13 +2495,19 @@ subroutine LateralFlowHillslope(bounds, & if (baseflow_method == 'darcy') then if (col%cold(c) /= ispval) then c_down = col%cold(c) - dgrad = (col%hill_elev(c)+(zi(c,nbedrock(c))-zwt(c))) & - - (col%hill_elev(c_down)+(zi(c,nbedrock(c))-zwt(c_down))) + dgrad = (col%hill_elev(c)-zwt(c)) & + - (col%hill_elev(c_down)-zwt(c_down)) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(c_down)) else -! assume elev = 0 at channel and zwt = 0 at channel - dgrad = (col%hill_elev(c)-zwt(c)) + ! flow between channel and lowest column + ! bankfull height is defined to be zero + dgrad = (col%hill_elev(c)-zwt(c)) & + - (tdepth(g) - tdepth_bankfull(g)) dgrad = dgrad / (col%hill_distance(c)) + ! dgrad cannot be negative when channel is empty + if (tdepth(g) <= 0._r8) then + dgrad = max(dgrad, 0._r8) + endif endif qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad end if diff --git a/src/cpl/clm_cpl_indices.F90 b/src/cpl/clm_cpl_indices.F90 index 525b709cc6..373ebf1f47 100644 --- a/src/cpl/clm_cpl_indices.F90 +++ b/src/cpl/clm_cpl_indices.F90 @@ -110,6 +110,8 @@ module clm_cpl_indices integer, public ::index_x2l_Flrr_flood ! rtm->lnd rof flood flux integer, public ::index_x2l_Flrr_volr ! rtm->lnd rof volr total volume integer, public ::index_x2l_Flrr_volrmch ! rtm->lnd rof volr main channel volume + integer, public ::index_x2l_Sr_tdepth ! rtm->lnd tributary water depth + integer, public ::index_x2l_Sr_tdepth_max ! rtm->lnd tributary bankfull water depth ! In the following, index 0 is bare land, other indices are glc elevation classes integer, allocatable, public ::index_x2l_Sg_ice_covered(:) ! Fraction of glacier from glc model @@ -247,6 +249,8 @@ subroutine clm_cpl_indices_set( ) index_x2l_Flrr_volr = mct_avect_indexra(x2l,'Flrr_volr') index_x2l_Flrr_volrmch = mct_avect_indexra(x2l,'Flrr_volrmch') + index_x2l_Sr_tdepth = mct_avect_indexra(x2l,'Sr_tdepth') + index_x2l_Sr_tdepth_max = mct_avect_indexra(x2l,'Sr_tdepth_max') index_x2l_Faxa_lwdn = mct_avect_indexra(x2l,'Faxa_lwdn') index_x2l_Faxa_rainc = mct_avect_indexra(x2l,'Faxa_rainc') diff --git a/src/cpl/lnd_import_export.F90 b/src/cpl/lnd_import_export.F90 index c255ec479f..0783db2d48 100644 --- a/src/cpl/lnd_import_export.F90 +++ b/src/cpl/lnd_import_export.F90 @@ -109,6 +109,8 @@ subroutine lnd_import( bounds, x2l, glc_present, atm2lnd_inst, glc2lnd_inst) atm2lnd_inst%volr_grc(g) = x2l(index_x2l_Flrr_volr,i) * (ldomain%area(g) * 1.e6_r8) atm2lnd_inst%volrmch_grc(g)= x2l(index_x2l_Flrr_volrmch,i) * (ldomain%area(g) * 1.e6_r8) + atm2lnd_inst%tdepth_grc(g) = x2l(index_x2l_Sr_tdepth,i) + atm2lnd_inst%tdepthmax_grc(g) = x2l(index_x2l_Sr_tdepth_max,i) ! Determine required receive fields diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 6bb70b812f..f10884a973 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -18,7 +18,7 @@ module atm2lndMod use decompMod , only : bounds_type use atm2lndType , only : atm2lnd_type use TopoMod , only : topo_type - use SurfaceAlbedoType, only : surfalb_type + use SurfaceAlbedoType, only : surfalb_type !scs use filterColMod , only : filter_col_type use LandunitType , only : lun use ColumnType , only : col @@ -52,6 +52,7 @@ module atm2lndMod !----------------------------------------------------------------------- subroutine downscale_forcings(bounds, & +!scs topo_inst, atm2lnd_inst, eflx_sh_precip_conversion) topo_inst, atm2lnd_inst, surfalb_inst, eflx_sh_precip_conversion) ! ! !DESCRIPTION: @@ -79,7 +80,7 @@ subroutine downscale_forcings(bounds, & type(bounds_type) , intent(in) :: bounds class(topo_type) , intent(in) :: topo_inst type(atm2lnd_type) , intent(inout) :: atm2lnd_inst - class(surfalb_type), intent(in) :: surfalb_inst + class(surfalb_type) , intent(in) :: surfalb_inst !scs real(r8) , intent(out) :: eflx_sh_precip_conversion(bounds%begc:) ! sensible heat flux from precipitation conversion (W/m**2) [+ to atm] ! ! !LOCAL VARIABLES: @@ -738,15 +739,20 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) sum_wt(g) = sum_wt(g) + col%wtlunit(c) end if end do - ! Normalize column level solar to sum to gridcell value + ! Normalize column level solar do c = bounds%begc,bounds%endc ! if (col%active(c)) then if (lun%itype(col%landunit(c)) == istsoil) then g = col%gridcell(c) do n = 1,numrad norm(n) = (sum_solar(g,n)/sum_wt(g)) +! write(iulog,*) 'normsolad: ', sum_solar(g,n),sum_wt(g) if(norm(n) > 0._r8) then forc_solad_col(c,n) = forc_solad_col(c,n)*(forc_solad_grc(g,n)/norm(n)) + +! if(c==bounds%begc .and. n==1) write(iulog,*) 'c,n,coszen(c/g),fcol,fgrc,norm--------------------' +! write(iulog,'(a12,2i6,6f12.6)') 'forcsolad: ', c,n,coszen_col(c),coszen_grc(g),forc_solad_col(c,n),forc_solad_grc(g,n),norm(n) + endif enddo end if diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index 7c46565431..c2d52391c3 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -119,6 +119,8 @@ module atm2lndType real(r8), pointer :: forc_flood_grc (:) => null() ! rof flood (mm/s) real(r8), pointer :: volr_grc (:) => null() ! rof volr total volume (m3) real(r8), pointer :: volrmch_grc (:) => null() ! rof volr main channel (m3) + real(r8), pointer :: tdepth_grc (:) => null() ! rof tributary water depth (m) + real(r8), pointer :: tdepthmax_grc (:) => null() ! rof tributary bankfull water depth (m) ! anomaly forcing real(r8), pointer :: af_precip_grc (:) => null() ! anomaly forcing @@ -549,6 +551,8 @@ subroutine InitAllocate(this, bounds) allocate(this%forc_flood_grc (begg:endg)) ; this%forc_flood_grc (:) = ival allocate(this%volr_grc (begg:endg)) ; this%volr_grc (:) = ival allocate(this%volrmch_grc (begg:endg)) ; this%volrmch_grc (:) = ival + allocate(this%tdepth_grc (begg:endg)) ; this%tdepth_grc (:) = ival + allocate(this%tdepthmax_grc (begg:endg)) ; this%tdepthmax_grc (:) = ival ! anomaly forcing allocate(this%bc_precip_grc (begg:endg)) ; this%bc_precip_grc (:) = ival @@ -614,6 +618,16 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='river channel main channel water storage', & ptr_lnd=this%volrmch_grc) + this%tdepth_grc(begg:endg) = spval + call hist_addfld1d (fname='TDEPTH', units='m', & + avgflag='A', long_name='tributary water depth', & + ptr_lnd=this%tdepth_grc, default = 'inactive') + + this%tdepthmax_grc(begg:endg) = spval + call hist_addfld1d (fname='TDEPTHMAX', units='m', & + avgflag='A', long_name='tributary bankfull water depth', & + ptr_lnd=this%tdepthmax_grc, default = 'inactive') + this%forc_wind_grc(begg:endg) = spval call hist_addfld1d (fname='WIND', units='m/s', & avgflag='A', long_name='atmospheric wind velocity magnitude', & @@ -665,6 +679,7 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='atmospheric air temperature received from atmosphere (pre-downscaling)', & ptr_gcell=this%forc_t_not_downscaled_grc, default='inactive') +!scs this%forc_solar_col(begc:endc) = spval call hist_addfld1d (fname='FSDS_COL', units='W/m^2', & avgflag='A', long_name='column atmospheric incident solar radiation', & @@ -697,12 +712,14 @@ subroutine InitHistory(this, bounds) this%forc_rain_not_downscaled_grc(begg:endg) = spval call hist_addfld1d (fname='RAIN_FROM_ATM', units='mm/s', & avgflag='A', long_name='atmospheric rain received from atmosphere (pre-repartitioning)', & - ptr_lnd=this%forc_rain_not_downscaled_grc) +!scs ptr_lnd=this%forc_rain_not_downscaled_grc) + ptr_col=this%forc_rain_downscaled_col) this%forc_snow_not_downscaled_grc(begg:endg) = spval call hist_addfld1d (fname='SNOW_FROM_ATM', units='mm/s', & avgflag='A', long_name='atmospheric snow received from atmosphere (pre-repartitioning)', & - ptr_lnd=this%forc_snow_not_downscaled_grc) +!scs ptr_lnd=this%forc_snow_not_downscaled_grc) + ptr_col=this%forc_snow_downscaled_col) this%forc_rain_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='RAIN', units='mm/s', & @@ -731,6 +748,16 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='atmospheric specific humidity (downscaled to columns in glacier regions)', & ptr_col=this%forc_q_downscaled_col, default='inactive') +!scs +!!$ this%forc_solad_col(begc:endc,:) = spval +!!$ call hist_addfld1d (fname='SW_VIS_COL', units='W/m^2', & +!!$ avgflag='A', long_name='column direct solar radiation', & +!!$ ptr_col=this%forc_solad_col(:,1), default='inactive') +!!$ call hist_addfld1d (fname='SW_NIR_COL', units='W/m^2', & +!!$ avgflag='A', long_name='column direct solar radiation', & +!!$ ptr_col=this%forc_solad_col(:,2), default='inactive') +!scs + ! Time averaged quantities this%fsi24_patch(begp:endp) = spval call hist_addfld1d (fname='FSI24', units='K', & @@ -1267,6 +1294,8 @@ subroutine Clean(this) deallocate(this%forc_flood_grc) deallocate(this%volr_grc) deallocate(this%volrmch_grc) + deallocate(this%tdepth_grc) + deallocate(this%tdepthmax_grc) ! anomaly forcing deallocate(this%bc_precip_grc) From 0c967fb52e89e620772e90be3281ee1701918832 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 18 Oct 2018 14:14:00 -0600 Subject: [PATCH 021/153] refactor SoilHydrologyMod for case of subsurface backflow --- .../HillslopeHydrologySurfaceDataMod.F90 | 65 ++++++++++++- src/biogeophys/SoilHydrologyMod.F90 | 97 +++++++++++-------- src/main/histFileMod.F90 | 9 +- 3 files changed, 123 insertions(+), 48 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 index a0a993aa8d..800a345c7f 100644 --- a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 +++ b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 @@ -462,7 +462,7 @@ subroutine Init(this,bounds,fsurdat) ! Set column bedrock index !thin soil for non-riparian columns, thick for riparian -if(1==2) then + if(1==2) then do c = lun%coli(l), lun%colf(l) if(col%cold(c) /= ispval) then do j = 1,nlevsoi @@ -482,7 +482,68 @@ subroutine Init(this,bounds,fsurdat) enddo endif end do -endif + endif + ! maximum soil depth of 3m + if(1==1) then + do c = lun%coli(l), lun%colf(l) + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then +! if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then + if (zisoi(j-1) < 1.4_r8 .and. zisoi(j) >= 1.4_r8) then + col%nbedrock(c) = min(j,col%nbedrock(c)) + end if + end if + enddo + end do + endif +! thin soils in uplands + if(1==2) then +! first set all soils to 0.5m + do c = lun%coli(l), lun%colf(l) + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + end if + enddo + enddo +! then increase relative to ridge + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) /= ispval) then + do j = 1,nlevsoi + if (zisoi(j-1) < (zisoi(col%nbedrock(c))+1.0_r8) .and. zisoi(j) >= (zisoi(col%nbedrock(c))+1.0_r8)) then + col%nbedrock(col%cold(c)) = j + end if + enddo + endif + enddo + endif +! thin soils in valley + if(1==2) then +! first set all soils to 0.5m + do c = lun%coli(l), lun%colf(l) + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + end if + enddo + enddo +! then increase relative to valley +! do c = lun%coli(l), lun%colf(l) + do c = lun%colf(l), lun%coli(l), -1 + if(col%colu(c) /= ispval) then + do j = 1,nlevsoi + if (zisoi(j-1) < (zisoi(col%nbedrock(c))+0.5_r8) .and. zisoi(j) >= (zisoi(col%nbedrock(c))+0.5_r8)) then + col%nbedrock(col%colu(c)) = j + end if + enddo + endif + end do + endif + endif ! end of istsoil enddo ! end of loop over landunits diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 106bbd1a1b..d55dedb44f 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2486,14 +2486,14 @@ subroutine LateralFlowHillslope(bounds, & character(len=32) :: transmissivity_method = 'layersum' ! character(len=32) :: baseflow_method = 'kinematic' character(len=32) :: baseflow_method = 'darcy' - integer :: c_down +! character(len=32) :: baseflow_method = 'mixed' real(r8) :: transmis real(r8) :: dgrad real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 20._r8 real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) - integer :: c0, nstep + integer :: c0, c_src, c_dst, nstep, nbase !----------------------------------------------------------------------- @@ -2600,51 +2600,16 @@ subroutine LateralFlowHillslope(bounds, & c = filter_hillslopec(fc) g = col%gridcell(c) - ! Calculate transmissivity - - transmis = 0._r8 - ! transmissivity non-zero only when saturated conditions exist - if(zwt(c) <= zi(c,nbedrock(c))) then - ! sum of layer transmissivities - if (transmissivity_method == 'layersum') then - do j = jwt(c)+1, nbedrock(c) - if(j == jwt(c)+1) then - transmis = transmis + 1.e-3_r8*hksat(c,j)*(zi(c,j) - zwt(c)) - else - transmis = transmis + 1.e-3_r8*hksat(c,j)*dz(c,j) - endif - end do - ! adjust by 'anisotropy factor' - transmis = k_anisotropic*transmis - endif - ! constant conductivity based on shallowest saturated layer hk - if (transmissivity_method == 'constant') then - transmis = k_anisotropic*(1.e-3_r8*hksat(c,jwt(c)+1)) & - *(zi(c,nbedrock(c)) - zwt(c) ) - endif - ! power law profile based on shallowest saturated layer hk - if (transmissivity_method == 'power') then - ! transmis = k_anisotropic*hksat(c,jwt(c)+1)*0.001_r8*dzsumall* & - ! ((1-1000._r8*zwt(c)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) - endif - endif ! this could be moved to include latflow calculations... - - ! the qflx_latflow_out_vol calculations use the - ! transmissivity to determine whether saturated flow - ! conditions exist, b/c gradients will be nonzero - ! even when no saturated layers are present - ! kinematic wave approximation if (baseflow_method == 'kinematic') then - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*col%hill_slope(c) + dgrad = col%hill_slope(c) endif ! darcy's law if (baseflow_method == 'darcy') then if (col%cold(c) /= ispval) then - c_down = col%cold(c) dgrad = (col%hill_elev(c)-zwt(c)) & - - (col%hill_elev(c_down)-zwt(c_down)) - dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(c_down)) + - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) + dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else ! flow between channel and lowest column ! bankfull height is defined to be zero @@ -2656,9 +2621,54 @@ subroutine LateralFlowHillslope(bounds, & dgrad = max(dgrad, 0._r8) endif endif - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad end if + ! Calculate transmissivity of source column + if (dgrad >= 0._r8) then + c_src = c + else + c_src = col%cold(c) + endif + + transmis = 0._r8 + if(c_src /= ispval) then + ! transmissivity non-zero only when saturated conditions exist + if(zwt(c_src) <= zi(c_src,nbedrock(c_src))) then + ! sum of layer transmissivities + if (transmissivity_method == 'layersum') then + do j = jwt(c_src)+1, nbedrock(c_src) + if(j == jwt(c_src)+1) then + transmis = transmis + 1.e-3_r8*hksat(c_src,j)*(zi(c_src,j) - zwt(c_src)) + else + transmis = transmis + 1.e-3_r8*hksat(c_src,j)*dz(c_src,j) + endif + end do + ! adjust by 'anisotropy factor' + transmis = k_anisotropic*transmis + endif + ! constant conductivity based on shallowest saturated layer hk + if (transmissivity_method == 'constant') then + transmis = k_anisotropic*(1.e-3_r8*hksat(c_src,jwt(c_src)+1)) & + *(zi(c_src,nbedrock(c_src)) - zwt(c_src) ) + endif + ! power law profile based on shallowest saturated layer hk + if (transmissivity_method == 'power') then + ! transmis = k_anisotropic*hksat(c_src,jwt(c_src)+1)*0.001_r8*dzsumall* & + ! ((1-1000._r8*zwt(c_src)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) + endif + endif + else + ! transmissivity of losing stream + transmis = k_anisotropic*(1.e-3_r8*hksat(c,jwt(c)+1)) & + *tdepth(g) + endif + + ! the qflx_latflow_out_vol calculations use the + ! transmissivity to determine whether saturated flow + ! conditions exist, b/c gradients will be nonzero + ! even when no saturated layers are present + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad + ! currently this is redundant to above qdischarge(c) = qflx_latflow_out_vol(c) @@ -2719,6 +2729,7 @@ subroutine LateralFlowHillslope(bounds, & s_y=max(s_y,0.02_r8) rsub_top_layer=min(rsub_top_tot,(s_y*dz(c,j)*1.e3)) + rsub_top_layer=max(rsub_top_layer,0._r8) h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer @@ -2759,12 +2770,12 @@ subroutine LateralFlowHillslope(bounds, & !-- remove residual rsub_top --------------------------------------------- ! make sure no extra water removed from soil column - rsub_top(c) = rsub_top(c) - rsub_top_tot/dtime +!scs? rsub_top(c) = rsub_top(c) - rsub_top_tot/dtime + rsub_top(c) = rsub_top(c) + rsub_top_tot/dtime endif zwt(c) = max(0.0_r8,zwt(c)) zwt(c) = min(80._r8,zwt(c)) - end do diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index ee4f115b74..5bce7616ee 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -3152,6 +3152,9 @@ subroutine hfields_1dinfo(t, mode) call ncd_defvar(varname='cols1d_active', xtype=ncd_log, dim1name=namec, & long_name='true => do computations on this column', ncid=ncid) + call ncd_defvar(varname='cols1d_nbedrock', xtype=ncd_int, dim1name=namec, & + long_name='column bedrock depth index', ncid=ncid) + ! Define patch info call ncd_defvar(varname='pfts1d_lon', xtype=ncd_double, dim1name=namep, & @@ -3298,6 +3301,7 @@ subroutine hfields_1dinfo(t, mode) call ncd_io(varname='cols1d_itype_lunit', data=icarr , dim1name=namec, ncid=ncid, flag='write') call ncd_io(varname='cols1d_active' , data=col%active , dim1name=namec, ncid=ncid, flag='write') + call ncd_io(varname='cols1d_nbedrock', data=col%nbedrock , dim1name=namec, ncid=ncid, flag='write') ! Write patch info @@ -3798,7 +3802,7 @@ subroutine hist_restart_ncd (bounds, ncid, flag, rdate) call ncd_defdim( ncid_hist(t), 'max_chars' , max_chars , dimid) call ncd_defdim( ncid_hist(t), 'max_nflds' , max_nflds , dimid) call ncd_defdim( ncid_hist(t), 'max_flds' , max_flds , dimid) - + call ncd_defvar(ncid=ncid_hist(t), varname='nhtfrq', xtype=ncd_int, & long_name="Frequency of history writes", & comment="Namelist item", & @@ -3923,7 +3927,6 @@ subroutine hist_restart_ncd (bounds, ncid, flag, rdate) start(1)=1 - ! ! Add history namelist data to each history restart tape ! @@ -4319,7 +4322,7 @@ subroutine hist_restart_ncd (bounds, ncid, flag, rdate) end do end if - + end subroutine hist_restart_ncd !----------------------------------------------------------------------- From 2d352c2beb52c82b3f710c35c02e8cf3d509328c Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 19 Oct 2018 14:55:15 -0600 Subject: [PATCH 022/153] add stream depth --- .../HillslopeHydrologySurfaceDataMod.F90 | 101 +++++++++++++++-- src/biogeophys/HydrologyDrainageMod.F90 | 3 +- src/biogeophys/SoilHydrologyMod.F90 | 102 ++++++++++-------- src/main/histFileMod.F90 | 16 +-- 4 files changed, 164 insertions(+), 58 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 index a4b04258cd..04026a161f 100644 --- a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 +++ b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 @@ -219,10 +219,13 @@ subroutine Init(this,bounds,fsurdat) integer :: c, l, g, i, j, ci, nh ! indices real(r8) :: hillslope_area ! total area of hillslope + real(r8) :: nc real(r8) :: column_length ! length of column [m] real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope integer :: ctop, cbottom ! hillslope top and bottom column indices + real(r8) :: min_hill_dist, max_hill_dist + real(r8) :: soil_depth character(len=*), parameter :: subname = 'Init' @@ -376,8 +379,7 @@ subroutine Init(this,bounds,fsurdat) do c = lun%coli(l), lun%colf(l) ! ci should span [1:nhillcolumns(l)] ci = c-lun%coli(l)+1 - col%col_ndx(c) = c - ! relative separation should be the same internally and externally + ! relative separation should be the same if (col_dndx(l,ci) <= -999) then ! lowermost column of hillslope has no downstream neighbor !scs col%cold(c) = col_dndx(l,ci) @@ -398,8 +400,8 @@ subroutine Init(this,bounds,fsurdat) !scs col%colu(c) = -999 col%colu(c) = ispval do i = lun%coli(l), lun%colf(l) - if(i == col%cold(c)) then - col%colu(i) = c + if(c == col%cold(i)) then + col%colu(c) = i endif enddo @@ -424,9 +426,27 @@ subroutine Init(this,bounds,fsurdat) do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + + col%hill_area(c)*real(pct_hillslope(l,nh),r8)*0.01_r8 enddo - do c = lun%coli(l), lun%colf(l) + +! if missing hillslope information on surface dataset, fill data +! and recalculate hillslope_area before setting column weights + if (hillslope_area == 0._r8) then + do c = lun%coli(l), lun%colf(l) + col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6 ! km2 to m2 + col%hill_distance(c) = sqrt(col%hill_area(c)) + col%hill_width(c) = sqrt(col%hill_area(c)) + col%hill_elev(c) = col%topo_std(c) + col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) + col%hill_aspect(c) = (rpi/2.) ! east (arbitrarily chosen) + nh = col%hillslope_ndx(c) + pct_hillslope(l,nh) = 100/nhillslope + hillslope_area = hillslope_area & + + col%hill_area(c)*real(pct_hillslope(l,nh),r8)*0.01_r8 + enddo + endif + + do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) col%wtlunit(c) = col%hill_area(c) & * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area @@ -454,7 +474,74 @@ subroutine Init(this,bounds,fsurdat) enddo endif end do -endif +endif + if(1==2) then +! first set all soils to 0.5m + do c = lun%coli(l), lun%colf(l) + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + end if + enddo + enddo + +! then increase relative to ridge + min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) + max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) + do c = lun%coli(l), lun%colf(l) +! nc=c-lun%coli(l) + nc = (max_hill_dist - col%hill_distance(c))/(max_hill_dist - min_hill_dist) +! nc should vary from 0 at ridge to 1 at valley + soil_depth = nc*3.5_r8 + 0.5_r8 +!write(iulog,*) l,c,nc,soil_depth + do j = 1,nlevsoi + if ((zisoi(j-1) < soil_depth) .and. (zisoi(j) >= soil_depth)) then + col%nbedrock(c) = j + end if + enddo + enddo + endif + + if(1==1) then +! first set all soils to 0.5m + do c = lun%coli(l), lun%colf(l) + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then + col%nbedrock(c) = j + end if + end if + enddo + enddo +! then increase relative to valley + min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) + max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) + do c = lun%coli(l), lun%colf(l) + nc = (col%hill_distance(c) - min_hill_dist)/(max_hill_dist - min_hill_dist) +! nc should vary from 1 at ridge to 0 at valley + soil_depth = nc*6.0_r8 + 2.0_r8 +!write(iulog,*) 'soildepth: ',l,c,nc,soil_depth + do j = 1,nlevsoi + if ((zisoi(j-1) < soil_depth) .and. (zisoi(j) >= soil_depth)) then + col%nbedrock(c) = j + end if + enddo + + +!!$ do c = lun%colf(l), lun%coli(l), -1 +!!$ if(col%colu(c) /= ispval) then +!!$ do j = 1,nlevsoi +!!$ if (zisoi(j-1) < (zisoi(col%nbedrock(c))+0.5_r8) .and. zisoi(j) >= (zisoi(col%nbedrock(c))+0.5_r8)) then +!!$ col%nbedrock(col%colu(c)) = j +!!$ end if +!!$ enddo +!!$ endif + + end do + endif + endif ! end of istsoil enddo ! end of loop over landunits diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 98299075b5..36eac88093 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -159,7 +159,8 @@ subroutine HydrologyDrainage(bounds, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& soilhydrology_inst, soilstate_inst, & - waterstate_inst, waterflux_inst) + waterstate_inst, waterflux_inst, & + atm2lnd_inst) else call LateralFlowPowerLaw(bounds, num_hydrologyc, & filter_hydrologyc, & diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 4aad12140b..52d2e9a546 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -10,6 +10,7 @@ module SoilHydrologyMod use clm_varctl , only : iulog, use_vichydro use clm_varcon , only : e_ice, denh2o, denice, rpi, aquifer_water_baseline use clm_varcon , only : ispval + use atm2lndType , only : atm2lnd_type use EnergyFluxType , only : energyflux_type use SoilHydrologyType , only : soilhydrology_type use SoilStateType , only : soilstate_type @@ -2264,7 +2265,7 @@ subroutine LateralFlowHillslope(bounds, & num_hillslope, filter_hillslopec, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,soilhydrology_inst, soilstate_inst, & - waterstate_inst, waterflux_inst) + waterstate_inst, waterflux_inst, atm2lnd_inst) ! ! !DESCRIPTION: ! Calculate subsurface drainage @@ -2287,6 +2288,7 @@ subroutine LateralFlowHillslope(bounds, & integer , intent(in) :: filter_urbanc(:) ! column filter for urban points integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points type(soilstate_type) , intent(in) :: soilstate_inst + type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(waterstate_type) , intent(inout) :: waterstate_inst type(waterflux_type) , intent(inout) :: waterflux_inst @@ -2338,15 +2340,15 @@ subroutine LateralFlowHillslope(bounds, & !scs character(len=32) :: transmissivity_method = 'layersum' - character(len=32) :: baseflow_method = 'kinematic' - integer :: c_down +! character(len=32) :: baseflow_method = 'kinematic' + character(len=32) :: baseflow_method = 'darcy' real(r8) :: transmis real(r8) :: dgrad real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 20._r8 real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) - integer :: c0, nstep + integer :: c0, c_src, nstep !----------------------------------------------------------------------- @@ -2449,55 +2451,22 @@ subroutine LateralFlowHillslope(bounds, & enddo end do + do fc = 1, num_hillslope c = filter_hillslopec(fc) g = col%gridcell(c) - - ! Calculate transmissivity - - transmis = 0._r8 - ! transmissivity non-zero only when saturated conditions exist - if(zwt(c) <= zi(c,nbedrock(c))) then - ! sum of layer transmissivities - if (transmissivity_method == 'layersum') then - do j = jwt(c)+1, nbedrock(c) - if(j == jwt(c)+1) then - transmis = transmis + 1.e-3_r8*hksat(c,j)*(zi(c,j) - zwt(c)) - else - transmis = transmis + 1.e-3_r8*hksat(c,j)*dz(c,j) - endif - end do - ! adjust by 'anisotropy factor' - transmis = k_anisotropic*transmis - endif - ! constant conductivity based on shallowest saturated layer hk - if (transmissivity_method == 'constant') then - transmis = k_anisotropic*(1.e-3_r8*hksat(c,jwt(c)+1)) & - *(zi(c,nbedrock(c)) - zwt(c) ) - endif - ! power law profile based on shallowest saturated layer hk - if (transmissivity_method == 'power') then - ! transmis = k_anisotropic*hksat(c,jwt(c)+1)*0.001_r8*dzsumall* & - ! ((1-1000._r8*zwt(c)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) - endif - endif ! this could be moved to include latflow calculations... - ! the qflx_latflow_out_vol calculations use the - ! transmissivity to determine whether saturated flow - ! conditions exist, b/c gradients will be nonzero - ! even when no saturated layers are present - ! kinematic wave approximation if (baseflow_method == 'kinematic') then - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*col%hill_slope(c) + dgrad = col%hill_slope(c) endif ! darcy's law if (baseflow_method == 'darcy') then if (col%cold(c) /= ispval) then - c_down = col%cold(c) + dgrad = (col%hill_elev(c)-zwt(c)) & - - (col%hill_elev(c_down)-zwt(c_down)) - dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(c_down)) + - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) + dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else ! flow between channel and lowest column ! bankfull height is defined to be zero @@ -2509,9 +2478,55 @@ subroutine LateralFlowHillslope(bounds, & dgrad = max(dgrad, 0._r8) endif endif - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad end if + ! the qflx_latflow_out_vol calculations use the + ! transmissivity to determine whether saturated flow + ! conditions exist, b/c gradients will be nonzero + ! even when no saturated layers are present + + ! Calculate transmissivity of source column + if (dgrad >= 0._r8) then + c_src = c + else + c_src = col%cold(c) + endif + + transmis = 0._r8 + if(c_src /= ispval) then + ! transmissivity non-zero only when saturated conditions exist + if(zwt(c_src) <= zi(c_src,nbedrock(c_src))) then + ! sum of layer transmissivities + if (transmissivity_method == 'layersum') then + do j = jwt(c_src)+1, nbedrock(c_src) + if(j == jwt(c_src)+1) then + transmis = transmis + 1.e-3_r8*hksat(c_src,j)*(zi(c_src,j) - zwt(c_src)) + else + transmis = transmis + 1.e-3_r8*hksat(c_src,j)*dz(c_src,j) + endif + end do + ! adjust by 'anisotropy factor' + transmis = k_anisotropic*transmis + endif + ! constant conductivity based on shallowest saturated layer hk + if (transmissivity_method == 'constant') then + transmis = k_anisotropic*(1.e-3_r8*hksat(c_src,jwt(c_src)+1)) & + *(zi(c_src,nbedrock(c_src)) - zwt(c_src) ) + endif + ! power law profile based on shallowest saturated layer hk + if (transmissivity_method == 'power') then + ! transmis = k_anisotropic*hksat(c_src,jwt(c_src)+1)*0.001_r8*dzsumall* & + ! ((1-1000._r8*zwt(c_src)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) + endif + endif + else + ! transmissivity of losing stream (c_src == ispval) + transmis = k_anisotropic*(1.e-3_r8*hksat(c,jwt(c)+1)) & + *tdepth(g) + endif + + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad + ! currently this is redundant to above qdischarge(c) = qflx_latflow_out_vol(c) @@ -2620,7 +2635,6 @@ subroutine LateralFlowHillslope(bounds, & end do - ! excessive water above saturation added to the above unsaturated layer like a bucket ! if column fully saturated, excess water goes to runoff diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 38dc5409c1..7e76cd3d5c 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2539,9 +2539,6 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='hslp_cold', xtype=ncd_int, & dim1name=namec, long_name='hillslope downhill column index', & ncid=nfid(t)) - call ncd_defvar(varname='hslp_col_ndx', xtype=ncd_int, & - dim1name=namec, long_name='hillslope column index', & - ncid=nfid(t)) end if if(use_fates)then @@ -2599,7 +2596,6 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='hslp_aspect' , data=col%hill_aspect, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_col_ndx' , data=col%col_ndx, dim1name=namec, ncid=nfid(t), flag='write') endif if(use_fates)then @@ -3102,8 +3098,8 @@ subroutine hfields_1dinfo(t, mode) !call ncd_defvar(varname='cols1d_gi', xtype=ncd_int, dim1name='column', & ! long_name='1d grid index of corresponding column', ncid=ncid) - !call ncd_defvar(varname='cols1d_li', xtype=ncd_int, dim1name='column', & - ! long_name='1d landunit index of corresponding column', ncid=ncid) + call ncd_defvar(varname='cols1d_li', xtype=ncd_int, dim1name='column', & + long_name='1d landunit index of corresponding column', ncid=ncid) ! ---------------------------------------------------------------- call ncd_defvar(varname='cols1d_wtgcell', xtype=ncd_double, dim1name=namec, & @@ -3122,6 +3118,9 @@ subroutine hfields_1dinfo(t, mode) call ncd_defvar(varname='cols1d_active', xtype=ncd_log, dim1name=namec, & long_name='true => do computations on this column', ncid=ncid) + call ncd_defvar(varname='cols1d_nbedrock', xtype=ncd_int, dim1name=namec, & + long_name='column bedrock depth index', ncid=ncid) + ! Define patch info call ncd_defvar(varname='pfts1d_lon', xtype=ncd_double, dim1name=namep, & @@ -3253,6 +3252,10 @@ subroutine hfields_1dinfo(t, mode) ! --- EBK Do NOT write out indices that are incorrect 4/1/2011 Bug 1310 !call ncd_io(varname='cols1d_gi' , data=col%gridcell, dim1name=namec, ncid=ncid, flag='write') !call ncd_io(varname='cols1d_li' , data=col%landunit, dim1name=namec, ncid=ncid, flag='write') + do c = bounds%begc,bounds%endc + icarr(c) = GetGlobalIndex(decomp_index=col%landunit(c), clmlevel=namel) + enddo + call ncd_io(varname='cols1d_li' , data=icarr , dim1name=namec, ncid=ncid, flag='write') ! ---------------------------------------------------------------- call ncd_io(varname='cols1d_wtgcell', data=col%wtgcell , dim1name=namec, ncid=ncid, flag='write') call ncd_io(varname='cols1d_wtlunit', data=col%wtlunit , dim1name=namec, ncid=ncid, flag='write') @@ -3264,6 +3267,7 @@ subroutine hfields_1dinfo(t, mode) call ncd_io(varname='cols1d_itype_lunit', data=icarr , dim1name=namec, ncid=ncid, flag='write') call ncd_io(varname='cols1d_active' , data=col%active , dim1name=namec, ncid=ncid, flag='write') + call ncd_io(varname='cols1d_nbedrock', data=col%nbedrock , dim1name=namec, ncid=ncid, flag='write') ! Write patch info From 6b326104ab9b29f12e0f18e1e3f7e217011e19e4 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 23 Oct 2018 12:32:13 -0600 Subject: [PATCH 023/153] add ncol minimum in subgridMod --- src/biogeophys/HydrologyDrainageMod.F90 | 2 ++ src/main/subgridMod.F90 | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 36eac88093..f03a15e817 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -121,6 +121,7 @@ subroutine HydrologyDrainage(bounds, & qflx_surf => waterflux_inst%qflx_surf_col , & ! surface runoff (mm H2O /s) qflx_infl => waterflux_inst%qflx_infl_col , & ! infiltration (mm H2O /s) qflx_qrgwl => waterflux_inst%qflx_qrgwl_col , & ! qflx_surf at glaciers, wetlands, lakes + qflx_latflow_out => waterflux_inst%qflx_latflow_out_col , & ! lateral subsurface outflow (mm H2O/s) qflx_runoff => waterflux_inst%qflx_runoff_col , & ! total runoff ! (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) qflx_runoff_u => waterflux_inst%qflx_runoff_u_col , & ! Urban total runoff (qflx_drain+qflx_surf) (mm H2O /s) @@ -199,6 +200,7 @@ subroutine HydrologyDrainage(bounds, & if (lun%itype(l)==istwet .or. lun%itype(l)==istice_mec) then + qflx_latflow_out(c) = 0._r8 qflx_drain(c) = 0._r8 qflx_drain_perched(c) = 0._r8 qflx_h2osfc_surf(c) = 0._r8 diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 15e5e6fc37..3d6771db3a 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -156,13 +156,14 @@ subroutine subgrid_get_info_natveg(gi, ncohorts, npatches, ncols, nlunits) nlunits = 1 if(use_hillslope) then - ncols = nhillcol(gi) + ! ensure ncols is > 0 + ncols = max(nhillcol(gi),1) else ncols = 1 endif npatches = ncols*natpft_size -! write(iulog,*) 'nhillslope, nhillcol, ncols:', nhillslope, nhillcol(gi), ncols +! write(iulog,*) 'nhillcol, ncols, npatches:', nhillcol(gi), ncols, npatches ! ------------------------------------------------------------------------- ! Number of cohorts is set here From 51247fa92cabbeb8cd3cb16bd8b3d09c988ccca3 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 24 Oct 2018 11:15:29 -0600 Subject: [PATCH 024/153] fix tdepth --- src/biogeophys/HydrologyDrainageMod.F90 | 1 + src/biogeophys/SoilHydrologyMod.F90 | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 61f59f1d68..de8c741730 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -124,6 +124,7 @@ subroutine HydrologyDrainage(bounds, & qflx_infl => waterfluxbulk_inst%qflx_infl_col , & ! infiltration (mm H2O /s) qflx_qrgwl => waterfluxbulk_inst%qflx_qrgwl_col , & ! qflx_surf at glaciers, wetlands, lakes qflx_runoff => waterfluxbulk_inst%qflx_runoff_col , & ! total runoff + qflx_latflow_out => waterfluxbulk_inst%qflx_latflow_out_col , & ! lateral subsurface flow ! (qflx_drain+qflx_surf+qflx_qrgwl) (mm H2O /s) qflx_runoff_u => waterfluxbulk_inst%qflx_runoff_u_col , & ! Urban total runoff (qflx_drain+qflx_surf) (mm H2O /s) qflx_runoff_r => waterfluxbulk_inst%qflx_runoff_r_col , & ! Rural total runoff diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index eee9708979..db03a37f1f 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2518,9 +2518,6 @@ subroutine LateralFlowHillslope(bounds, & tdepth => atm2lnd_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) tdepth_bankfull => atm2lnd_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) - tdepth => atm2lnd_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) - tdepth_bankfull => atm2lnd_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) - depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) Dsmax => soilhydrology_inst%dsmax_col , & ! Input: [real(r8) (:) ] max. velocity of baseflow (mm/day) From 77e1cd3b04c2a383a74a0467492db5624eb38367 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 3 Apr 2019 10:21:12 -0600 Subject: [PATCH 025/153] update externals to point to hillslope_hydrology cime and mosart branches --- Externals.cfg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Externals.cfg b/Externals.cfg index 723e6d98fd..9d2515bee5 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -22,15 +22,15 @@ required = True [mosart] local_path = components/mosart protocol = git -repo_url = https://github.com/ESCOMP/mosart -tag = release-cesm2.0.00 +repo_url = https://github.com/swensosc/mosart +branch = pass_tdepth required = True [cime] local_path = cime protocol = git -repo_url = https://github.com/ESMCI/cime -tag = ctsm/ctsm1.0/cime5.7.9/n01 +repo_url = https://github.com/swensosc/cime +branch = hillslope_hydrology required = True [externals_description] From b2e4b74ff2c99ad8550ce2bed590ef2c995eb4ab Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 3 Apr 2019 10:35:07 -0600 Subject: [PATCH 026/153] update CLMBuildNamelist.pm for hillslope_hydrology_inparm --- bld/CLMBuildNamelist.pm | 4 +--- src/biogeophys/BalanceCheckMod.F90 | 2 -- src/biogeophys/SoilHydrologyMod.F90 | 5 ++++- src/cpl/lnd_import_export.F90 | 4 ++++ src/main/clm_initializeMod.F90 | 2 +- src/main/clm_instMod.F90 | 2 +- src/main/histFileMod.F90 | 4 ++-- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 0eacb5c5c7..82cfe18583 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -2837,9 +2837,7 @@ sub setup_logic_hillslope { # my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; - if ( $physv->as_long() >= $physv->as_long("clm4_5") ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); - } } #------------------------------------------------------------------------------- @@ -3569,7 +3567,7 @@ sub write_output_files { soilhydrology_inparm luna friction_velocity mineral_nitrogen_dynamics soilwater_movement_inparm rooting_profile_inparm soil_resis_inparm bgc_shared canopyfluxes_inparm aerosol - clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm + clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm hillslope_hydrology_inparm cnprecision_inparm clm_glacier_behavior crop irrigation_inparm water_tracers_inparm); diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index d1d01595be..7ca04dce46 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -276,7 +276,6 @@ subroutine BalanceCheck( bounds, & !----------------------------------------------------------------------- associate( & - volr => wateratm2lndbulk_inst%volr_grc , & ! Input: [real(r8) (:) ] river water storage (m3) forc_solad_col => atm2lnd_inst%forc_solad_col , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (vis=forc_solsd, nir=forc_solld) @@ -477,7 +476,6 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'qflx_glcice_dyn_water_flux = ', qflx_glcice_dyn_water_flux(indexc)*dtime write(iulog,*)'qflx_snwcp_discarded_ice = ',qflx_snwcp_discarded_ice(indexc)*dtime write(iulog,*)'qflx_snwcp_discarded_liq = ',qflx_snwcp_discarded_liq(indexc)*dtime - write(iulog,*)'qflx_rootsoi_col(1:nlevsoil) = ',qflx_rootsoi_col(indexc,:)*dtime write(iulog,*)'cold/colu = ',col%cold(indexc),col%colu(indexc) write(iulog,*)'clm model is stopping' call endrun(decomp_index=indexc, clmlevel=namec, msg=errmsg(sourcefile, __LINE__)) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index d2a01ff87c..d7dc64be73 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2618,7 +2618,10 @@ subroutine LateralFlowHillslope(bounds, & ! flow between channel and lowest column ! bankfull height is defined to be zero dgrad = (col%hill_elev(c)-zwt(c)) & - - (tdepth(g) - tdepth_bankfull(g)) +! - (tdepth(g) - tdepth_bankfull(g)) + ! ignore overbankfull storage + - min((tdepth(g) - tdepth_bankfull(g)),0._r8) + dgrad = dgrad / (col%hill_distance(c)) ! dgrad cannot be negative when channel is empty if (tdepth(g) <= 0._r8) then diff --git a/src/cpl/lnd_import_export.F90 b/src/cpl/lnd_import_export.F90 index aa6f1ca2d3..7595e818b5 100644 --- a/src/cpl/lnd_import_export.F90 +++ b/src/cpl/lnd_import_export.F90 @@ -10,6 +10,8 @@ module lnd_import_export use Waterlnd2atmBulkType , only: waterlnd2atmbulk_type use Wateratm2lndBulkType , only: wateratm2lndbulk_type use clm_cpl_indices +!scs + use GridcellType , only : grc ! implicit none !=============================================================================== @@ -423,6 +425,8 @@ subroutine lnd_export( bounds, waterlnd2atmbulk_inst, lnd2atm_inst, lnd2glc_inst end if end do write(iulog,*) 'gridcell index = ', g +!scs + write(iulog,*) 'lon/lat = ', grc%londeg(g), grc%latdeg(g) call endrun( sub//' ERROR: One or more of the output from CLM to the coupler are NaN ' ) end if diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 5272447694..5a3563d955 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -14,7 +14,7 @@ module clm_initializeMod use clm_varctl , only : iulog use clm_varctl , only : use_lch4, use_cn, use_cndv, use_c13, use_c14, use_fates use clm_varctl , only : nhillslope - use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft, irrig_method, wt_glc_mec, topo_glc_mec + use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft, irrig_method, wt_glc_mec, topo_glc_mec, nhillcol use perf_mod , only : t_startf, t_stopf use readParamsMod , only : readParameters use ncdio_pio , only : file_desc_t diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 907a1afb4c..4547a7c497 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -180,7 +180,7 @@ end subroutine clm_instReadNML subroutine clm_instInit(bounds) ! ! !USES: - use clm_varpar , only : nlevsno, numpft + use clm_varpar , only : nlevsno use controlMod , only : nlfilename, fsurdat use domainMod , only : ldomain use SoilBiogeochemDecompCascadeBGCMod , only : init_decompcascade_bgc diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index ab3f1950ad..baa5a12ee6 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -3493,7 +3493,7 @@ subroutine hist_htapes_wrapup( rstwr, nlend, bounds, & call htape_timeconst(t, mode='define') ! Define 3D time-constant field variables on first history tapes - if ( do_3Dtconst) then + if ( do_3Dtconst .and. t == 1) then call htape_timeconst3D(t, & bounds, watsat_col, sucsat_col, bsw_col, hksat_col, mode='define') TimeConst3DVars_Filename = trim(locfnh(t)) @@ -3512,7 +3512,7 @@ subroutine hist_htapes_wrapup( rstwr, nlend, bounds, & call htape_timeconst(t, mode='write') ! Write 3D time constant history variables to first history tapes - if ( do_3Dtconst .and. tape(t)%ntimes == 1 )then + if ( do_3Dtconst .and. t == 1 .and. tape(t)%ntimes == 1 )then call htape_timeconst3D(t, & bounds, watsat_col, sucsat_col, bsw_col, hksat_col, mode='write') do_3Dtconst = .false. From 8387050a707a667b43e748f06121b1b64bd88da2 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 4 Apr 2019 09:15:15 -0600 Subject: [PATCH 027/153] initialize column level direct solar forcing --- src/main/atm2lndMod.F90 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index b97cb5cf28..5d97a29379 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -158,13 +158,15 @@ subroutine downscale_forcings(bounds, & forc_q_g => wateratm2lndbulk_inst%forc_q_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric specific humidity (kg/kg) forc_pbot_g => atm2lnd_inst%forc_pbot_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric pressure (Pa) forc_rho_g => atm2lnd_inst%forc_rho_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric density (kg/m**3) + forc_solad_g => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation ! Column-level downscaled fields: forc_t_c => atm2lnd_inst%forc_t_downscaled_col , & ! Output: [real(r8) (:)] atmospheric temperature (Kelvin) forc_th_c => atm2lnd_inst%forc_th_downscaled_col , & ! Output: [real(r8) (:)] atmospheric potential temperature (Kelvin) forc_q_c => wateratm2lndbulk_inst%forc_q_downscaled_col , & ! Output: [real(r8) (:)] atmospheric specific humidity (kg/kg) forc_pbot_c => atm2lnd_inst%forc_pbot_downscaled_col , & ! Output: [real(r8) (:)] atmospheric pressure (Pa) - forc_rho_c => atm2lnd_inst%forc_rho_downscaled_col & ! Output: [real(r8) (:)] atmospheric density (kg/m**3) + forc_rho_c => atm2lnd_inst%forc_rho_downscaled_col , & ! Output: [real(r8) (:)] atmospheric density (kg/m**3) + forc_solad_c => atm2lnd_inst%forc_solad_col & ! Output: [real(r8) (:)] column direct incoming solar radiation ) ! Initialize column forcing (needs to be done for ALL active columns) @@ -177,6 +179,7 @@ subroutine downscale_forcings(bounds, & forc_q_c(c) = forc_q_g(g) forc_pbot_c(c) = forc_pbot_g(g) forc_rho_c(c) = forc_rho_g(g) + forc_solad_c(c,1:numrad) = forc_solad_g(g,1:numrad) end if end do From 5f54a18fede0390f767447b879729042b099fdec Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 21 Apr 2020 08:08:29 -0600 Subject: [PATCH 028/153] remove analytical hillslope methods --- bld/CLMBuildNamelist.pm | 14 - bld/namelist_files/namelist_defaults_ctsm.xml | 4 - .../namelist_definition_ctsm.xml | 5 - src/biogeophys/HillslopeHydrologyBaseMod.F90 | 200 ----- .../HillslopeHydrologyFactoryMod.F90 | 129 --- .../HillslopeHydrologyIndependentMod.F90 | 404 ---------- src/biogeophys/HillslopeHydrologyMod.F90 | 759 ++++++++++++++---- .../HillslopeHydrologySurfaceDataMod.F90 | 632 --------------- .../HillslopeHydrologyTroch02Mod.F90 | 432 ---------- src/biogeophys/HydrologyDrainageMod.F90 | 26 +- src/biogeophys/SoilHydrologyMod.F90 | 642 ++++++++++----- src/biogeophys/SurfaceAlbedoMod.F90 | 7 +- src/main/ColumnType.F90 | 2 - src/main/GridcellType.F90 | 3 - src/main/clm_driver.F90 | 2 - src/main/clm_initializeMod.F90 | 16 +- src/main/clm_instMod.F90 | 13 +- src/main/clm_varctl.F90 | 2 +- src/main/clm_varsur.F90 | 2 +- src/main/filterMod.F90 | 35 +- src/main/initHillslopeMod.F90 | 188 ----- src/main/subgridMod.F90 | 4 +- src/main/surfrdMod.F90 | 18 +- 23 files changed, 1086 insertions(+), 2453 deletions(-) delete mode 100644 src/biogeophys/HillslopeHydrologyBaseMod.F90 delete mode 100644 src/biogeophys/HillslopeHydrologyFactoryMod.F90 delete mode 100644 src/biogeophys/HillslopeHydrologyIndependentMod.F90 delete mode 100644 src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 delete mode 100644 src/biogeophys/HillslopeHydrologyTroch02Mod.F90 delete mode 100644 src/main/initHillslopeMod.F90 diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 82cfe18583..dcb889b540 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1611,11 +1611,6 @@ sub process_namelist_inline_logic { ############################################# setup_logic_soil_resis($opts, $nl_flags, $definition, $defaults, $nl); - ############################################# - # namelist group: hillslope_hydrology_inparm # - ############################################# - setup_logic_hillslope_hydrology($opts, $nl_flags, $definition, $defaults, $nl); - ############################################# # namelist group: canopyfluxes_inparm # ############################################# @@ -3381,15 +3376,6 @@ sub setup_logic_soil_resis { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'soil_resis_method' ); } -#------------------------------------------------------------------------------- - -sub setup_logic_hillslope_hydrology { - # - my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_geomorphology' ); -} -#------------------------------------------------------------------------------- sub setup_logic_canopyfluxes { # diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index afd3d73467..fdc6975eb6 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -144,10 +144,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 1 0 - -independent -independent - 1.d-2 0.001d00 diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 53dff2e6bb..4de785e737 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -184,11 +184,6 @@ Changes soil evaporative resistance method from Sakaguchi and Zeng formulation (1). - -Equation set used to derive hillslope geomorphology - - The method type to use for CNFire diff --git a/src/biogeophys/HillslopeHydrologyBaseMod.F90 b/src/biogeophys/HillslopeHydrologyBaseMod.F90 deleted file mode 100644 index 0e2916eb58..0000000000 --- a/src/biogeophys/HillslopeHydrologyBaseMod.F90 +++ /dev/null @@ -1,200 +0,0 @@ -module HillslopeHydrologyBaseMod - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Calculate geomorphological quantities for hillslope columns. - ! - ! !USES: -#include "shr_assert.h" - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use spmdMod , only : masterproc - use abortutils , only : endrun - use clm_varctl , only : iulog - use decompMod , only : bounds_type - - implicit none - private - save - - !----------------------------------------------------------------------- - - ! !PUBLIC TYPES: - type, abstract, public :: hillslope_geomorphology_type - private - ! variable declarations - - contains - ! procedure declarations - procedure (Init_interface) , deferred :: Init - procedure (hcol_width_interface) , deferred :: hcol_width - procedure (hcol_elevation_interface), deferred :: hcol_elevation - procedure (hcol_slope_interface) , deferred :: hcol_slope - procedure :: hcol_distance - procedure :: hcol_area - - end type hillslope_geomorphology_type - - !----------------------------------------------------------------------- - - abstract interface - - subroutine Init_interface(this,bounds,fsurdat) - ! - ! !DESCRIPTION: - ! Initialize hillslope geomorphology - ! - ! !USES: - - use decompMod, only : bounds_type - import hillslope_geomorphology_type - - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_type), intent(inout) :: this - type(bounds_type), intent(in) :: bounds - character(len=*) , intent(in) :: fsurdat ! surface data file name - end subroutine Init_interface - - function hcol_width_interface(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) - ! - ! !DESCRIPTION: - ! Returns width of hillslope column. - ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8 - import hillslope_geomorphology_type - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_type) , intent(in) :: this - real(r8) :: width ! function result - real(r8), intent(in) :: x ! distance along hillslope - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - - end function hcol_width_interface - - !----------------------------------------------------------------------- - function hcol_slope_interface(this,xtop,xbottom,alpha, hill_length, hill_height) result(slope) - ! - ! !DESCRIPTION: - ! Returns mean along-hillslope slope of hillslope column - ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8 - import hillslope_geomorphology_type - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_type) , intent(in) :: this - real(r8) :: slope ! function result - real(r8), intent(in) :: xtop ! distance to upper edge of column - real(r8), intent(in) :: xbottom ! distance to lower edge of column - real(r8), intent(in) :: alpha ! hillslope profile curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_height ! total hillslope height - end function hcol_slope_interface - - !----------------------------------------------------------------------- - - function hcol_elevation_interface(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) - ! - ! !DESCRIPTION: - ! Returns mean elevation of column (relative to hillslope bottom). - ! Area-weighted mean elevation is calculated by - ! numerically integrating using hcol_width function. ! - ! !USES: - use shr_kind_mod , only : r8 => shr_kind_r8 - import hillslope_geomorphology_type - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_type) , intent(in) :: this - real(r8) :: elev ! function result - real(r8), intent(in) :: xtop ! upper integration limit - real(r8), intent(in) :: xbottom ! lower integration limit - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - - end function hcol_elevation_interface - - end interface - -! PRIVATE - character(len=*), parameter, private :: sourcefile = & - __FILE__ - -contains - - !----------------------------------------------------------------------- - function hcol_distance(this, c, ctop, cbottom, hill_length) result(x) - ! - ! !DESCRIPTION: - ! Returns distance from the bottom of the hillslope of the - ! column's node. Assumes hilltop to hillbottom column - ! ordering based on lun%coli, lun%colf (see initHillslopeMod). - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_type) , intent(in) :: this - real(r8) :: x ! function result - integer, intent(in) :: c ! current column - integer, intent(in) :: ctop ! hillslope top column - integer, intent(in) :: cbottom ! hillslope bottom column - real(r8), intent(in) :: hill_length ! total hillslope length - ! - ! !LOCAL VARIABLES: - - character(len=*), parameter :: subname = 'hcol_distance' - !----------------------------------------------------------------------- - - x = hill_length * (real(cbottom - c,r8) +0.5_r8) & - / real(cbottom - ctop + 1,r8) - - end function hcol_distance - - !----------------------------------------------------------------------- - function hcol_area(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(area) - ! - ! !DESCRIPTION: - ! Returns area of a hillslope column. Area is calculated by - ! numerically integrating using hcol_width function. - ! - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_type) , intent(in) :: this - real(r8) :: area ! function result - real(r8), intent(in) :: xtop ! upper integration limit - real(r8), intent(in) :: xbottom ! lower integration limit - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - integer :: n - integer, parameter :: ndiv = 100 - real(r8) :: x - real(r8) :: dx - character(len=*), parameter :: subname = 'hcol_area' - !----------------------------------------------------------------------- - ! surface area of column - dx = (xtop - xbottom)/real(ndiv) - - area = 0._r8 - do n = 0, ndiv-1 - x = xbottom + (n+0.5)*dx - area = area + dx * this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) - enddo - - end function hcol_area - -end module HillslopeHydrologyBaseMod diff --git a/src/biogeophys/HillslopeHydrologyFactoryMod.F90 b/src/biogeophys/HillslopeHydrologyFactoryMod.F90 deleted file mode 100644 index 5084370341..0000000000 --- a/src/biogeophys/HillslopeHydrologyFactoryMod.F90 +++ /dev/null @@ -1,129 +0,0 @@ -module HillslopeHydrologyFactoryMod - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Calculate geomorphological quantities for hillslope columns. - ! - ! !USES: -#include "shr_assert.h" - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use spmdMod , only : masterproc - use abortutils , only : endrun - use clm_varctl , only : iulog, use_hillslope - use decompMod , only : bounds_type - implicit none - private - save - -! namelist variable specifying geomorphology defining equation set - character(len=256) :: hillslope_geomorphology - - !----------------------------------------------------------------------- - - ! !PUBLIC ROUTINES - public :: create_and_init_hillslope_geomorphology_type - - ! !PRIVATE ROUTINES - private :: hillslope_geomorphology_readNL - -contains - - function create_and_init_hillslope_geomorphology_type(bounds) result(hg) - ! - ! !DESCRIPTION: - ! Create and initialize an object of hillslope_geomorphology_type, - ! and return this object. The particular type is determined based on - ! the use_hillslope namelist parameter. - ! - ! !USES: - use controlMod , only : NLFilename - use clm_varctl , only : use_hillslope, fsurdat - use HillslopeHydrologyBaseMod , only : hillslope_geomorphology_type - use HillslopeHydrologySurfaceDataMod , only : hillslope_geomorphology_surfacedata_type - use HillslopeHydrologyIndependentMod , only : hillslope_geomorphology_independent_type - use HillslopeHydrologyTroch02Mod , only : hillslope_geomorphology_troch02_type - - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_type), allocatable :: hg ! function result - type(bounds_type), intent(in) :: bounds - - !----------------------------------------------------------------- - - call hillslope_geomorphology_readNL(NLFilename) - - select case (trim(hillslope_geomorphology)) - case ('surfacedata') - allocate(hg, source = hillslope_geomorphology_surfacedata_type()) - case ('independent') - allocate(hg, source = hillslope_geomorphology_independent_type()) - case ('troch02') - allocate(hg, source = hillslope_geomorphology_troch02_type()) - - end select - - call hg%Init(bounds, fsurdat) - - end function create_and_init_hillslope_geomorphology_type - - !----------------------------------------------------------------------- - subroutine hillslope_geomorphology_readNL(NLFilename) - ! - !DESCRIPTIONS - ! Read the namelist for soil resistance method - ! - ! !USES: - use abortutils , only : endrun - use fileutils , only : getavu, relavu - use spmdMod , only : mpicom, masterproc - use shr_mpi_mod , only : shr_mpi_bcast - use clm_varctl , only : iulog - use clm_nlUtilsMod , only : find_nlgroup_name - - ! !ARGUMENTS: - !------------------------------------------------------------------------------ - implicit none - character(len=*), intent(IN) :: NLFilename ! Namelist filename - integer :: nu_nml ! unit for namelist file - integer :: nml_error ! namelist i/o error flag - character(*), parameter :: subName = "('hillslope_geomorphology_readNL')" - - !----------------------------------------------------------------------- - -! MUST agree with name in namelist and read statement - namelist /hillslope_hydrology_inparm/ hillslope_geomorphology - - ! Default values for namelist - - hillslope_geomorphology = 'surfacedata' - - ! Read soil_resis namelist - if (masterproc) then - nu_nml = getavu() - open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) - call find_nlgroup_name(nu_nml, 'hillslope_hydrology_inparm', status=nml_error) - if (nml_error == 0) then - read(nu_nml, nml=hillslope_hydrology_inparm,iostat=nml_error) - if (nml_error /= 0) then - call endrun(subname // ':: ERROR reading hillslope_hydrology namelist') - end if - else - call endrun(subname // ':: ERROR reading hillslope_hydrology namelist') - end if - close(nu_nml) - call relavu( nu_nml ) - - endif - - call shr_mpi_bcast(hillslope_geomorphology, mpicom) - - if (masterproc) then - write(iulog,*) ' ' - write(iulog,*) 'hillslope hydrology settings:' - write(iulog,*) ' hillslope_geomorphology = ',hillslope_geomorphology - endif - - end subroutine hillslope_geomorphology_readNL - -end module HillslopeHydrologyFactoryMod diff --git a/src/biogeophys/HillslopeHydrologyIndependentMod.F90 b/src/biogeophys/HillslopeHydrologyIndependentMod.F90 deleted file mode 100644 index cddc0a2911..0000000000 --- a/src/biogeophys/HillslopeHydrologyIndependentMod.F90 +++ /dev/null @@ -1,404 +0,0 @@ -module HillslopeHydrologyIndependentMod - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Calculate geomorphological quantities for hillslope columns - ! assuming independent profile and plan shapes. - ! - ! !USES: -#include "shr_assert.h" - use shr_kind_mod , only : r8 => shr_kind_r8 - use HillslopeHydrologyBaseMod, only : hillslope_geomorphology_type - use shr_log_mod , only : errMsg => shr_log_errMsg - use spmdMod , only : masterproc - use abortutils , only : endrun - use clm_varctl , only : iulog - use decompMod , only : bounds_type - - implicit none - private - save - - ! PRIVATE - character(len=*), parameter, private :: sourcefile = & - __FILE__ - - ! !PUBLIC TYPES: - - type, extends(hillslope_geomorphology_type), public :: & - hillslope_geomorphology_independent_type - private - - ! variable declarations - - contains - - procedure :: Init - procedure :: hcol_width - procedure :: hcol_elevation - procedure :: hcol_slope - - end type hillslope_geomorphology_independent_type - - !----------------------------------------------------------------------- - interface hillslope_geomorphology_independent_type - - end interface hillslope_geomorphology_independent_type - - - !----------------------------------------------------------------------- - -contains - - !----------------------------------------------------------------------- - function hcol_width(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) - ! - ! !DESCRIPTION: - ! Returns width of hillslope column. - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_independent_type) , intent(in) :: this - real(r8) :: width ! function result - real(r8), intent(in) :: x ! distance along hillslope - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - real(r8) :: eps = 1.e-6_r8 - real(r8) :: x0,y0,yl ! integration limits - real(r8) :: slope, intercept - character(len=*), parameter :: subname = 'hcol_width' - !----------------------------------------------------------------------- - - ! width varies linearly with distance - - ! divergent -! y0 = hill_width/2._r8 -! yl = 0.25_r8 * yl - ! convergent - yl = hill_width/2._r8 - y0 = 0.1_r8 * yl -! y0 = 1.0_r8 * yl - - slope = (yl - y0)/(hill_length) - intercept = y0 - width = slope*x + intercept - - ! hillslope width is twice integral [0:x] - width = 2._r8 * width - - end function hcol_width - - !----------------------------------------------------------------------- - function hcol_elevation(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) - ! - ! !DESCRIPTION: - ! Returns mean elevation of column (relative to hillslope bottom). - ! Area-weighted mean elevation is calculated by - ! numerically integrating using hcol_width function. ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_independent_type) , intent(in) :: this - real(r8) :: elev ! function result - real(r8), intent(in) :: xtop ! upper integration limit - real(r8), intent(in) :: xbottom ! lower integration limit - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - - integer :: n - integer, parameter :: ndiv = 100 - real(r8) :: x, y - real(r8) :: dx - real(r8) :: dA - real(r8) :: area - character(len=*), parameter :: subname = 'hcol_elevation' - !----------------------------------------------------------------------- - ! mean elevation of column relative to hillslope bottom - ! elevation is considered 1-d - - dx = (xtop - xbottom)/real(ndiv) - - elev = 0._r8 - area = 0._r8 - do n = 0, ndiv-1 - x = xbottom + (n+0.5)*dx - y = this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) - dA = dx * y - area = area + dA - elev = elev + dx * y * hill_height*(x/hill_length)**alpha - enddo - elev = elev / area - - end function hcol_elevation - - !----------------------------------------------------------------------- - function hcol_slope(this,xtop,xbottom,alpha, hill_length, hill_height) result(slope) - ! - ! !DESCRIPTION: - ! Returns mean along-hillslope slope of hillslope column - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_independent_type) , intent(in) :: this - real(r8) :: slope ! function result - real(r8), intent(in) :: xtop ! distance to upper edge of column - real(r8), intent(in) :: xbottom ! distance to lower edge of column - real(r8), intent(in) :: alpha ! hillslope profile curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - - character(len=*), parameter :: subname = 'hcol_slope' - !----------------------------------------------------------------------- - - ! mean along-hill slope of column - slope = hill_height & - * ((xtop/hill_length)**alpha & - - (xbottom/hill_length)**alpha) & - / (xtop - xbottom) - - end function hcol_slope - - !----------------------------------------------------------------------- - - subroutine Init(this,bounds,fsurdat) - ! - ! !DESCRIPTION: - ! Initialize hillslope geomorphology - ! - ! !USES: - use LandunitType , only : lun - use GridcellType , only : grc - use ColumnType , only : col - use clm_varctl , only : nhillslope - use clm_varcon , only : zmin_bedrock, zisoi - use clm_varpar , only : nlevsoi - use spmdMod , only : masterproc - use fileutils , only : getfil - use clm_varcon , only : spval, ispval, grlnd - use landunit_varcon , only : istsoil - use ncdio_pio - - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_independent_type) , intent(inout) :: this - type(bounds_type), intent(in) :: bounds - character(len=*) , intent(in) :: fsurdat ! surface data file name - real(r8), pointer :: ihillslope_in(:,:) ! read in - integer - real(r8), pointer :: fhillslope_in(:,:) ! read in - float - integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope - real(r8), allocatable :: hill_alpha(:,:) ! hillslope 'alpha' parameter - real(r8), allocatable :: hill_beta(:,:) ! hillslope 'beta' parameter - real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] - real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] - real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] - - type(file_desc_t) :: ncid ! netcdf id - logical :: readvar ! check whether variable on file - character(len=256) :: locfn ! local filename - integer :: ierr ! error code - integer :: c, l, g, j, nh ! indices - - real(r8) :: hillslope_area ! total area of hillslope - real(r8) :: column_length ! length of column [m] - real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope - real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope - integer :: ctop, cbottom ! hillslope top and bottom column indices - - character(len=*), parameter :: subname = 'Init' - - !----------------------------------------------------------------------- - - ! Open surface dataset to read in data below - - call getfil (fsurdat, locfn, 0) - call ncd_pio_openfile (ncid, locfn, 0) - - allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & - hill_alpha(bounds%begl:bounds%endl,nhillslope), & - hill_beta(bounds%begl:bounds%endl,nhillslope), & - hill_length(bounds%begl:bounds%endl,nhillslope), & - hill_width(bounds%begl:bounds%endl,nhillslope), & - hill_height(bounds%begl:bounds%endl,nhillslope), & - stat=ierr) - - allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) - - call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - pct_hillslope(l,:) = ihillslope_in(g,:) - enddo - deallocate(ihillslope_in) - - allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) - call ncd_io(ncid=ncid, varname='h_alpha', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_alpha not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_alpha(l,:) = fhillslope_in(g,:) - enddo -!scs -hill_alpha = 4 - - call ncd_io(ncid=ncid, varname='h_beta', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_beta not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_beta(l,:) = fhillslope_in(g,:) - enddo - call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_length(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_width(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_height(l,:) = fhillslope_in(g,:) - enddo - deallocate(fhillslope_in) - - ! Set hillslope hydrology column level variables - ! This needs to match how columns set up in subgridMod - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - if(lun%itype(l) == istsoil) then - ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost - - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - ctop = lun%coli(l)+(nh-1)*lun%ncolumns(l)/nhillslope - cbottom = lun%coli(l)+(nh)*lun%ncolumns(l)/nhillslope - 1 - - ! distance of lower edge of column from hillslope bottom - col%hill_distance(c) = this%hcol_distance(c, & - ctop, cbottom, hill_length(l,nh)) - ! if (masterproc) write(iulog,*) 'hd: ',c,col%hill_distance(c) - - !distance of lower edge of column from hillslope bottom - column_length = hill_length(l,nh)/(lun%ncolumns(l)/nhillslope) - le_distance = col%hill_distance(c) - 0.5_r8*column_length - ue_distance = col%hill_distance(c) + 0.5_r8*column_length - - ! width of lower edge of column from hillslope bottom - col%hill_width(c) = this%hcol_width(le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'hw: ',c,col%hill_width(c) - - col%hill_area(c) = this%hcol_area(ue_distance, le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'ha: ',c,col%hill_area(c) - - ! mean elevation of column relative to mean gridcell elevation - col%hill_elev(c) = this%hcol_elevation(ue_distance, le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'he: ',c,col%hill_elev(c) - - ! mean along-hill slope of column - col%hill_slope(c) = this%hcol_slope(ue_distance, le_distance, & - hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'hs: ',c,col%hill_slope(c) - - enddo - - ! Now that column areas are determined, column weights can be recalculated - hillslope_area = 0._r8 - ! area weighted by pct_hillslope - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) - enddo - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - col%wtlunit(c) = col%hill_area(c) & - * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area - enddo - - ! Set column bedrock index - !thin soil for non-riparian columns, thick for riparian - do c = lun%coli(l), lun%colf(l) - if(col%cold(c) /= ispval) then - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then - col%nbedrock(c) = j - end if - end if - enddo - else - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then - col%nbedrock(c) = j - end if - end if - enddo - endif - end do - - endif ! end of istsoil - enddo ! end of loop over landunits - - deallocate(pct_hillslope,hill_alpha,hill_beta,hill_length, & - hill_width,hill_height) - - call ncd_pio_closefile(ncid) - - end subroutine Init - -end module HillslopeHydrologyIndependentMod diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 2d1882093b..16c781e817 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -2,7 +2,7 @@ module HillslopeHydrologyMod !----------------------------------------------------------------------- ! !DESCRIPTION: - ! Calculate geomorphological quantities for hillslope columns. + ! Read geomorphological parameters for hillslope columns ! ! !USES: #include "shr_assert.h" @@ -11,234 +11,653 @@ module HillslopeHydrologyMod use spmdMod , only : masterproc use abortutils , only : endrun use clm_varctl , only : iulog + use decompMod , only : bounds_type + use clm_varcon , only : rpi + ! !PUBLIC TYPES: implicit none private save ! !PUBLIC MEMBER FUNCTIONS: - public :: hcol_distance - public :: hcol_width - public :: hcol_area - public :: hcol_elevation - public :: hcol_slope - - - ! !PRIVATE MEMBER FUNCTIONS: -! private :: - + public InitHillslope + public HillslopeSoilThicknessProfile + public HillslopeSetLowlandUplandPfts + public HillslopeDominantPft + public HillslopeDominantLowlandPft + + ! PRIVATE character(len=*), parameter, private :: sourcefile = & __FILE__ + integer, private, parameter :: soil_profile_set_lowland_upland = 0 + integer, private, parameter :: soil_profile_linear = 1 + + !----------------------------------------------------------------------- contains - !------------------------------------------------------------------------------ - function hcol_distance(c, ctop, cbottom, hill_length) result(x) + !----------------------------------------------------------------------- + + subroutine InitHillslope(bounds,fsurdat) ! ! !DESCRIPTION: - ! Returns distance from the bottom of the hillslope of the - ! column's node. Assumes hilltop to hillbottom column - ! ordering based on lun%coli, lun%colf (see initHillslopeMod). + ! Initialize hillslope geomorphology from input dataset ! ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use clm_varctl , only : nhillslope, nmax_col_per_hill + use clm_varcon , only : zmin_bedrock, zisoi + use clm_varpar , only : nlevsoi + use spmdMod , only : masterproc + use fileutils , only : getfil + use clm_varcon , only : spval, ispval, grlnd + use landunit_varcon , only : istsoil + use ncdio_pio + ! ! !ARGUMENTS: - real(r8) :: x ! function result - integer, intent(in) :: c ! current column - integer, intent(in) :: ctop ! hillslope top column - integer, intent(in) :: cbottom ! hillslope bottom column - real(r8), intent(in) :: hill_length ! total hillslope length - ! - ! !LOCAL VARIABLES: + type(bounds_type), intent(in) :: bounds + character(len=*) , intent(in) :: fsurdat ! surface data file name + real(r8), pointer :: ihillslope_in(:,:) ! read in - integer + real(r8), pointer :: fhillslope_in(:,:) ! read in - float + integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope + integer, allocatable :: hill_ndx(:,:) ! hillslope index + integer, allocatable :: col_ndx(:,:) ! column index + integer, allocatable :: col_dndx(:,:) ! downhill column index + real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] + real(r8), allocatable :: hill_aspect(:,:) ! hillslope azimuth [radians] + real(r8), allocatable :: hill_area(:,:) ! hillslope area [m2] + real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] + real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] + real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] + + type(file_desc_t) :: ncid ! netcdf id + logical :: readvar ! check whether variable on file + character(len=256) :: locfn ! local filename + integer :: ierr ! error code + integer :: c, l, g, i, j, ci, nh ! indices + + real(r8) :: hillslope_area ! total area of hillslope + + character(len=*), parameter :: subname = 'InitHillslope' - character(len=*), parameter :: subname = 'hcol_distance' !----------------------------------------------------------------------- - x = hill_length * (real(cbottom - c,r8) +0.5_r8) & - / real(cbottom - ctop + 1,r8) + ! Open surface dataset to read in data below + + call getfil (fsurdat, locfn, 0) + call ncd_pio_openfile (ncid, locfn, 0) + + allocate( & + pct_hillslope(bounds%begl:bounds%endl,nhillslope), & + hill_ndx (bounds%begl:bounds%endl,nmax_col_per_hill), & + col_ndx (bounds%begl:bounds%endl,nmax_col_per_hill), & + col_dndx (bounds%begl:bounds%endl,nmax_col_per_hill), & + hill_slope (bounds%begl:bounds%endl,nmax_col_per_hill), & + hill_aspect (bounds%begl:bounds%endl,nmax_col_per_hill), & + hill_area (bounds%begl:bounds%endl,nmax_col_per_hill), & + hill_length (bounds%begl:bounds%endl,nmax_col_per_hill), & + hill_width (bounds%begl:bounds%endl,nmax_col_per_hill), & + hill_height (bounds%begl:bounds%endl,nmax_col_per_hill), & + stat=ierr) + + allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) + + call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + pct_hillslope(l,:) = ihillslope_in(g,:) + enddo + deallocate(ihillslope_in) + + allocate(ihillslope_in(bounds%begg:bounds%endg,nmax_col_per_hill)) + + call ncd_io(ncid=ncid, varname='hillslope_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: hillslope_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_ndx(l,:) = ihillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + col_ndx(l,:) = ihillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='downhill_column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: downhill_column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + col_dndx(l,:) = ihillslope_in(g,:) + enddo + deallocate(ihillslope_in) + + allocate(fhillslope_in(bounds%begg:bounds%endg,nmax_col_per_hill)) + call ncd_io(ncid=ncid, varname='h_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_slope(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_aspect(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_area(l,:) = fhillslope_in(g,:) + enddo + call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_length(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_width(l,:) = fhillslope_in(g,:) + enddo + + call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_height(l,:) = fhillslope_in(g,:) + enddo + deallocate(fhillslope_in) + + ! Set hillslope hydrology column level variables + ! This needs to match how columns set up in subgridMod + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + if(lun%itype(l) == istsoil) then + ! map external column index to internal column index + do c = lun%coli(l), lun%colf(l) + ! ci should span [1:nhillcolumns(l)] + ci = c-lun%coli(l)+1 + ! relative separation should be the same + if (col_dndx(l,ci) <= -999) then + ! lowermost column of hillslope has no downstream neighbor + col%cold(c) = ispval + else + col%cold(c) = c + (col_dndx(l,ci) - col_ndx(l,ci)) + endif + enddo + + do c = lun%coli(l), lun%colf(l) + ci = c-lun%coli(l)+1 + + col%hillslope_ndx(c) = hill_ndx(l,ci) + + ! Find uphill neighbors (this may not actually be useful...) + col%colu(c) = ispval + do i = lun%coli(l), lun%colf(l) + if(c == col%cold(i)) then + col%colu(c) = i + endif + enddo + + ! distance of lower edge of column from hillslope bottom + col%hill_distance(c) = hill_length(l,ci) + ! width of lower edge of column + col%hill_width(c) = hill_width(l,ci) + ! mean elevation of column relative to gridcell mean elevation + col%hill_elev(c) = hill_height(l,ci) + ! mean along-hill slope of column + col%hill_slope(c) = hill_slope(l,ci) + ! area of column + col%hill_area(c) = hill_area(l,ci) + ! azimuth of column + col%hill_aspect(c) = hill_aspect(l,ci) + enddo + + ! Calculate total (representative) hillslope area on landunit + ! weighted relative to one another via pct_hillslope + hillslope_area = 0._r8 + do c = lun%coli(l), lun%colf(l) + hillslope_area = hillslope_area & + + col%hill_area(c)*(real(pct_hillslope(l,nh),r8)*0.01_r8) + enddo + + ! if missing hillslope information on surface dataset, fill data + ! and recalculate hillslope_area + if (hillslope_area == 0._r8) then + do c = lun%coli(l), lun%colf(l) + col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6 ! km2 to m2 + col%hill_distance(c) = sqrt(col%hill_area(c)) + col%hill_width(c) = sqrt(col%hill_area(c)) + col%hill_elev(c) = col%topo_std(c) + col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) + col%hill_aspect(c) = (rpi/2.) ! east (arbitrarily chosen) + nh = col%hillslope_ndx(c) + pct_hillslope(l,nh) = 100/nhillslope + hillslope_area = hillslope_area & + + col%hill_area(c)*(real(pct_hillslope(l,nh),r8)*0.01_r8) + enddo + endif + + ! Recalculate column weights using input areas + do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) + col%wtlunit(c) = col%hill_area(c) & + * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + enddo + + endif + enddo + + deallocate(pct_hillslope,hill_ndx,col_ndx,col_dndx, & + hill_slope,hill_area,hill_length, & + hill_width,hill_height,hill_aspect) + + call ncd_pio_closefile(ncid) + + ! Modify pft distributions + !upland_ivt = 13 ! c3 non-arctic grass + !lowland_ivt = 7 ! broadleaf deciduous tree + !call HillslopeSetLowlandUplandPfts(lowland_ivt=7,upland_ivt=13) - end function hcol_distance + call HillslopeDominantPft() + + ! Modify hillslope soil thickness profile + !call HillslopeSoilThicknessProfile(bounds,& + !soil_profile_method=soil_profile_set_lowland_upland) + + end subroutine InitHillslope - function hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) result(width) + !----------------------------------------------------------------------- + subroutine HillslopeSoilThicknessProfile(bounds,soil_profile_method) ! ! !DESCRIPTION: - ! Returns width of hillslope column. + ! Modify soil thickness across hillslope by changing + ! col%nbedrock ! ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use clm_varcon , only : zmin_bedrock, zisoi + use clm_varpar , only : nlevsoi + use spmdMod , only : masterproc + use fileutils , only : getfil + use clm_varcon , only : spval, ispval, grlnd + use landunit_varcon , only : istsoil + use ncdio_pio + ! ! !ARGUMENTS: - real(r8) :: width ! function result - real(r8), intent(in) :: x ! distance along hillslope - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - real(r8) :: eps = 1.e-6_r8 - real(r8) :: x0,y0,yl ! integration limits - character(len=*), parameter :: subname = 'hcol_width' + type(bounds_type), intent(in) :: bounds + integer, intent(in) :: soil_profile_method + integer :: c, l, g, i, j + + real(r8) :: min_hill_dist, max_hill_dist + real(r8) :: m, b ! linear soil thickness slope/intercept + real(r8) :: soil_depth_col + ! soil_depth_* could be input args, but using parameters for now... + real(r8), parameter :: soil_depth_lowland = 3.0 + real(r8), parameter :: soil_depth_upland = 0.5 + + character(len=*), parameter :: subname = 'HillslopeSoilThicknessProfile' + !----------------------------------------------------------------------- - ! width function has special case for n = 2 - ! in this implementation, integration limits depend on sign of beta - if (abs(alpha - 2._r8) < eps) then - - ! function blows up for x0=0; integration limits set by trial and error - if(beta < 0._r8) then - y0 = hill_width/2._r8 - yl = 0.1_r8 - x0=hill_length *(yl/y0)**(-hill_height/(beta*hill_length**2)) - else - x0 = 0.2_r8 - y0 = (hill_width/2._r8)& - *(x0/hill_length)**(beta*hill_length**2/hill_height) - endif + do l = bounds%begl,bounds%endl + if(lun%itype(l) == istsoil) then + ! Specify lowland/upland soil thicknesses separately + if(soil_profile_method == soil_profile_set_lowland_upland) then + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) /= ispval) then + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < soil_depth_upland .and. zisoi(j) >= soil_depth_upland) then + col%nbedrock(c) = j + end if + end if + enddo + else + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < soil_depth_lowland .and. zisoi(j) >= soil_depth_lowland) then + col%nbedrock(c) = j + end if + end if + enddo + endif + end do + endif + + ! Linear soil thickness profile + if(soil_profile_method == soil_profile_linear) then - ! compiler does not like log(zero) - if (x == 0._r8) then - if (beta < 0._r8) then - width = hill_width/2._r8 - else - width = eps + min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) + max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) + m = (soil_depth_lowland - soil_depth_upland)/ & + (max_hill_dist - min_hill_dist) + b = soil_depth_upland + + do c = lun%coli(l), lun%colf(l) + soil_depth_col = m*(max_hill_dist - col%hill_distance(c)) + b + + do j = 1,nlevsoi + if ((zisoi(j-1) < soil_depth_col) .and. (zisoi(j) >= soil_depth_col)) then + col%nbedrock(c) = j + end if + enddo + enddo endif - else - width = y0*(x/x0)**(beta*hill_length**2/hill_height) - endif - else - ! alpha /= 2 case, x0 equals zero - y0 = hill_width/2._r8 - if(beta > 0._r8) then - y0 = y0 * exp(-(2._r8*beta*hill_length**2) & - / (hill_height*(2._r8 - alpha)*alpha)) - endif - ! compiler does not like zero to a negative power. - if (x == 0._r8) then - width = y0 - else - width = y0*exp((((2._r8*beta*hill_length**2) & - / (hill_height*(2._r8 - alpha)*alpha)) & - * (x/hill_length)**(2._r8-alpha))) - endif - endif - ! hillslope width is twice integral [0:x] - width = 2._r8 * width - end function hcol_width + endif ! end of istsoil + enddo ! end of loop over landunits + + end subroutine HillslopeSoilThicknessProfile - function hcol_area(xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(area) + !------------------------------------------------------------------------ + subroutine HillslopeSetLowlandUplandPfts(lowland_ivt,upland_ivt) ! - ! !DESCRIPTION: - ! Returns area of a hillslope column. Area is calculated by - ! numerically integrating using hcol_width function. - ! + ! !DESCRIPTION: + ! Reassign patch weights such that each column has a single pft. + ! upland_ivt/lowland_ivt patches must be allocated + ! in natveg_patch_exists (subgridMod) even if zero weight on fsurdat + ! - ! !USES: + ! !USES + use LandunitType , only : lun + use ColumnType , only : col + use decompMod , only : get_clump_bounds, get_proc_clumps + use clm_varcon , only : ispval + use landunit_varcon , only : istsoil, istcrop + use PatchType , only : patch ! ! !ARGUMENTS: - real(r8) :: area ! function result - real(r8), intent(in) :: xtop ! upper integration limit - real(r8), intent(in) :: xbottom ! lower integration limit - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height ! ! !LOCAL VARIABLES: - integer :: n - integer, parameter :: ndiv = 100 - real(r8) :: x - real(r8) :: dx - character(len=*), parameter :: subname = 'hcol_area' - !----------------------------------------------------------------------- - ! surface area of column - dx = (xtop - xbottom)/real(ndiv) + integer :: n,nc,p,pu,pl,l,c ! indices + integer :: nclumps ! number of clumps on this processor + + integer, intent(in) :: upland_ivt + integer, intent(in) :: lowland_ivt + real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc + type(bounds_type) :: bounds_proc + type(bounds_type) :: bounds_clump - area = 0._r8 - do n = 0, ndiv-1 - x = xbottom + (n+0.5)*dx - area = area + dx * hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) - enddo + !------------------------------------------------------------------------ - end function hcol_area - - function hcol_elevation(xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) + nclumps = get_proc_clumps() + + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + do nc = 1, nclumps + + call get_clump_bounds(nc, bounds_clump) + + do l = bounds_clump%begl, bounds_clump%endl + + if (lun%itype(l) == istsoil) then + do c = lun%coli(l), lun%colf(l) + + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + pl = ispval + pu = ispval + do p = col%patchi(c), col%patchf(c) + if(patch%itype(p) == lowland_ivt) pl = p + if(patch%itype(p) == upland_ivt) pu = p + enddo + + ! only reweight if pfts exist within column + if (pl /= ispval .and. pu /= ispval) then + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + + ! hillbottom + if(col%cold(c) == ispval) then + patch%wtcol(pl) = sum_wtcol + patch%wtlunit(pl) = sum_wtlun + patch%wtgcell(pl) = sum_wtgrc + else + patch%wtcol(pu) = sum_wtcol + patch%wtlunit(pu) = sum_wtlun + patch%wtgcell(pu) = sum_wtgrc + endif + endif + enddo ! end loop c + endif + enddo ! end loop l + enddo ! end loop nc + !$OMP END PARALLEL DO + + end subroutine HillslopeSetLowlandUplandPfts + + !------------------------------------------------------------------------ + subroutine HillslopeDominantPft() ! - ! !DESCRIPTION: - ! Returns mean elevation of column (relative to hillslope bottom). - ! Area-weighted mean elevation is calculated by - ! numerically integrating using hcol_width function. ! - ! !USES: + ! !DESCRIPTION: + ! Reassign patch weights such that each column has a single pft + ! determined by each column's most dominant pft on input dataset. + + ! + ! !USES + use LandunitType , only : lun + use ColumnType , only : col + use decompMod , only : get_clump_bounds, get_proc_clumps + use clm_varcon , only : ispval + use landunit_varcon , only : istsoil + use PatchType , only : patch ! ! !ARGUMENTS: - real(r8) :: elev ! function result - real(r8), intent(in) :: xtop ! upper integration limit - real(r8), intent(in) :: xbottom ! lower integration limit - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height ! ! !LOCAL VARIABLES: + integer :: n,nc,p,pu,pl,l,c ! indices + integer :: nclumps ! number of clumps on this processor + integer :: pdom(1) + real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc + type(bounds_type) :: bounds_proc + type(bounds_type) :: bounds_clump - integer :: n - integer, parameter :: ndiv = 100 - real(r8) :: x, y - real(r8) :: dx - real(r8) :: dA - real(r8) :: area - character(len=*), parameter :: subname = 'hcol_elevation' - !----------------------------------------------------------------------- - ! mean elevation of column relative to hillslope bottom - ! elevation is first integrated analytically in across-slope direction - ! then summed in along-slope direction - - dx = (xtop - xbottom)/real(ndiv) - - elev = 0._r8 - area = 0._r8 - do n = 0, ndiv-1 - x = xbottom + (n+0.5)*dx - y = hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) - dA = dx * y - area = area + dA - elev = elev + dx * (hill_height*y*(x/hill_length)**alpha & - + beta*y**3/12._r8) - enddo - elev = elev / area + !------------------------------------------------------------------------ + + nclumps = get_proc_clumps() + + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + do nc = 1, nclumps + + call get_clump_bounds(nc, bounds_clump) - end function hcol_elevation + do l = bounds_clump%begl, bounds_clump%endl - function hcol_slope(xtop,xbottom,alpha, hill_length, hill_height) result(slope) + if (lun%itype(l) == istsoil) then + do c = lun%coli(l), lun%colf(l) + + pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) + pdom = pdom + (col%patchi(c) - 1) + + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + + patch%wtcol(pdom(1)) = sum_wtcol + patch%wtlunit(pdom(1)) = sum_wtlun + patch%wtgcell(pdom(1)) = sum_wtgrc + enddo ! end loop c + endif + enddo ! end loop l + enddo ! end loop nc + !$OMP END PARALLEL DO + + end subroutine HillslopeDominantPft + + !------------------------------------------------------------------------ + subroutine HillslopeDominantLowlandPft() ! - ! !DESCRIPTION: - ! Returns mean along-hillslope slope of hillslope column + ! !DESCRIPTION: + ! Reassign patch weights such that each column has a single, + ! dominant pft. Use largest weight for lowland, 2nd largest + ! weight for uplands + ! - ! !USES: + ! !USES + use LandunitType , only : lun + use ColumnType , only : col + use decompMod , only : get_clump_bounds, get_proc_clumps + use clm_varcon , only : ispval + use landunit_varcon , only : istsoil + use PatchType , only : patch ! ! !ARGUMENTS: - real(r8) :: slope ! function result - real(r8), intent(in) :: xtop ! distance to upper edge of column - real(r8), intent(in) :: xbottom ! distance to lower edge of column - real(r8), intent(in) :: alpha ! hillslope profile curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_height ! total hillslope height ! ! !LOCAL VARIABLES: + integer :: n,nc,p,pu,pl,l,c ! indices + integer :: nclumps ! number of clumps on this processor + integer :: pdom(1),psubdom(1) + integer :: plow, phigh + real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc + real(r8),allocatable :: mask(:) + type(bounds_type) :: bounds_proc + type(bounds_type) :: bounds_clump - character(len=*), parameter :: subname = 'hcol_slope' - !----------------------------------------------------------------------- + !------------------------------------------------------------------------ + + nclumps = get_proc_clumps() - ! mean along-hill slope of column - slope = hill_height & - * ((xtop/hill_length)**alpha & - - (xbottom/hill_length)**alpha) & - / (xtop - xbottom) + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + do nc = 1, nclumps + + call get_clump_bounds(nc, bounds_clump) + + do l = bounds_clump%begl, bounds_clump%endl + + if (lun%itype(l) == istsoil) then + do c = lun%coli(l), lun%colf(l) + + pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) + ! create mask to exclude pdom + allocate(mask(col%npatches(c))) + mask(:) = 1. + mask(pdom(1)) = 0. + + pdom = pdom + (col%patchi(c) - 1) + + psubdom = maxloc(mask*patch%wtcol(col%patchi(c):col%patchf(c))) + psubdom = psubdom + (col%patchi(c) - 1) + deallocate(mask) + + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + + ! assumes trees are 1-8, shrubs 9-11, and grasses 12-14 + ! and puts the lowest ivt on the lowland column + if ((patch%itype(pdom(1)) > patch%itype(psubdom(1)) & + .and. patch%itype(psubdom(1)) > 0) .or. & + (patch%itype(pdom(1)) == 0)) then + plow = psubdom(1) + phigh = pdom(1) + else + plow = pdom(1) + phigh = psubdom(1) + endif + + ! Special cases (subjective) + + ! if NET/BDT assign BDT to lowland + if ((patch%itype(pdom(1)) == 1) .and. (patch%itype(psubdom(1)) < 9)) then + plow = psubdom(1) + phigh = pdom(1) + endif + ! if C3/C4 assign C4 to lowland + if ((patch%itype(pdom(1)) == 14) .and. (patch%itype(psubdom(1)) == 13)) then + plow = pdom(1) + phigh = psubdom(1) + endif + if ((patch%itype(pdom(1)) == 13) .and. (patch%itype(psubdom(1)) == 14)) then + plow = psubdom(1) + phigh = pdom(1) + endif + + if(col%cold(c) == ispval) then + ! lowland column + patch%wtcol(plow) = sum_wtcol + patch%wtlunit(plow) = sum_wtlun + patch%wtgcell(plow) = sum_wtgrc + else + ! upland columns + patch%wtcol(phigh) = sum_wtcol + patch%wtlunit(phigh) = sum_wtlun + patch%wtgcell(phigh) = sum_wtgrc + endif + enddo ! end loop c + endif + enddo ! end loop l + enddo ! end loop nc + !$OMP END PARALLEL DO - end function hcol_slope + end subroutine HillslopeDominantLowlandPft end module HillslopeHydrologyMod diff --git a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 b/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 deleted file mode 100644 index 5a5d7007c8..0000000000 --- a/src/biogeophys/HillslopeHydrologySurfaceDataMod.F90 +++ /dev/null @@ -1,632 +0,0 @@ -module HillslopeHydrologySurfaceDataMod - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Calculate geomorphological quantities for hillslope columns - ! assuming independent profile and plan shapes. - ! - ! !USES: -#include "shr_assert.h" - use shr_kind_mod , only : r8 => shr_kind_r8 - use HillslopeHydrologyBaseMod, only : hillslope_geomorphology_type - use shr_log_mod , only : errMsg => shr_log_errMsg - use spmdMod , only : masterproc - use abortutils , only : endrun - use clm_varctl , only : iulog - use decompMod , only : bounds_type -!scs - use clm_varcon , only : rpi -!scs - implicit none - private - save - - ! PRIVATE - character(len=*), parameter, private :: sourcefile = & - __FILE__ - - ! !PUBLIC TYPES: - - type, extends(hillslope_geomorphology_type), public :: & - hillslope_geomorphology_surfacedata_type - private - - ! variable declarations - - contains - - procedure :: Init - procedure :: hcol_width - procedure :: hcol_elevation - procedure :: hcol_slope - - end type hillslope_geomorphology_surfacedata_type - - !----------------------------------------------------------------------- - interface hillslope_geomorphology_surfacedata_type - - end interface hillslope_geomorphology_surfacedata_type - - - !----------------------------------------------------------------------- - -contains - - !----------------------------------------------------------------------- - function hcol_width(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) - ! - ! !DESCRIPTION: - ! Returns width of hillslope column. - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_surfacedata_type) , intent(in) :: this - real(r8) :: width ! function result - real(r8), intent(in) :: x ! distance along hillslope - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - real(r8) :: eps = 1.e-6_r8 - real(r8) :: x0,y0,yl ! integration limits - real(r8) :: slope, intercept - character(len=*), parameter :: subname = 'hcol_width' - !----------------------------------------------------------------------- - - ! width varies linearly with distance - - ! divergent -! y0 = hill_width/2._r8 -! yl = 0.25_r8 * yl - ! convergent - yl = hill_width/2._r8 - y0 = 0.1_r8 * yl -! y0 = 1.0_r8 * yl - - slope = (yl - y0)/(hill_length) - intercept = y0 - width = slope*x + intercept - - ! hillslope width is twice integral [0:x] - width = 2._r8 * width - - end function hcol_width - - !----------------------------------------------------------------------- - function hcol_elevation(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) - ! - ! !DESCRIPTION: - ! Returns mean elevation of column (relative to hillslope bottom). - ! Area-weighted mean elevation is calculated by - ! numerically integrating using hcol_width function. ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_surfacedata_type) , intent(in) :: this - real(r8) :: elev ! function result - real(r8), intent(in) :: xtop ! upper integration limit - real(r8), intent(in) :: xbottom ! lower integration limit - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - - integer :: n - integer, parameter :: ndiv = 100 - real(r8) :: x, y - real(r8) :: dx - real(r8) :: dA - real(r8) :: area - character(len=*), parameter :: subname = 'hcol_elevation' - !----------------------------------------------------------------------- - ! mean elevation of column relative to hillslope bottom - ! elevation is considered 1-d - - dx = (xtop - xbottom)/real(ndiv) - - elev = 0._r8 - area = 0._r8 - do n = 0, ndiv-1 - x = xbottom + (n+0.5)*dx - y = this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) - dA = dx * y - area = area + dA - elev = elev + dx * y * hill_height*(x/hill_length)**alpha - enddo - elev = elev / area - - end function hcol_elevation - - !----------------------------------------------------------------------- - function hcol_slope(this,xtop,xbottom,alpha, hill_length, hill_height) result(slope) - ! - ! !DESCRIPTION: - ! Returns mean along-hillslope slope of hillslope column - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_surfacedata_type) , intent(in) :: this - real(r8) :: slope ! function result - real(r8), intent(in) :: xtop ! distance to upper edge of column - real(r8), intent(in) :: xbottom ! distance to lower edge of column - real(r8), intent(in) :: alpha ! hillslope profile curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - - character(len=*), parameter :: subname = 'hcol_slope' - !----------------------------------------------------------------------- - - ! mean along-hill slope of column - slope = hill_height & - * ((xtop/hill_length)**alpha & - - (xbottom/hill_length)**alpha) & - / (xtop - xbottom) - - end function hcol_slope - - !----------------------------------------------------------------------- - - subroutine Init(this,bounds,fsurdat) - ! - ! !DESCRIPTION: - ! Initialize hillslope geomorphology - ! - ! !USES: - use LandunitType , only : lun - use GridcellType , only : grc - use ColumnType , only : col - use clm_varctl , only : nhillslope, nmaxhillcol - use clm_varcon , only : zmin_bedrock, zisoi - use clm_varpar , only : nlevsoi - use spmdMod , only : masterproc - use fileutils , only : getfil - use clm_varcon , only : spval, ispval, grlnd - use landunit_varcon , only : istsoil - use ncdio_pio - - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_surfacedata_type) , intent(inout) :: this - type(bounds_type), intent(in) :: bounds - character(len=*) , intent(in) :: fsurdat ! surface data file name - real(r8), pointer :: ihillslope_in(:,:) ! read in - integer - real(r8), pointer :: fhillslope_in(:,:) ! read in - float - integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope - integer, allocatable :: hill_ndx(:,:) ! hillslope index - integer, allocatable :: col_ndx(:,:) ! column index - integer, allocatable :: col_dndx(:,:) ! downhill column index - real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] - real(r8), allocatable :: hill_aspect(:,:) ! hillslope azimuth [radians] - real(r8), allocatable :: hill_area(:,:) ! hillslope area [m2] - real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] - real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] - real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] - - type(file_desc_t) :: ncid ! netcdf id - logical :: readvar ! check whether variable on file - character(len=256) :: locfn ! local filename - integer :: ierr ! error code - integer :: c, l, g, i, j, ci, nh ! indices - - real(r8) :: hillslope_area ! total area of hillslope - real(r8) :: nc - real(r8) :: column_length ! length of column [m] - real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope - real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope - integer :: ctop, cbottom ! hillslope top and bottom column indices - real(r8) :: min_hill_dist, max_hill_dist - real(r8) :: soil_depth - - character(len=*), parameter :: subname = 'Init' - - !----------------------------------------------------------------------- - - ! Open surface dataset to read in data below - - call getfil (fsurdat, locfn, 0) - call ncd_pio_openfile (ncid, locfn, 0) - - allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & - hill_ndx(bounds%begl:bounds%endl,nmaxhillcol), & - col_ndx(bounds%begl:bounds%endl,nmaxhillcol), & - col_dndx(bounds%begl:bounds%endl,nmaxhillcol), & - hill_slope(bounds%begl:bounds%endl,nmaxhillcol), & - hill_aspect(bounds%begl:bounds%endl,nmaxhillcol), & - hill_area(bounds%begl:bounds%endl,nmaxhillcol), & - hill_length(bounds%begl:bounds%endl,nmaxhillcol), & - hill_width(bounds%begl:bounds%endl,nmaxhillcol), & - hill_height(bounds%begl:bounds%endl,nmaxhillcol), & - stat=ierr) - - allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) - - call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - pct_hillslope(l,:) = ihillslope_in(g,:) - enddo - deallocate(ihillslope_in) - - allocate(ihillslope_in(bounds%begg:bounds%endg,nmaxhillcol)) - - call ncd_io(ncid=ncid, varname='hillslope_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: hillslope_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_ndx(l,:) = ihillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - col_ndx(l,:) = ihillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='downhill_column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: downhill_column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - col_dndx(l,:) = ihillslope_in(g,:) - enddo - deallocate(ihillslope_in) - - allocate(fhillslope_in(bounds%begg:bounds%endg,nmaxhillcol)) - call ncd_io(ncid=ncid, varname='h_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_slope(l,:) = fhillslope_in(g,:) -!scs: hack for lack of data -! hill_slope(l,:) = 0.001_r8 - enddo - - call ncd_io(ncid=ncid, varname='h_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_aspect(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_area(l,:) = fhillslope_in(g,:) - enddo - call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_length(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_width(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_height(l,:) = fhillslope_in(g,:) - enddo - deallocate(fhillslope_in) - - ! Set hillslope hydrology column level variables - ! This needs to match how columns set up in subgridMod - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - if(lun%itype(l) == istsoil) then - ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost - - ! map external column index to internal column index - do c = lun%coli(l), lun%colf(l) - ! ci should span [1:nhillcolumns(l)] - ci = c-lun%coli(l)+1 - ! relative separation should be the same - if (col_dndx(l,ci) <= -999) then - ! lowermost column of hillslope has no downstream neighbor -!scs col%cold(c) = col_dndx(l,ci) - col%cold(c) = ispval - else - col%cold(c) = c + (col_dndx(l,ci) - col_ndx(l,ci)) - endif - enddo - - - do c = lun%coli(l), lun%colf(l) - ci = c-lun%coli(l)+1 - - col%hillslope_ndx(c) = hill_ndx(l,ci) - - ! Find uphill/downhill neighbors (must calculate - ! col%cold in a previous loop -!scs col%colu(c) = -999 - col%colu(c) = ispval - do i = lun%coli(l), lun%colf(l) - if(c == col%cold(i)) then - col%colu(c) = i - endif - enddo - -! distance of lower edge of column from hillslope bottom - col%hill_distance(c) = hill_length(l,ci) -! width of lower edge of column - col%hill_width(c) = hill_width(l,ci) -! mean elevation of column relative to gridcell mean elevation - col%hill_elev(c) = hill_height(l,ci) -! mean along-hill slope of column - col%hill_slope(c) = hill_slope(l,ci) -! area of column - col%hill_area(c) = hill_area(l,ci) -! azimuth of column - col%hill_aspect(c) = hill_aspect(l,ci) - enddo - - ! Now that column areas are determined, column weights can be recalculated - hillslope_area = 0._r8 - ! area weighted by pct_hillslope - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - hillslope_area = hillslope_area & - + col%hill_area(c)*real(pct_hillslope(l,nh),r8)*0.01_r8 - enddo - -! if missing hillslope information on surface dataset, fill data -! and recalculate hillslope_area before setting column weights - if (hillslope_area == 0._r8) then - do c = lun%coli(l), lun%colf(l) - col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6 ! km2 to m2 - col%hill_distance(c) = sqrt(col%hill_area(c)) - col%hill_width(c) = sqrt(col%hill_area(c)) - col%hill_elev(c) = col%topo_std(c) - col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) - col%hill_aspect(c) = (rpi/2.) ! east (arbitrarily chosen) - nh = col%hillslope_ndx(c) - pct_hillslope(l,nh) = 100/nhillslope - hillslope_area = hillslope_area & - + col%hill_area(c)*real(pct_hillslope(l,nh),r8)*0.01_r8 - enddo - endif - - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - col%wtlunit(c) = col%hill_area(c) & - * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area - enddo - - -!!$ ! area weighted by pct_hillslope -!!$ i=0 -!!$ do c = lun%coli(l), lun%colf(l) -!!$ if(col%active(c)) i=i+1 -!!$ -!!$if(l==4398) write(iulog,'(a12,3i8,f20.17,2f18.2,f20.17)') 'colweights: ', l, c, pct_hillslope(l,col%hillslope_ndx(c)),col%wtlunit(c),col%hill_area(c),hillslope_area,col%hill_area(c)/hillslope_area -!!$ enddo -!!$! write(iulog,'(a12,3i8)') 'numcol: ', l, i,lun%ncolumns(l) -!!$ ! area weighted by pct_hillslope -!!$ -!!$!!! ensure col wts sum to 1, re-use hillslope_area to normalize -!!$ hillslope_area = 0._r8 -!!$ do c = lun%coli(l), lun%colf(l) -!!$ hillslope_area = hillslope_area & -!!$ + col%wtlunit(c) -!!$ enddo -!!$ -!!$ if (hillslope_area > 1._r8) then -!!$ write(iulog,'(a12,i8,f18.14)') 'wtsgt1: ', l,hillslope_area -!!$ do c = lun%coli(l), lun%colf(l) -!!$ col%wtlunit(c)=col%wtlunit(c)/hillslope_area -!!$ enddo -!!$ endif -!!! - - - ! Set column bedrock index - !thin soil for non-riparian columns, thick for riparian - if(1==2) then - do c = lun%coli(l), lun%colf(l) - if(col%cold(c) /= ispval) then - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then - col%nbedrock(c) = j - end if - end if - enddo - else - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then - col%nbedrock(c) = j - end if - end if - enddo - endif - end do - endif - if(1==2) then -! first set all soils to 0.5m - do c = lun%coli(l), lun%colf(l) - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then - col%nbedrock(c) = j - end if - end if - enddo - enddo - -! then increase relative to ridge - min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) - max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) - do c = lun%coli(l), lun%colf(l) -! nc=c-lun%coli(l) - nc = (max_hill_dist - col%hill_distance(c))/(max_hill_dist - min_hill_dist) -! nc should vary from 0 at ridge to 1 at valley - soil_depth = nc*3.5_r8 + 0.5_r8 -!write(iulog,*) l,c,nc,soil_depth - do j = 1,nlevsoi - if ((zisoi(j-1) < soil_depth) .and. (zisoi(j) >= soil_depth)) then - col%nbedrock(c) = j - end if - enddo - enddo - endif - - ! maximum soil depth of 3m - if(1==1) then - do c = lun%coli(l), lun%colf(l) - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then -! if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then - if (zisoi(j-1) < 1.4_r8 .and. zisoi(j) >= 1.4_r8) then - col%nbedrock(c) = min(j,col%nbedrock(c)) - end if - end if - enddo - end do - endif -! thin soils in uplands - if(1==2) then -! first set all soils to 0.5m - do c = lun%coli(l), lun%colf(l) - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then - col%nbedrock(c) = j - end if - end if - enddo - enddo -! then increase relative to ridge - do c = lun%coli(l), lun%colf(l) - if(col%cold(c) /= ispval) then - do j = 1,nlevsoi - if (zisoi(j-1) < (zisoi(col%nbedrock(c))+1.0_r8) .and. zisoi(j) >= (zisoi(col%nbedrock(c))+1.0_r8)) then - col%nbedrock(col%cold(c)) = j - end if - enddo - endif - enddo - endif -! thin soils in valley - if(1==2) then -! first set all soils to 0.5m - do c = lun%coli(l), lun%colf(l) - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then - col%nbedrock(c) = j - end if - end if - enddo - enddo -! then increase relative to valley - min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) - max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) - do c = lun%coli(l), lun%colf(l) - nc = (col%hill_distance(c) - min_hill_dist)/(max_hill_dist - min_hill_dist) -! nc should vary from 1 at ridge to 0 at valley - soil_depth = nc*6.0_r8 + 2.0_r8 -!write(iulog,*) 'soildepth: ',l,c,nc,soil_depth - do j = 1,nlevsoi - if ((zisoi(j-1) < soil_depth) .and. (zisoi(j) >= soil_depth)) then - col%nbedrock(c) = j - end if - enddo - - -!!$ do c = lun%colf(l), lun%coli(l), -1 -!!$ if(col%colu(c) /= ispval) then -!!$ do j = 1,nlevsoi -!!$ if (zisoi(j-1) < (zisoi(col%nbedrock(c))+0.5_r8) .and. zisoi(j) >= (zisoi(col%nbedrock(c))+0.5_r8)) then -!!$ col%nbedrock(col%colu(c)) = j -!!$ end if -!!$ enddo -!!$ endif - - end do - endif - if(1==2) then -! do c = lun%coli(l), lun%colf(l) - do c = lun%colf(l), lun%coli(l), -1 - if(col%colu(c) /= ispval) then - do j = 1,nlevsoi - if (zisoi(j-1) < (zisoi(col%nbedrock(c))+0.5_r8) .and. zisoi(j) >= (zisoi(col%nbedrock(c))+0.5_r8)) then - col%nbedrock(col%colu(c)) = j - end if - enddo - endif - end do - endif - endif ! end of istsoil - enddo ! end of loop over landunits - - deallocate(pct_hillslope,hill_ndx,col_ndx,col_dndx, & - hill_slope,hill_area,hill_length, & - hill_width,hill_height,hill_aspect) - - call ncd_pio_closefile(ncid) - - end subroutine Init - -end module HillslopeHydrologySurfaceDataMod diff --git a/src/biogeophys/HillslopeHydrologyTroch02Mod.F90 b/src/biogeophys/HillslopeHydrologyTroch02Mod.F90 deleted file mode 100644 index 21dcce9c2d..0000000000 --- a/src/biogeophys/HillslopeHydrologyTroch02Mod.F90 +++ /dev/null @@ -1,432 +0,0 @@ -module HillslopeHydrologyTroch02Mod - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Calculate geomorphological quantities for hillslope columns - ! assuming Troch et al., AWR, 2002 profile and plan shapes. - ! - ! !USES: -#include "shr_assert.h" - use shr_kind_mod , only : r8 => shr_kind_r8 - use HillslopeHydrologyBaseMod, only : hillslope_geomorphology_type - use shr_log_mod , only : errMsg => shr_log_errMsg - use spmdMod , only : masterproc - use abortutils , only : endrun - use clm_varctl , only : iulog - use decompMod , only : bounds_type - - implicit none - private - save - - ! PRIVATE - character(len=*), parameter, private :: sourcefile = & - __FILE__ - - ! !PUBLIC TYPES: - - type, extends(hillslope_geomorphology_type), public :: & - hillslope_geomorphology_troch02_type - private - - ! variable declarations - - contains - - procedure :: Init - procedure :: hcol_width - procedure :: hcol_elevation - procedure :: hcol_slope - - end type hillslope_geomorphology_troch02_type - - !----------------------------------------------------------------------- - interface hillslope_geomorphology_troch02_type - - end interface hillslope_geomorphology_troch02_type - - - !----------------------------------------------------------------------- - -contains - - !----------------------------------------------------------------------- - function hcol_width(this,x,alpha,beta,hill_length,hill_width,hill_height) result(width) - ! - ! !DESCRIPTION: - ! Returns width of hillslope column. - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_troch02_type) , intent(in) :: this - real(r8) :: width ! function result - real(r8), intent(in) :: x ! distance along hillslope - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - real(r8) :: eps = 1.e-6_r8 - real(r8) :: x0,y0,yl ! integration limits - character(len=*), parameter :: subname = 'hcol_width' - !----------------------------------------------------------------------- - - ! width function has special case for n = 2 - ! in this implementation, integration limits depend on sign of beta - if (abs(alpha - 2._r8) < eps) then - - ! function blows up for x0=0; integration limits set by trial and error - if(beta < 0._r8) then - y0 = hill_width/2._r8 - yl = 0.1_r8 - x0=hill_length *(yl/y0)**(-hill_height/(beta*hill_length**2)) - else - x0 = 0.2_r8 - y0 = (hill_width/2._r8)& - *(x0/hill_length)**(beta*hill_length**2/hill_height) - endif - - ! compiler does not like log(zero) - if (x == 0._r8) then - if (beta < 0._r8) then - width = hill_width/2._r8 - else - width = eps - endif - else - width = y0*(x/x0)**(beta*hill_length**2/hill_height) - endif - else - ! alpha /= 2 case, x0 equals zero - y0 = hill_width/2._r8 - if(beta > 0._r8) then - y0 = y0 * exp(-(2._r8*beta*hill_length**2) & - / (hill_height*(2._r8 - alpha)*alpha)) - endif - ! compiler does not like zero to a negative power. - if (x == 0._r8) then - width = y0 - else - width = y0*exp((((2._r8*beta*hill_length**2) & - / (hill_height*(2._r8 - alpha)*alpha)) & - * (x/hill_length)**(2._r8-alpha))) - endif - endif - ! hillslope width is twice integral [0:x] - width = 2._r8 * width - - end function hcol_width - - !----------------------------------------------------------------------- - - function hcol_elevation(this,xtop,xbottom,alpha,beta,hill_length,hill_width,hill_height) result(elev) - ! - ! !DESCRIPTION: - ! Returns mean elevation of column (relative to hillslope bottom). - ! Area-weighted mean elevation is calculated by - ! numerically integrating using hcol_width function. ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_troch02_type) , intent(in) :: this - real(r8) :: elev ! function result - real(r8), intent(in) :: xtop ! upper integration limit - real(r8), intent(in) :: xbottom ! lower integration limit - real(r8), intent(in) :: alpha ! profile curvature parameter - real(r8), intent(in) :: beta ! plan curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_width ! total hillslope width - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - - integer :: n - integer, parameter :: ndiv = 100 - real(r8) :: x, y - real(r8) :: dx - real(r8) :: dA - real(r8) :: area - character(len=*), parameter :: subname = 'hcol_elevation' - !----------------------------------------------------------------------- - ! mean elevation of column relative to hillslope bottom - ! elevation is first integrated analytically in across-slope direction - ! then summed in along-slope direction - - dx = (xtop - xbottom)/real(ndiv) - - elev = 0._r8 - area = 0._r8 - do n = 0, ndiv-1 - x = xbottom + (n+0.5)*dx - y = this%hcol_width(x,alpha,beta,hill_length,hill_width,hill_height) - dA = dx * y - area = area + dA - elev = elev + dx * (hill_height*y*(x/hill_length)**alpha & - + beta*y**3/12._r8) - enddo - elev = elev / area - - end function hcol_elevation - - !----------------------------------------------------------------------- - - function hcol_slope(this, xtop,xbottom,alpha, hill_length, hill_height) result(slope) - ! - ! !DESCRIPTION: - ! Returns mean along-hillslope slope of hillslope column - ! - ! !USES: - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_troch02_type) , intent(in) :: this - real(r8) :: slope ! function result - real(r8), intent(in) :: xtop ! distance to upper edge of column - real(r8), intent(in) :: xbottom ! distance to lower edge of column - real(r8), intent(in) :: alpha ! hillslope profile curvature parameter - real(r8), intent(in) :: hill_length ! total hillslope length - real(r8), intent(in) :: hill_height ! total hillslope height - ! - ! !LOCAL VARIABLES: - - character(len=*), parameter :: subname = 'hcol_slope' - !----------------------------------------------------------------------- - - ! mean along-hill slope of column - slope = hill_height & - * ((xtop/hill_length)**alpha & - - (xbottom/hill_length)**alpha) & - / (xtop - xbottom) - - end function hcol_slope - - !----------------------------------------------------------------------- - - subroutine Init(this,bounds,fsurdat) - ! - ! !DESCRIPTION: - ! Initialize hillslope geomorphology - ! - ! !USES: - use LandunitType , only : lun - use GridcellType , only : grc - use ColumnType , only : col - use clm_varctl , only : nhillslope - use clm_varcon , only : zmin_bedrock, zisoi - use clm_varpar , only : nlevsoi - use spmdMod , only : masterproc - use fileutils , only : getfil - use clm_varcon , only : spval, ispval, grlnd - use landunit_varcon , only : istsoil - use ncdio_pio - - ! - ! !ARGUMENTS: - class(hillslope_geomorphology_troch02_type) , intent(inout) :: this - type(bounds_type), intent(in) :: bounds - character(len=*) , intent(in) :: fsurdat ! surface data file name - real(r8), pointer :: ihillslope_in(:,:) ! read in - integer - real(r8), pointer :: fhillslope_in(:,:) ! read in - float - integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope - real(r8), allocatable :: hill_alpha(:,:) ! hillslope 'alpha' parameter - real(r8), allocatable :: hill_beta(:,:) ! hillslope 'beta' parameter - real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] - real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] - real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] - - type(file_desc_t) :: ncid ! netcdf id - logical :: readvar ! check whether variable on file - character(len=256) :: locfn ! local filename - integer :: ierr ! error code - integer :: c, l, g, j, nh ! indices - - real(r8) :: hillslope_area ! total area of hillslope - real(r8) :: column_length ! length of column [m] - real(r8) :: le_distance ! distance of lower edge of column from bottom of hillslope - real(r8) :: ue_distance ! distance of upper edge of column from bottom of hillslope - integer :: ctop, cbottom ! hillslope top and bottom column indices - - character(len=*), parameter :: subname = 'Init' - - !----------------------------------------------------------------------- - - ! Open surface dataset to read in data below - - call getfil (fsurdat, locfn, 0) - call ncd_pio_openfile (ncid, locfn, 0) - - allocate(pct_hillslope(bounds%begl:bounds%endl,nhillslope), & - hill_alpha(bounds%begl:bounds%endl,nhillslope), & - hill_beta(bounds%begl:bounds%endl,nhillslope), & - hill_length(bounds%begl:bounds%endl,nhillslope), & - hill_width(bounds%begl:bounds%endl,nhillslope), & - hill_height(bounds%begl:bounds%endl,nhillslope), & - stat=ierr) - - allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) - - call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - pct_hillslope(l,:) = ihillslope_in(g,:) - enddo - deallocate(ihillslope_in) - - allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) - call ncd_io(ncid=ncid, varname='h_alpha', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_alpha not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_alpha(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_beta', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_beta not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_beta(l,:) = fhillslope_in(g,:) - enddo - call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_length(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_width(l,:) = fhillslope_in(g,:) - enddo - - call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_height(l,:) = fhillslope_in(g,:) - enddo - deallocate(fhillslope_in) - - ! Set hillslope hydrology column level variables - ! This needs to match how columns set up in subgridMod - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - if(lun%itype(l) == istsoil) then - ! lun%coli is the uppermost column in the hillslope, lun%colf is the lowermost - - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - ctop = lun%coli(l)+(nh-1)*lun%ncolumns(l)/nhillslope - cbottom = lun%coli(l)+(nh)*lun%ncolumns(l)/nhillslope - 1 - - ! distance of lower edge of column from hillslope bottom - col%hill_distance(c) = this%hcol_distance(c, & - ctop, cbottom, hill_length(l,nh)) - ! if (masterproc) write(iulog,*) 'hd: ',c,col%hill_distance(c) - - !distance of lower edge of column from hillslope bottom - column_length = hill_length(l,nh)/(lun%ncolumns(l)/nhillslope) - le_distance = col%hill_distance(c) - 0.5_r8*column_length - ue_distance = col%hill_distance(c) + 0.5_r8*column_length - - ! width of lower edge of column from hillslope bottom - col%hill_width(c) = this%hcol_width(le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'hw: ',c,col%hill_width(c) - - col%hill_area(c) = this%hcol_area(ue_distance, le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'ha: ',c,col%hill_area(c) - - ! mean elevation of column relative to mean gridcell elevation - col%hill_elev(c) = this%hcol_elevation(ue_distance, le_distance, & - hill_alpha(l,nh), hill_beta(l,nh),hill_length(l,nh), & - hill_width(l,nh),hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'he: ',c,col%hill_elev(c) - - ! mean along-hill slope of column - col%hill_slope(c) = this%hcol_slope(ue_distance, le_distance, & - hill_alpha(l,nh),hill_length(l,nh), hill_height(l,nh)) - ! if (masterproc) write(iulog,*) 'hs: ',c,col%hill_slope(c) - - enddo - - ! Now that column areas are determined, column weights can be recalculated - hillslope_area = 0._r8 - ! area weighted by pct_hillslope - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) - enddo - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - col%wtlunit(c) = col%hill_area(c) & - * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area - enddo - - ! Set column bedrock index - !thin soil for non-riparian columns, thick for riparian - do c = lun%coli(l), lun%colf(l) - if(col%cold(c) /= ispval) then - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 0.5_r8 .and. zisoi(j) >= 0.5_r8) then - col%nbedrock(c) = j - end if - end if - enddo - else - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < 3.0_r8 .and. zisoi(j) >= 3.0_r8) then - col%nbedrock(c) = j - end if - end if - enddo - endif - end do - - endif ! end of istsoil - enddo ! end of loop over landunits - - deallocate(pct_hillslope,hill_alpha,hill_beta,hill_length, & - hill_width,hill_height) - - call ncd_pio_closefile(ncid) - - end subroutine Init - -end module HillslopeHydrologyTroch02Mod diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 57e538cf56..d3c3ce5b59 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -37,8 +37,6 @@ module HydrologyDrainageMod !----------------------------------------------------------------------- subroutine HydrologyDrainage(bounds, & - num_hilltop, filter_hilltopc, & - num_hillbottom, filter_hillbottomc, & num_hillslope, filter_hillslopec, & num_nolakec, filter_nolakec, & num_hydrologyc, filter_hydrologyc, & @@ -59,7 +57,7 @@ subroutine HydrologyDrainage(bounds, & use clm_varctl , only : use_vichydro, use_hillslope use clm_varpar , only : nlevgrnd, nlevurb use clm_time_manager , only : get_step_size, get_nstep - use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, LateralFlowPowerLaw, LateralFlowHillslope + use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, PerchedLateralFlowHillslope, LateralFlowPowerLaw, LateralFlowHillslope use SoilWaterMovementMod , only : use_aquifer_layer ! ! !ARGUMENTS: @@ -72,10 +70,6 @@ subroutine HydrologyDrainage(bounds, & integer , intent(in) :: filter_urbanc(:) ! column filter for urban points integer , intent(in) :: num_do_smb_c ! number of bareland columns in which SMB is calculated, in column filter integer , intent(in) :: filter_do_smb_c(:) ! column filter for bare land SMB columns - integer , intent(in) :: num_hilltop ! number of soil cols marked "upslope" - integer , intent(in) :: filter_hilltopc(:) ! column filter for designating "upslope" cols. - integer , intent(in) :: num_hillbottom ! number of soil cols marked "downslope" - integer , intent(in) :: filter_hillbottomc(:) ! column filter for designating "downslope" cols. integer , intent(in) :: num_hillslope ! number of soil hill cols. integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hill cols. @@ -147,15 +141,14 @@ subroutine HydrologyDrainage(bounds, & waterstatebulk_inst, waterfluxbulk_inst) else - call PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc,& - soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst) - if(use_hillslope) then + call PerchedLateralFlowHillslope(bounds, & + num_hydrologyc, filter_hydrologyc, & + soilhydrology_inst, soilstate_inst, & + waterstatebulk_inst, waterfluxbulk_inst,& + wateratm2lndbulk_inst) + call LateralFlowHillslope(bounds, & - num_hilltop, filter_hilltopc, & - num_hillbottom, filter_hillbottomc, & num_hillslope, filter_hillslopec, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& @@ -163,6 +156,11 @@ subroutine HydrologyDrainage(bounds, & waterstatebulk_inst, waterfluxbulk_inst, & wateratm2lndbulk_inst) else + call PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & + num_urbanc, filter_urbanc,& + soilhydrology_inst, soilstate_inst, & + waterstatebulk_inst, waterfluxbulk_inst) + call LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& soilhydrology_inst, soilstate_inst, & diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index d7dc64be73..65d1dbc4b6 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -51,6 +51,7 @@ module SoilHydrologyMod public :: CLMVICMap public :: PerchedWaterTable ! Calculate perched water table public :: PerchedLateralFlow ! Calculate lateral flow from perched saturated zone + public :: PerchedLateralFlowHillslope ! Calculate lateral flow from perched saturated zone in hillslope configuration public :: ThetaBasedWaterTable ! Calculate water table from soil moisture state public :: LateralFlowPowerLaw ! Calculate lateral flow based on power law drainage function public :: LateralFlowHillslope ! Calculate lateral in multi-column hillslope configuration @@ -1985,6 +1986,249 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & end subroutine PerchedLateralFlow +!#41 + !----------------------------------------------------------------------- + subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & + filter_hydrologyc, soilhydrology_inst, soilstate_inst, & + waterstatebulk_inst, waterfluxbulk_inst, wateratm2lndbulk_inst) + ! + ! !DESCRIPTION: + ! Calculate subsurface drainage from perched saturated zone + ! + ! !USES: + use clm_varcon , only : pondmx, tfrz, watmin,rpi, secspday, nlvic + use landunit_varcon , only : istsoil + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter + integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points + type(soilstate_type) , intent(in) :: soilstate_inst + type(soilhydrology_type) , intent(inout) :: soilhydrology_inst + type(waterstatebulk_type) , intent(inout) :: waterstatebulk_inst + type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst + type(wateratm2lndbulk_type), intent(in) :: wateratm2lndbulk_inst + ! + ! !LOCAL VARIABLES: + character(len=32) :: subname = 'PerchedLateralFlowHillslope' ! subroutine name + integer :: c,j,fc,i,g ! indices + real(r8) :: dtime ! land model time step (sec) + real(r8) :: drainage_tot + real(r8) :: drainage_layer + real(r8) :: s_y + integer :: k + integer :: k_frost(bounds%begc:bounds%endc) + integer :: k_perch(bounds%begc:bounds%endc) + real(r8) :: wtsub + real(r8) :: q_perch + real(r8) :: q_perch_max + + character(len=32) :: transmissivity_method = 'layersum' +! character(len=32) :: baseflow_method = 'kinematic' + character(len=32) :: baseflow_method = 'darcy' +! character(len=32) :: baseflow_method = 'mixed' + real(r8) :: transmis + real(r8) :: dgrad + real(r8), parameter :: k_anisotropic = 1._r8 + integer :: c0, c_src, c_dst, nstep, nbase + real(r8) :: qflx_drain_perched_vol(bounds%begc:bounds%endc) ! volumetric lateral subsurface flow through active layer [m3/s] + real(r8) :: qflx_drain_perched_out(bounds%begc:bounds%endc) ! lateral subsurface flow through active layer [mm/s] + + associate( & + nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) + z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) + zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) + dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) + bsw => soilstate_inst%bsw_col , & ! Input: [real(r8) (:,:) ] Clapp and Hornberger "b" + hksat => soilstate_inst%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) + sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) + watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) + + frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) + zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) + zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Input: [real(r8) (:) ] perched water table depth (m) + + tdepth => wateratm2lndbulk_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) + tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) + + qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col , & ! Output: [real(r8) (:) ] perched wt sub-surface runoff (mm H2O /s) + + h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) + h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) + ) + + ! Get time step + + dtime = get_step_size() + + ! locate frost table and perched water table + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + k_frost(c)=nbedrock(c) + k_perch(c)=nbedrock(c) + do k=1, nbedrock(c) + if (frost_table(c) >= zi(c,k-1) .and. frost_table(c) <= zi(c,k)) then + k_frost(c)=k + exit + endif + enddo + + do k=1, nbedrock(c) + if (zwt_perched(c) >= zi(c,k-1) .and. zwt_perched(c) <= zi(c,k)) then + k_perch(c)=k + exit + endif + enddo + enddo + + ! compute drainage from perched saturated region + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + + qflx_drain_perched(c) = 0._r8 + qflx_drain_perched_out(c) = 0._r8 + qflx_drain_perched_vol(c) = 0._r8 + + if (frost_table(c) > zwt_perched(c)) then + ! hillslope columns + if (lun%itype(col%landunit(c)) == istsoil) then + + ! calculate head gradient + g = col%gridcell(c) + ! kinematic wave approximation + if (baseflow_method == 'kinematic') then + dgrad = col%hill_slope(c) + endif + ! darcy's law + if (baseflow_method == 'darcy') then + if (col%cold(c) /= ispval) then + dgrad = (col%hill_elev(c)-zwt_perched(c)) & + - (col%hill_elev(col%cold(c))-zwt_perched(col%cold(c))) + dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) + else + ! flow between channel and lowest column + ! bankfull height is defined to be zero + dgrad = (col%hill_elev(c)-zwt_perched(c)) & + ! ignore overbankfull storage + - min(max((tdepth(g) - tdepth_bankfull(g)), & + (col%hill_elev(c)-frost_table(c))),0._r8) + + dgrad = dgrad / (col%hill_distance(c)) + ! dgrad cannot be negative when channel is empty + if (tdepth(g) <= 0._r8) then + dgrad = max(dgrad, 0._r8) + endif + endif + end if + + ! Determine source and destination columns + if (dgrad >= 0._r8) then + c_src = c + c_dst = col%cold(c) + else + c_src = col%cold(c) + c_dst = c + endif + + ! Calculate transmissivity of source column + transmis = 0._r8 + if(c_src /= ispval) then + ! sum of layer transmissivities + if (transmissivity_method == 'layersum') then + do k = k_perch(c_src), k_frost(c_src) + if(k == k_perch(c_src)) then + transmis = transmis + 1.e-3_r8*hksat(c_src,k)*(zi(c_src,k) - zwt_perched(c_src)) + else + transmis = transmis + 1.e-3_r8*hksat(c_src,k)*dz(c_src,k) + endif + end do + ! adjust by 'anisotropy factor' + transmis = k_anisotropic*transmis + endif + ! constant conductivity based on shallowest saturated layer hk + if (transmissivity_method == 'constant') then + transmis = k_anisotropic*(1.e-3_r8*hksat(c_src,k_perch(c_src))) & + *(zi(c_src,k_frost(c_src)) - zwt_perched(c_src) ) + endif + ! power law profile based on shallowest saturated layer hk + if (transmissivity_method == 'power') then + endif + else + ! transmissivity of losing stream (c_src == ispval) + transmis = k_anisotropic*(1.e-3_r8*hksat(c,k_perch(c_dst)))*tdepth(g) + endif + + qflx_drain_perched_vol(c) = transmis*col%hill_width(c)*dgrad + qflx_drain_perched_out(c) = 1.e3_r8*(qflx_drain_perched_vol(c)/col%hill_area(c)) + + else + ! non-hillslope columns + ! specify maximum drainage rate + q_perch_max = 1.e-5_r8 * sin(col%topo_slope(c) * (rpi/180._r8)) + + wtsub = 0._r8 + q_perch = 0._r8 + do k = k_perch(c), k_frost(c) + q_perch = q_perch + hksat(c,k)*dz(c,k) + wtsub = wtsub + dz(c,k) + end do + if (wtsub > 0._r8) q_perch = q_perch/wtsub + + qflx_drain_perched_out(c) = q_perch_max * q_perch & + *(frost_table(c) - zwt_perched(c)) + endif + endif + + enddo + + ! compute net drainage from perched saturated region + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + ! drainage-out + qflx_drain_perched(c) = qflx_drain_perched(c) + qflx_drain_perched_out(c) + if (lun%itype(col%landunit(c)) == istsoil) then + ! drainage-in + if (col%cold(c) /= ispval) then + qflx_drain_perched(col%cold(c)) = & + qflx_drain_perched(col%cold(c)) - & + 1.e3_r8*(qflx_drain_perched_vol(c))/col%hill_area(col%cold(c)) + endif + endif + enddo + + ! remove drainage from soil moisture storage + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + + ! remove drainage from perched saturated layers + drainage_tot = qflx_drain_perched(c) * dtime + do k = k_perch(c), k_frost(c) + + s_y = watsat(c,k) & + * ( 1. - (1.+1.e3*zwt_perched(c)/sucsat(c,k))**(-1./bsw(c,k))) + s_y=max(s_y,0.02_r8) + if (k== k_perch(c)) then + drainage_layer=min(drainage_tot,(s_y*(zi(c,k) - zwt_perched(c))*1.e3)) + else + drainage_layer=min(drainage_tot,(s_y*(dz(c,k))*1.e3)) + endif + + drainage_layer=max(drainage_layer,0._r8) + drainage_tot = drainage_tot - drainage_layer + h2osoi_liq(c,k) = h2osoi_liq(c,k) - drainage_layer + + enddo + + ! if drainage_tot is greater than available water + ! (above frost table), then decrease qflx_drain_perched + ! by residual amount for water balance + qflx_drain_perched(c) = qflx_drain_perched(c) - drainage_tot/dtime + enddo + + end associate + + end subroutine PerchedLateralFlowHillslope + !#5 !----------------------------------------------------------------------- subroutine ThetaBasedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & @@ -2408,8 +2652,6 @@ end subroutine LateralFlowPowerLaw !#61 !----------------------------------------------------------------------- subroutine LateralFlowHillslope(bounds, & - num_hilltop, filter_hilltopc, & - num_hillbottom, filter_hillbottomc, & num_hillslope, filter_hillslopec, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,soilhydrology_inst, soilstate_inst, & @@ -2442,10 +2684,6 @@ subroutine LateralFlowHillslope(bounds, & type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst integer , intent(in) :: num_hillslope ! number of hillslope soil cols integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. - integer , intent(in) :: num_hilltop ! number of hillslope soil cols - integer , intent(in) :: filter_hilltopc(:) ! column filter for designating all hillslope cols. - integer , intent(in) :: num_hillbottom ! number of hillslope soil cols - integer , intent(in) :: filter_hillbottomc(:) ! column filter for designating all hillslope cols. ! ! !LOCAL VARIABLES: @@ -2464,10 +2702,10 @@ subroutine LateralFlowHillslope(bounds, & real(r8) :: wtsub ! summation of hk*dzmm for layers below water table (mm**2/s) real(r8) :: dzsum ! summation of dzmm of layers below water table (mm) real(r8) :: icefracsum ! summation of icefrac*dzmm of layers below water table (-) - real(r8) :: fracice_rsub(bounds%begc:bounds%endc) ! fractional impermeability of soil layers (-) + real(r8) :: ice_imped_col(bounds%begc:bounds%endc) ! column average hydraulic conductivity reduction due to presence of soil ice (-) + real(r8) :: ice_imped(bounds%begc:bounds%endc,1:nlevsoi) ! hydraulic conductivity reduction due to presence of soil ice (-) real(r8) :: available_h2osoi_liq ! available soil liquid water in a layer real(r8) :: h2osoi_vol - real(r8) :: imped real(r8) :: rsub_top_tot real(r8) :: rsub_top_layer real(r8) :: theta_unsat @@ -2486,19 +2724,22 @@ subroutine LateralFlowHillslope(bounds, & real(r8) :: wtsub_vic ! summation of hk*dzmm for layers in the third VIC layer integer :: g -!scs character(len=32) :: transmissivity_method = 'layersum' ! character(len=32) :: baseflow_method = 'kinematic' character(len=32) :: baseflow_method = 'darcy' ! character(len=32) :: baseflow_method = 'mixed' - real(r8) :: transmis - real(r8) :: dgrad + logical :: no_lateral_flow = .false. + real(r8) :: transmis ! transmissivity + real(r8) :: dgrad ! hydraulic head gradient real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent - real(r8), parameter :: k_anisotropic = 20._r8 + real(r8), parameter :: k_anisotropic = 1._r8 ! anisotropy scalar real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) + real(r8) :: qflx_latflow_avg(bounds%begc:bounds%endc) + real(r8) :: larea integer :: c0, c_src, c_dst, nstep, nbase - + integer :: l + !----------------------------------------------------------------------- associate( & @@ -2564,7 +2805,8 @@ subroutine LateralFlowHillslope(bounds, & dzmm(c,j) = dz(c,j)*1.e3_r8 vol_ice = min(watsat(c,j), h2osoi_ice(c,j)/(dz(c,j)*denice)) - icefrac(c,j) = min(1._r8,vol_ice/watsat(c,j)) + icefrac(c,j) = min(1._r8,vol_ice/watsat(c,j)) + ice_imped(c,j)=10._r8**(-e_ice*icefrac(c,j)) end do end do @@ -2575,7 +2817,6 @@ subroutine LateralFlowHillslope(bounds, & qflx_drain(c) = 0._r8 qflx_rsub_sat(c) = 0._r8 rsub_top(c) = 0._r8 - fracice_rsub(c) = 0._r8 qflx_latflow_in(c) = 0._r8 qflx_latflow_out(c) = 0._r8 @@ -2584,175 +2825,211 @@ subroutine LateralFlowHillslope(bounds, & qflx_latflow_out_vol(c) = 0._r8 end do + ! The layer index of the first unsaturated layer, + ! i.e., the layer right above the water table + + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + jwt(c) = nlevsoi + ! allow jwt to equal zero when zwt is in top layer + do j = 1,nlevsoi + if(zwt(c) <= zi(c,j)) then + jwt(c) = j-1 + exit + end if + enddo + end do - ! The layer index of the first unsaturated layer, - ! i.e., the layer right above the water table - - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - jwt(c) = nlevsoi - ! allow jwt to equal zero when zwt is in top layer - do j = 1,nlevsoi - if(zwt(c) <= zi(c,j)) then - jwt(c) = j-1 - exit - end if - enddo - end do - + ! Calculate ice impedance factor (after jwt calculated) + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + dzsum = 0._r8 + icefracsum = 0._r8 + do j = max(jwt(c),1), nlevsoi + dzsum = dzsum + dzmm(c,j) + icefracsum = icefracsum + icefrac(c,j) * dzmm(c,j) + end do + ice_imped_col(c)=10._r8**(-e_ice*(icefracsum/dzsum)) + enddo + + do fc = 1, num_hillslope + c = filter_hillslopec(fc) + g = col%gridcell(c) - do fc = 1, num_hillslope - c = filter_hillslopec(fc) - g = col%gridcell(c) - ! kinematic wave approximation - if (baseflow_method == 'kinematic') then - dgrad = col%hill_slope(c) - endif - ! darcy's law - if (baseflow_method == 'darcy') then - if (col%cold(c) /= ispval) then - dgrad = (col%hill_elev(c)-zwt(c)) & - - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) - dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) - else - ! flow between channel and lowest column - ! bankfull height is defined to be zero - dgrad = (col%hill_elev(c)-zwt(c)) & -! - (tdepth(g) - tdepth_bankfull(g)) - ! ignore overbankfull storage - - min((tdepth(g) - tdepth_bankfull(g)),0._r8) - - dgrad = dgrad / (col%hill_distance(c)) - ! dgrad cannot be negative when channel is empty - if (tdepth(g) <= 0._r8) then - dgrad = max(dgrad, 0._r8) - endif - endif - end if - - ! Calculate transmissivity of source column - if (dgrad >= 0._r8) then - c_src = c - else - c_src = col%cold(c) - endif - - transmis = 0._r8 - if(c_src /= ispval) then - ! transmissivity non-zero only when saturated conditions exist - if(zwt(c_src) <= zi(c_src,nbedrock(c_src))) then - ! sum of layer transmissivities - if (transmissivity_method == 'layersum') then - do j = jwt(c_src)+1, nbedrock(c_src) - if(j == jwt(c_src)+1) then - transmis = transmis + 1.e-3_r8*hksat(c_src,j)*(zi(c_src,j) - zwt(c_src)) - else - transmis = transmis + 1.e-3_r8*hksat(c_src,j)*dz(c_src,j) - endif - end do - ! adjust by 'anisotropy factor' - transmis = k_anisotropic*transmis - endif - ! constant conductivity based on shallowest saturated layer hk - if (transmissivity_method == 'constant') then - transmis = k_anisotropic*(1.e-3_r8*hksat(c_src,jwt(c_src)+1)) & - *(zi(c_src,nbedrock(c_src)) - zwt(c_src) ) - endif - ! power law profile based on shallowest saturated layer hk - if (transmissivity_method == 'power') then - ! transmis = k_anisotropic*hksat(c_src,jwt(c_src)+1)*0.001_r8*dzsumall* & - ! ((1-1000._r8*zwt(c_src)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) - endif - endif - else - ! transmissivity of losing stream (c_src == ispval) - transmis = k_anisotropic*(1.e-3_r8*hksat(c,jwt(c)+1)) & - *tdepth(g) - endif - - ! the qflx_latflow_out_vol calculations use the - ! transmissivity to determine whether saturated flow - ! conditions exist, b/c gradients will be nonzero - ! even when no saturated layers are present - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad - -! currently this is redundant to above - qdischarge(c) = qflx_latflow_out_vol(c) - - ! convert volumetric flow to equivalent flux - qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) - - ! hilltop column has no inflow - if (col%colu(c) == ispval) then - qflx_latflow_in(c) = 0._r8 - endif - - ! current outflow is inflow to downhill column normalized by downhill area - if (col%cold(c) /= ispval) then - qflx_latflow_in(col%cold(c)) = qflx_latflow_in(col%cold(c)) + & - 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) - endif - - enddo - - !-- Topographic runoff ------------------------- - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - - ! net lateral flow (positive out) - qflx_net_latflow(c) = qflx_latflow_out(c) - qflx_latflow_in(c) - - fff(c) = 1._r8/ hkdepth(c) - dzsum = 0._r8 - icefracsum = 0._r8 - do j = max(jwt(c),1), nlevsoi - dzsum = dzsum + dzmm(c,j) - icefracsum = icefracsum + icefrac(c,j) * dzmm(c,j) - end do - imped=10._r8**(-e_ice*(icefracsum/dzsum)) - !@@ - ! baseflow - if(zwt(c) <= zi(c,nbedrock(c))) then - if (lun%itype(col%landunit(c)) == istsoil) then - ! apply net lateral flow here - rsub_top(c) = qflx_net_latflow(c) - else - rsub_top(c) = imped * baseflow_scalar & - * tan(rpi/180._r8*col%topo_slope(c))* & - (zi(c,nbedrock(c)) - zwt(c))**(n_baseflow) - endif - else - rsub_top(c) = 0._r8 - endif - - !-- Now remove water via rsub_top - rsub_top_tot = - rsub_top(c) * dtime - - if(rsub_top_tot > 0.) then !rising water table - do j = jwt(c)+1,1,-1 - ! analytical expression for specific yield - s_y = watsat(c,j) & - * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) - s_y=max(s_y,0.02_r8) - - rsub_top_layer=min(rsub_top_tot,(s_y*dz(c,j)*1.e3)) - - rsub_top_layer=max(rsub_top_layer,0._r8) - h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer - - rsub_top_tot = rsub_top_tot - rsub_top_layer - - if (rsub_top_tot <= 0.) then - zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 - exit - else - zwt(c) = zi(c,j-1) - endif - - enddo - - !-- remove residual rsub_top -------------------------------- - h2osfc(c) = h2osfc(c) + rsub_top_tot + ! kinematic wave approximation + if (baseflow_method == 'kinematic') then + dgrad = col%hill_slope(c) + endif + + ! darcy's law + if (baseflow_method == 'darcy') then + if (col%cold(c) /= ispval) then + dgrad = (col%hill_elev(c)-zwt(c)) & + - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) + dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) + else + ! flow between channel and lowest column + ! bankfull height is defined to be zero + dgrad = (col%hill_elev(c)-zwt(c)) & + ! - (tdepth(g) - tdepth_bankfull(g)) + ! ignore overbankfull storage + - min((tdepth(g) - tdepth_bankfull(g)),0._r8) + + dgrad = dgrad / (col%hill_distance(c)) + ! dgrad cannot be negative when channel is empty + if (tdepth(g) <= 0._r8) then + dgrad = max(dgrad, 0._r8) + endif + ! add vertical drainage for losing streams + ! (this could be a separate term from lateral flow...) + if (dgrad < 0._r8) then + ! dgrad = dgrad - 1._r8 + ! adjust lateral gradient w/ k_anisotropic + dgrad = dgrad - 1._r8/k_anisotropic + endif + endif + end if + + ! Calculate transmissivity of source column + if (dgrad >= 0._r8) then + c_src = c + else + c_src = col%cold(c) + endif + + transmis = 0._r8 + if(c_src /= ispval) then + ! transmissivity non-zero only when saturated conditions exist + if(zwt(c_src) <= zi(c_src,nbedrock(c_src))) then + ! sum of layer transmissivities + if (transmissivity_method == 'layersum') then + do j = jwt(c_src)+1, nbedrock(c_src) + if(j == jwt(c_src)+1) then + transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*(zi(c_src,j) - zwt(c_src)) + else + transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*dz(c_src,j) + endif + end do + endif + ! constant conductivity based on shallowest saturated layer hk + if (transmissivity_method == 'constant') then + transmis = (1.e-3_r8*ice_imped(c_src,jwt(c_src)+1)*hksat(c_src,jwt(c_src)+1)) & + *(zi(c_src,nbedrock(c_src)) - zwt(c_src) ) + endif + ! power law profile based on shallowest saturated layer hk + if (transmissivity_method == 'power') then + ! transmis = ice_imped(c_src,jwt(c_src)+1)*hksat(c_src,jwt(c_src)+1)*0.001_r8*dzsumall* & + ! ((1-1000._r8*zwt(c_src)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) + endif + endif + else + ! transmissivity of losing stream (c_src == ispval) + transmis = (1.e-3_r8*ice_imped(c,jwt(c)+1)*hksat(c,jwt(c)+1))*tdepth(g) + endif + ! adjust transmissivity by 'anisotropy factor' + transmis = k_anisotropic*transmis + + ! the qflx_latflow_out_vol calculations use the + ! transmissivity to determine whether saturated flow + ! conditions exist, b/c gradients will be nonzero + ! even when no saturated layers are present + ! qflx_latflow_out_vol(c) = ice_imped(c)*transmis*col%hill_width(c)*dgrad + ! include ice impedance in transmissivity + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad + + ! currently this is redundant to above + qdischarge(c) = qflx_latflow_out_vol(c) + + ! convert volumetric flow to equivalent flux + qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) + + ! hilltop column has no inflow + if (col%colu(c) == ispval) then + qflx_latflow_in(c) = 0._r8 + endif + + ! current outflow is inflow to downhill column normalized by downhill area + if (col%cold(c) /= ispval) then + qflx_latflow_in(col%cold(c)) = qflx_latflow_in(col%cold(c)) + & + 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) + endif + enddo + + ! recalculate average flux for no-lateral flow case + if(no_lateral_flow) then + if (baseflow_method /= 'kinematic') then + call endrun(msg="baseflow_method must be kinematic for no_lateral_flow = .true.! "//errmsg(sourcefile, __LINE__)) + endif + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + l = col%landunit(c) + !need to sum all columns w/ same hillslope id for each column + qflx_latflow_avg(c) = 0._r8 + larea = 0._r8 + do c0 = lun%coli(l), lun%colf(l) + if(col%hillslope_ndx(c0) == col%hillslope_ndx(c)) then + qflx_latflow_avg(c) = qflx_latflow_avg(c) + qflx_latflow_out_vol(c0) + larea = larea + col%hill_area(c0) + endif + enddo + qflx_latflow_avg(c) = 1.e3_r8*qflx_latflow_avg(c)/larea + enddo + endif + + !-- Topographic runoff ------------------------- + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + + ! net lateral flow (positive out) + qflx_net_latflow(c) = qflx_latflow_out(c) - qflx_latflow_in(c) + if(no_lateral_flow) then + qflx_net_latflow(c) = qflx_latflow_avg(c) + endif + + fff(c) = 1._r8/ hkdepth(c) + !@@ + ! baseflow + if(zwt(c) <= zi(c,nbedrock(c))) then + if (lun%itype(col%landunit(c)) == istsoil) then + ! apply net lateral flow here + rsub_top(c) = qflx_net_latflow(c) + else + rsub_top(c) = ice_imped_col(c) * baseflow_scalar & + * tan(rpi/180._r8*col%topo_slope(c))* & + (zi(c,nbedrock(c)) - zwt(c))**(n_baseflow) + endif + else + rsub_top(c) = 0._r8 + endif + + !-- Now remove water via rsub_top + rsub_top_tot = - rsub_top(c) * dtime + + if(rsub_top_tot > 0.) then !rising water table + do j = jwt(c)+1,1,-1 + ! analytical expression for specific yield + s_y = watsat(c,j) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) + s_y=max(s_y,0.02_r8) + + rsub_top_layer=min(rsub_top_tot,(s_y*dz(c,j)*1.e3)) + + rsub_top_layer=max(rsub_top_layer,0._r8) + h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer + + rsub_top_tot = rsub_top_tot - rsub_top_layer + + if (rsub_top_tot <= 0.) then + zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 + exit + else + zwt(c) = zi(c,j-1) + endif + + enddo + + !-- remove residual rsub_top -------------------------------- + h2osfc(c) = h2osfc(c) + rsub_top_tot else ! deepening water table do j = jwt(c)+1, nbedrock(c) @@ -2777,7 +3054,6 @@ subroutine LateralFlowHillslope(bounds, & !-- remove residual rsub_top --------------------------------------------- ! make sure no extra water removed from soil column -!scs? rsub_top(c) = rsub_top(c) - rsub_top_tot/dtime rsub_top(c) = rsub_top(c) + rsub_top_tot/dtime endif diff --git a/src/biogeophys/SurfaceAlbedoMod.F90 b/src/biogeophys/SurfaceAlbedoMod.F90 index 471e0ca2de..8f1a97ef5c 100644 --- a/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/src/biogeophys/SurfaceAlbedoMod.F90 @@ -363,7 +363,6 @@ subroutine SurfaceAlbedo(bounds,nc, & ! Cosine solar zenith angle for next time step do g = bounds%begg,bounds%endg -! coszen_gcell(g) = shr_orb_cosz (nextsw_cday, grc%lat(g), grc%lon(g), declinp1) coszen_grc(g) = shr_orb_cosz (nextsw_cday, grc%lat(g), grc%lon(g), declinp1) end do @@ -374,14 +373,13 @@ subroutine SurfaceAlbedo(bounds,nc, & zenith_angle = acos(coszen_grc(g)) azsun_grc(g) = shr_orb_azimuth(nextsw_cday, grc%lat(g), grc%lon(g), declinp1, zenith_angle) - - coszen_col(c) = shr_orb_cosinc(zenith_angle,azsun_grc(g),col%hill_slope(c),col%hill_aspect(c)) +! hill_slope is [m/m], convert to radians + coszen_col(c) = shr_orb_cosinc(zenith_angle,azsun_grc(g),atan(col%hill_slope(c)),col%hill_aspect(c)) if(coszen_grc(g) > 0._r8 .and. coszen_col(c) < 0._r8) coszen_col(c) = 0._r8 else -! coszen_col(c) = coszen_gcell(g) coszen_col(c) = coszen_grc(g) endif end do @@ -389,7 +387,6 @@ subroutine SurfaceAlbedo(bounds,nc, & p = filter_nourbanp(fp) g = patch%gridcell(p) c = patch%column(p) -! coszen_patch(p) = coszen_gcell(g) coszen_patch(p) = coszen_col(c) end do diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index e836407eb0..e73ce657e6 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -75,8 +75,6 @@ module ColumnType real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column real(r8), pointer :: hill_distance (:) ! along-hill distance of column from bottom of hillslope real(r8), pointer :: hill_aspect (:) ! azimuth angle of column wrt to north, positive to east -! for init_interp, add information on relative position -! real(r8), pointer :: relative_position (:) ! relative position of column along hillslope ! other column characteristics logical , pointer :: hydrologically_active(:) ! true if this column is a hydrologically active type diff --git a/src/main/GridcellType.F90 b/src/main/GridcellType.F90 index 0b7920a57a..30fe988eff 100644 --- a/src/main/GridcellType.F90 +++ b/src/main/GridcellType.F90 @@ -30,7 +30,6 @@ module GridcellType logical , pointer :: active (:) ! just needed for symmetry with other subgrid types integer, pointer :: nbedrock (:) ! index of uppermost bedrock layer - integer, pointer :: ncolumns (:) ! number of columns per hillslope ! Daylength real(r8) , pointer :: max_dayl (:) ! maximum daylength for this grid cell (s) @@ -72,7 +71,6 @@ subroutine Init(this, begg, endg) allocate(this%londeg (begg:endg)) ; this%londeg (:) = nan allocate(this%active (begg:endg)) ; this%active (:) = .true. allocate(this%nbedrock (begg:endg)) ; this%nbedrock (:) = ispval - allocate(this%ncolumns (begg:endg)); this%ncolumns (:) = ispval ! This is initiailized in module DayLength allocate(this%max_dayl (begg:endg)) ; this%max_dayl (:) = nan @@ -98,7 +96,6 @@ subroutine Clean(this) deallocate(this%londeg ) deallocate(this%active ) deallocate(this%nbedrock ) - deallocate(this%ncolumns ) deallocate(this%max_dayl ) deallocate(this%dayl ) deallocate(this%prev_dayl ) diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 12a0063b33..423bfdcde9 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -920,8 +920,6 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call t_startf('hydro2_drainage') call HydrologyDrainage(bounds_clump, & - filter(nc)%num_hilltop, filter(nc)%hilltopc, & - filter(nc)%num_hillbottom, filter(nc)%hillbottomc, & filter(nc)%num_hillslope, filter(nc)%hillslopec, & filter(nc)%num_nolakec, filter(nc)%nolakec, & filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 5a3563d955..04e2d95cc7 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -14,7 +14,7 @@ module clm_initializeMod use clm_varctl , only : iulog use clm_varctl , only : use_lch4, use_cn, use_cndv, use_c13, use_c14, use_fates use clm_varctl , only : nhillslope - use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft, irrig_method, wt_glc_mec, topo_glc_mec, nhillcol + use clm_instur , only : wt_lunit, urban_valid, wt_nat_patch, wt_cft, fert_cft, irrig_method, wt_glc_mec, topo_glc_mec, ncol_per_hillslope use perf_mod , only : t_startf, t_stopf use readParamsMod , only : readParameters use ncdio_pio , only : file_desc_t @@ -57,7 +57,6 @@ subroutine initialize1( ) use controlMod , only: control_init, control_print, NLFilename use ncdio_pio , only: ncd_pio_init use initGridCellsMod , only: initGridCells - use initHillslopeMod , only: initHillslopes, HillslopeDomPft use ch4varcon , only: ch4conrd use UrbanParamsType , only: UrbanInput, IsSimpleBuildTemp ! @@ -169,7 +168,7 @@ subroutine initialize1( ) allocate (wt_glc_mec (begg:endg, maxpatch_glcmec)) allocate (topo_glc_mec(begg:endg, maxpatch_glcmec)) if(use_hillslope) then - allocate (nhillcol (begg:endg )) + allocate (ncol_per_hillslope (begg:endg )) endif ! Read list of Patches and their corresponding parameter values ! Independent of model resolution, Needs to stay before surfrd_get_data @@ -221,15 +220,6 @@ subroutine initialize1( ) call initGridCells(glc_behavior) - if(use_hillslope) then - ! Specify hillslope (column-level) connectivity - call initHillslopes() - - ! Set single pft for hillslope columns -! call HillslopeDomPft() - - endif - ! Set global seg maps for gridcells, landlunits, columns and patches call decompInit_glcp(ns, ni, nj, glc_behavior) @@ -263,7 +253,7 @@ subroutine initialize1( ) ! end of the run for error checking. deallocate (wt_lunit, wt_cft, wt_glc_mec) - if(use_hillslope) deallocate (nhillcol) + if(use_hillslope) deallocate (ncol_per_hillslope) call t_stopf('clm_init1') diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 4547a7c497..46a87f5e6d 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -45,6 +45,7 @@ module clm_instMod use EnergyFluxType , only : energyflux_type use FrictionVelocityMod , only : frictionvel_type use GlacierSurfaceMassBalanceMod , only : glacier_smb_type + use HillslopeHydrologyMod , only : InitHillslope use InfiltrationExcessRunoffMod , only : infiltration_excess_runoff_type use IrrigationMod , only : irrigation_type use LakeStateType , only : lakestate_type @@ -75,7 +76,6 @@ module clm_instMod use ColumnType , only : col use PatchType , only : patch use CLMFatesInterfaceMod , only : hlm_fates_interface_type - use HillslopeHydrologyBaseMod , only : hillslope_geomorphology_type use SoilWaterRetentionCurveMod , only : soil_water_retention_curve_type use NutrientCompetitionMethodMod , only : nutrient_competition_method_type ! @@ -121,7 +121,6 @@ module clm_instMod type(lnd2glc_type), public :: lnd2glc_inst type(glc_behavior_type), target, public :: glc_behavior type(topo_type), public :: topo_inst - class(hillslope_geomorphology_type), allocatable :: hillslope_inst class(soil_water_retention_curve_type), public, allocatable :: soil_water_retention_curve ! CN vegetation types @@ -190,7 +189,6 @@ subroutine clm_instInit(bounds) use initVerticalMod , only : initVertical use accumulMod , only : print_accum_fields - use HillslopeHydrologyFactoryMod , only : create_and_init_hillslope_geomorphology_type use SoilWaterRetentionCurveFactoryMod , only : create_soil_water_retention_curve use decompMod , only : get_proc_bounds use BalanceCheckMod , only : GetBalanceCheckSkipSteps @@ -278,11 +276,6 @@ subroutine clm_instInit(bounds) call canopystate_inst%Init(bounds) - if(use_hillslope) then - allocate(hillslope_inst, & - source=create_and_init_hillslope_geomorphology_type(bounds)) - endif - call soilstate_inst%Init(bounds) call SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) ! sets hydraulic and thermal soil properties @@ -320,6 +313,10 @@ subroutine clm_instInit(bounds) call saturated_excess_runoff_inst%Init(bounds) call infiltration_excess_runoff_inst%Init(bounds) + if(use_hillslope) then + call InitHillslope(bounds, fsurdat) + endif + call solarabs_inst%Init(bounds) call surfalb_inst%Init(bounds) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 10cb50bc9c..364eaf493b 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -127,7 +127,7 @@ module clm_varctl integer, public :: nhillslope = 0 ! maximum number of hillslope columns per landunit - integer, public :: nmaxhillcol = 1 + integer, public :: nmax_col_per_hill = 1 ! do not irrigate by default logical, public :: irrigate = .false. diff --git a/src/main/clm_varsur.F90 b/src/main/clm_varsur.F90 index 5fada22c73..64dcbdf6e4 100644 --- a/src/main/clm_varsur.F90 +++ b/src/main/clm_varsur.F90 @@ -47,7 +47,7 @@ module clm_instur real(r8), pointer :: topo_glc_mec(:,:) ! subgrid hillslope hydrology constituents - integer, pointer :: nhillcol(:) + integer, pointer :: ncol_per_hillslope(:) !----------------------------------------------------------------------- diff --git a/src/main/filterMod.F90 b/src/main/filterMod.F90 index 2831abb6a3..a51687f4dd 100644 --- a/src/main/filterMod.F90 +++ b/src/main/filterMod.F90 @@ -12,7 +12,7 @@ module filterMod use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun - use clm_varctl , only : iulog + use clm_varctl , only : iulog, use_hillslope use decompMod , only : bounds_type use GridcellType , only : grc use LandunitType , only : lun @@ -68,10 +68,6 @@ module filterMod integer, pointer :: hydrologyc(:) ! hydrology filter (columns) integer :: num_hydrologyc ! number of columns in hydrology filter - integer, pointer :: hilltopc(:) ! uppermost column in hillslope - integer :: num_hilltop ! number of hilltop columns - integer, pointer :: hillbottomc(:) ! downhill filter in veg. landunits (columns) - integer :: num_hillbottom ! number of columns downhill integer, pointer :: hillslopec(:) ! hillslope hydrology filter (columns) integer :: num_hillslope ! number of hillslope hydrology (columns) integer, pointer :: urbanl(:) ! urban filter (landunits) @@ -219,9 +215,8 @@ subroutine allocFiltersOneGroup(this_filter) allocate(this_filter(nc)%natvegp(bounds%endp-bounds%begp+1)) allocate(this_filter(nc)%hydrologyc(bounds%endc-bounds%begc+1)) - allocate(this_filter(nc)%hilltopc(bounds%endc-bounds%begc+1)) - allocate(this_filter(nc)%hillbottomc(bounds%endc-bounds%begc+1)) allocate(this_filter(nc)%hillslopec(bounds%endc-bounds%begc+1)) + allocate(this_filter(nc)%urbanp(bounds%endp-bounds%begp+1)) allocate(this_filter(nc)%nourbanp(bounds%endp-bounds%begp+1)) @@ -423,7 +418,7 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio do c = bounds%begc,bounds%endc if (col%active(c) .or. include_inactive) then l = col%landunit(c) - if (lun%nhillslopes(l) > 0) then + if (lun%itype(l) == istsoil .and. use_hillslope) then fs = fs + 1 this_filter(nc)%hillslopec(fs) = c end if @@ -431,30 +426,6 @@ subroutine setFiltersOneGroup(bounds, this_filter, include_inactive, glc_behavio end do this_filter(nc)%num_hillslope = fs - fs = 0 - do c = bounds%begc,bounds%endc - if (col%active(c) .or. include_inactive) then - l = col%landunit(c) - if (lun%nhillslopes(l) > 0 .and. col%colu(c) == ispval) then - fs = fs + 1 - this_filter(nc)%hilltopc(fs) = c - end if - end if - end do - this_filter(nc)%num_hilltop = fs - - fs = 0 - do c = bounds%begc,bounds%endc - if (col%active(c) .or. include_inactive) then - l = col%landunit(c) - if (lun%nhillslopes(l) > 0 .and. col%cold(c) == ispval) then - fs = fs + 1 - this_filter(nc)%hillbottomc(fs) = c - end if - end if - end do - this_filter(nc)%num_hillbottom = fs - ! Create prognostic crop and soil w/o prog. crop filters at patch-level ! according to where the crop model should be used diff --git a/src/main/initHillslopeMod.F90 b/src/main/initHillslopeMod.F90 deleted file mode 100644 index c00dd7190c..0000000000 --- a/src/main/initHillslopeMod.F90 +++ /dev/null @@ -1,188 +0,0 @@ -module initHillslopeMod - -#include "shr_assert.h" - - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Initializes (column-level) hillslope connectivity. - ! - ! !USES: - - use shr_kind_mod , only : r8 => shr_kind_r8 - use shr_log_mod , only : errMsg => shr_log_errMsg - use spmdMod , only : masterproc,iam - use abortutils , only : endrun - use clm_varctl , only : iulog - use decompMod , only : bounds_type - use LandunitType , only : lun - use ColumnType , only : col - - ! - ! !PUBLIC TYPES: - implicit none - private - ! - ! !PUBLIC MEMBER FUNCTIONS: - public initHillslopes ! initialize hillslope connectivity - public HillslopeDomPft ! change patch weights to a single pft - ! - - character(len=*), parameter, private :: sourcefile = & - __FILE__ - !----------------------------------------------------------------------- - -contains - - !------------------------------------------------------------------------ - subroutine initHillslopes() - ! - ! !DESCRIPTION: - ! Initialize hillslope connectivity. Each landunit may have multiple - ! hillslopes, and each hillslope may have multiple columns. Specify - ! uphill and downhill neighbors sequentially based on col%coli, col%colf. - ! Hilltop columns have no uphill neighbor; hillbottom columns have no - ! downhill neighbor. - - ! - ! !USES - use decompMod , only : get_proc_bounds, get_clump_bounds, get_proc_clumps - use clm_varctl , only : nhillslope - use landunit_varcon , only : istsoil, istcrop - ! - ! !ARGUMENTS: - ! - ! !LOCAL VARIABLES: - integer :: n,nc,nh,l,c,ci,cf ! indices - integer :: nclumps ! number of clumps on this processor - integer :: ncol_per_hill - type(bounds_type) :: bounds_proc - type(bounds_type) :: bounds_clump - integer :: begg, endg, begl, endl, begc, endc, begp, endp, & - begCohort, endCohort - !------------------------------------------------------------------------ - - nclumps = get_proc_clumps() - - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) - do nc = 1, nclumps - - call get_clump_bounds(nc, bounds_clump) - - do l = bounds_clump%begl, bounds_clump%endl - -! Set number of hillslopes; total number of columns already set -! in clm_ptrs_compdown; this must be consistent with how columns set in -! subgrid_get_info_* routines in subgridMod -! currently only _natveg specifies multiple columns - if (lun%itype(l) == istsoil) then - lun%nhillslopes(l) = nhillslope - else - lun%nhillslopes(l) = 0 - endif - - if (lun%nhillslopes(l) > 0) then - -! number of columns per hillslope = lun%ncolumns / lun%nhillslopes -! 1st column index of each hillslope is coli+(n-1)*ncol_per_hill for n(1:nhillslope) -! last column index is coli+n*ncol_per_hill-1 -! This will be overwritten in HillslopeHydrologySurfaceDataMod - ncol_per_hill = lun%ncolumns(l) / lun%nhillslopes(l) - ! loop over hillslopes - do nh = 1,lun%nhillslopes(l) - ci = lun%coli(l) + (nh-1)*ncol_per_hill - cf = lun%coli(l) + (nh)*ncol_per_hill - 1 - ! loop over columns within each hillslope - do n = 1, ncol_per_hill - c = ci + (n-1) - - col%hillslope_ndx(c) = nh - - ! downhill columns (hillbottom has no downhill neighbor) - if(c < cf) then - col%cold(c) = c + 1 - endif - ! uphill columns (hilltop has no uphill neighbor) - if(c > ci) then - col%colu(c) = c - 1 - endif - enddo ! end loop n - enddo ! end loop nh - endif - - enddo ! end loop l - enddo ! end loop nc - !$OMP END PARALLEL DO - - end subroutine initHillslopes - - !------------------------------------------------------------------------ - subroutine HillslopeDomPft() - ! - ! !DESCRIPTION: - ! Reassign patch weights such that each column has a single, - ! dominant pft. - - ! - ! !USES - use decompMod , only : get_clump_bounds, get_proc_clumps - use clm_varcon , only : ispval - use landunit_varcon , only : istsoil, istcrop - use PatchType , only : patch - ! - ! !ARGUMENTS: - ! - ! !LOCAL VARIABLES: - integer :: n,nc,p,pu,pl,l,c ! indices - integer :: nclumps ! number of clumps on this processor - integer :: upland_ivt = 13 ! c3 non-arctic grass - integer :: lowland_ivt = 8 ! broadleaf deciduous tree - real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc - type(bounds_type) :: bounds_proc - type(bounds_type) :: bounds_clump - - !------------------------------------------------------------------------ - - nclumps = get_proc_clumps() - - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) - do nc = 1, nclumps - - call get_clump_bounds(nc, bounds_clump) - - do l = bounds_clump%begl, bounds_clump%endl - - if (lun%itype(l) == istsoil) then - do c = lun%coli(l), lun%colf(l) - - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - - do p = col%patchi(c), col%patchf(c) - if(patch%itype(p) == lowland_ivt) pl = p - if(patch%itype(p) == upland_ivt) pu = p - enddo - - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - - ! hillbottom - if(col%cold(c) == ispval) then - patch%wtcol(pl) = sum_wtcol - patch%wtlunit(pl) = sum_wtlun - patch%wtgcell(pl) = sum_wtgrc - else - patch%wtcol(pu) = sum_wtcol - patch%wtlunit(pu) = sum_wtlun - patch%wtgcell(pu) = sum_wtgrc - endif - enddo ! end loop c - endif - enddo ! end loop l - enddo ! end loop nc - !$OMP END PARALLEL DO - - end subroutine HillslopeDomPft - -end module initHillslopeMod diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 9619c703bf..ec1de7da94 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -134,7 +134,7 @@ subroutine subgrid_get_info_natveg(gi, npatches, ncols, nlunits) ! ! !USES use clm_varpar, only : natpft_lb, natpft_ub - use clm_instur, only : nhillcol + use clm_instur, only : ncol_per_hillslope use clm_varctl, only : use_hillslope ! ! !ARGUMENTS: @@ -161,7 +161,7 @@ subroutine subgrid_get_info_natveg(gi, npatches, ncols, nlunits) nlunits = 1 if(use_hillslope) then ! ensure ncols is > 0 - ncols = max(nhillcol(gi),1) + ncols = max(ncol_per_hillslope(gi),1) else ncols = 1 endif diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index fce3be9941..974c2b68bf 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -934,8 +934,8 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! Determine number of hillslopes and columns for hillslope hydrology mode ! ! !USES: - use clm_instur, only : nhillcol - use clm_varctl, only : nhillslope,nmaxhillcol + use clm_instur, only : ncol_per_hillslope + use clm_varctl, only : nhillslope,nmax_col_per_hill use ncdio_pio , only : ncd_inqdid, ncd_inqdlen ! ! !ARGUMENTS: @@ -967,22 +967,22 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! maximum number of columns per landunit call ncd_inqdid(ncid,'nmaxhillcol',dimid,readvar) if (.not. readvar) then - write(iulog,*)'surfrd error: nmaxhillcol not on surface data file' - nmaxhillcol = 1 + write(iulog,*)'surfrd error: nmax_col_per_hill not on surface data file' + nmax_col_per_hill = 1 else call ncd_inqdlen(ncid,dimid,nh) - nmaxhillcol = nh + nmax_col_per_hill = nh endif ! actual number of columns per landunit allocate(arrayl(begg:endg)) call ncd_io(ncid=ncid, varname='nhillcolumns', flag='read', data=arrayl, & dim1name=grlnd, readvar=readvar) if (.not. readvar) then - write(iulog,*)'surfrd error: nhillcol not on surface data file' - nhillcol(begg:endg) = 1 - write(iulog,*)'setting nhillcol[:] = 1' + write(iulog,*)'surfrd error: nhillcolumns not on surface data file' + ncol_per_hillslope(begg:endg) = 1 + write(iulog,*)'setting ncol_per_hillslope[:] = 1' else - nhillcol(begg:endg) = arrayl(begg:endg) + ncol_per_hillslope(begg:endg) = arrayl(begg:endg) endif deallocate(arrayl) From 151a47465b0209cb0d84b3737f0f9cce6b734458 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 22 Apr 2020 10:38:47 -0600 Subject: [PATCH 029/153] minor cleanup --- src/biogeophys/BalanceCheckMod.F90 | 37 ----------------------------- src/biogeophys/SoilHydrologyMod.F90 | 8 ++----- src/main/clm_driver.F90 | 2 +- src/main/initGridCellsMod.F90 | 2 +- 4 files changed, 4 insertions(+), 45 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index b616e25d64..ede5358e04 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -637,41 +637,6 @@ subroutine BalanceCheck( bounds, & ! Solar radiation energy balance check -<<<<<<< HEAD - found = .false. - do p = bounds%begp, bounds%endp - if (patch%active(p)) then - if ( (errsol(p) /= spval) .and. (abs(errsol(p)) > 1.e-7_r8) ) then - found = .true. - indexp = p - indexg = patch%gridcell(indexp) - end if - end if - end do - if ( found .and. (DAnstep > skip_steps) ) then - write(iulog,*)'WARNING:: BalanceCheck, solar radiation balance error (W/m2)' - write(iulog,*)'nstep = ',nstep - write(iulog,*)'errsol = ',errsol(indexp) - c = patch%column(indexp) - write(iulog,*)'index p,c = ',indexp,c - write(iulog,*)' col%itype= ',col%itype(c), & - ' lun%itype= ',lun%itype(col%landunit(c)) - - if (abs(errsol(indexp)) > 1.e-5_r8 ) then - write(iulog,*)'clm model is stopping - error is greater than 1e-5 (W/m2)' - write(iulog,*)'fsa = ',fsa(indexp) - write(iulog,*)'fsr = ',fsr(indexp) - write(iulog,*)'forc_solad(1) = ',forc_solad(indexg,1) - write(iulog,*)'forc_solad(2) = ',forc_solad(indexg,2) - write(iulog,*)'forc_solai(1) = ',forc_solai(indexg,1) - write(iulog,*)'forc_solai(2) = ',forc_solai(indexg,2) - write(iulog,*)'forc_tot = ',forc_solad(indexg,1)+forc_solad(indexg,2) & - +forc_solai(indexg,1)+forc_solai(indexg,2) - write(iulog,*)'clm model is stopping' - call endrun(decomp_index=indexp, clmlevel=namep, msg=errmsg(sourcefile, __LINE__)) - end if - end if -======= errsol_max_val = maxval( abs(errsol(bounds%begp:bounds%endp)), mask = (errsol(bounds%begp:bounds%endp) /= spval) ) if ((errsol_max_val > energy_warning_thresh) .and. (DAnstep > skip_steps)) then @@ -695,8 +660,6 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'clm model is stopping' call endrun(decomp_index=indexp, clmlevel=namep, msg=errmsg(sourcefile, __LINE__)) end if ->>>>>>> escomp/master - end if ! Longwave radiation energy balance check diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index bade1e7279..4e0929a0ce 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1908,7 +1908,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & ! Get time step - dtime = get_step_size() + dtime = get_step_size_real() ! locate frost table and perched water table do fc = 1, num_hydrologyc @@ -2588,7 +2588,6 @@ subroutine LateralFlowHillslope(bounds, & associate( & nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) - h2osno => waterstatebulk_inst%h2osno_col , & ! Input: [real(r8) (:) ] surface water (mm) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) @@ -2626,9 +2625,6 @@ subroutine LateralFlowHillslope(bounds, & qflx_snwcp_liq => waterfluxbulk_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] qflx_ice_runoff_xs => waterfluxbulk_inst%qflx_ice_runoff_xs_col , & ! Output: [real(r8) (:) ] solid runoff from excess ice in soil (mm H2O /s) [+] - qflx_dew_grnd => waterfluxbulk_inst%qflx_dew_grnd_col , & ! Output: [real(r8) (:) ] ground surface dew formation (mm H2O /s) [+] - qflx_dew_snow => waterfluxbulk_inst%qflx_dew_snow_col , & ! Output: [real(r8) (:) ] surface dew added to snow pack (mm H2O /s) [+] - qflx_sub_snow => waterfluxbulk_inst%qflx_sub_snow_col , & ! Output: [real(r8) (:) ] sublimation rate from snow pack (mm H2O /s) [+] qflx_drain => waterfluxbulk_inst%qflx_drain_col , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) qflx_qrgwl => waterfluxbulk_inst%qflx_qrgwl_col , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes (mm H2O /s) qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] @@ -2638,7 +2634,7 @@ subroutine LateralFlowHillslope(bounds, & ! Get time step - dtime = get_step_size() + dtime = get_step_size_real() nstep = get_nstep() ! Convert layer thicknesses from m to mm diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 969fc7e559..9720ace48f 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -948,7 +948,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & filter(nc)%num_urbanc, filter(nc)%urbanc, & filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & - atm2lnd_inst, glc2lnd_inst, temperature_inst, & + glc2lnd_inst, temperature_inst, & soilhydrology_inst, soilstate_inst, water_inst%waterstatebulk_inst, & water_inst%waterdiagnosticbulk_inst, water_inst%waterbalancebulk_inst, & water_inst%waterfluxbulk_inst, water_inst%wateratm2lndbulk_inst, & diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index 1346c86f82..e2c5a6de43 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -11,7 +11,7 @@ module initGridCellsMod ! these modules (or the two modules should be combined into one). ! ! !USES: - +#include "shr_assert.h" use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use spmdMod , only : masterproc,iam From 22a433b9645a9e86196f93572dc09152dbe25572 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 23 Apr 2020 11:35:25 -0600 Subject: [PATCH 030/153] fix bug in hillslope_area calculation --- src/biogeophys/HillslopeHydrologyMod.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 16c781e817..6e2e956238 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -273,6 +273,7 @@ subroutine InitHillslope(bounds,fsurdat) ! weighted relative to one another via pct_hillslope hillslope_area = 0._r8 do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) hillslope_area = hillslope_area & + col%hill_area(c)*(real(pct_hillslope(l,nh),r8)*0.01_r8) enddo From f69d6e01dda3ce555473232533db027d9253ab19 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 23 Apr 2020 12:26:48 -0600 Subject: [PATCH 031/153] add downscaling in TopoMod --- src/main/TopoMod.F90 | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index 43b935bed0..3450db9ba2 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -13,8 +13,9 @@ module TopoMod use LandunitType , only : lun use glc2lndMod , only : glc2lnd_type use glcBehaviorMod , only : glc_behavior_type - use landunit_varcon, only : istice_mec + use landunit_varcon, only : istice_mec, istsoil use filterColMod , only : filter_col_type, col_filter_from_logical_array_active_only + use clm_varctl , only : use_hillslope ! ! !PUBLIC TYPES: implicit none @@ -139,8 +140,14 @@ subroutine InitCold(this, bounds) ! For other landunits, arbitrarily initialize topo_col to 0 m; for landunits ! where this matters, this will get overwritten in the run loop by values sent ! from CISM - this%topo_col(c) = 0._r8 - this%needs_downscaling_col(c) = .false. + if (lun%itype(l) == istsoil .and. use_hillslope) then + this%topo_col(c) = col%hill_elev(c) ! + atm_topo(g) + this%needs_downscaling_col(c) = .true. + else + this%topo_col(c) = 0._r8 + this%needs_downscaling_col(c) = .false. + endif + end if end do @@ -218,7 +225,7 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & ! ! !LOCAL VARIABLES: integer :: begc, endc - integer :: c, g + integer :: c, l, g character(len=*), parameter :: subname = 'UpdateTopo' !----------------------------------------------------------------------- @@ -250,7 +257,13 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & do c = bounds%begc, bounds%endc if (.not. this%needs_downscaling_col(c)) then g = col%gridcell(c) - this%topo_col(c) = atm_topo(g) + l = col%landunit(c) + if (lun%itype(l) == istsoil .and. use_hillslope) then + this%topo_col(c) = col%hill_elev(c) + atm_topo(g) + this%needs_downscaling_col(c) = .true. + else + this%topo_col(c) = atm_topo(g) + endif end if end do From e452966ce6ef2b2216a3ad766b32a9c300b9c45f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 24 Apr 2020 07:38:38 -0600 Subject: [PATCH 032/153] remove urban from endrun message --- src/biogeophys/BalanceCheckMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index ede5358e04..5b9c58fdba 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -437,7 +437,7 @@ subroutine BalanceCheck( bounds, & ' errh2o= ',errh2o(indexc) if ((errh2o_max_val > error_thresh) .and. (DAnstep > skip_steps)) then - write(iulog,*)'clm urban model is stopping - error is greater than 1e-5 (mm)' + write(iulog,*)'clm model is stopping - error is greater than 1e-5 (mm)' write(iulog,*)'nstep = ',nstep write(iulog,*)'errh2o = ',errh2o(indexc) write(iulog,*)'forc_rain = ',forc_rain_col(indexc)*dtime From 4ee9ace9e39338d5417408d0878e36338fe78ea4 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 4 Sep 2020 10:09:43 -0600 Subject: [PATCH 033/153] fix wtlunit recalculation --- src/biogeophys/HillslopeHydrologyMod.F90 | 30 ++++++++++++++---------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 6e2e956238..9fe0a1a4af 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -61,12 +61,12 @@ subroutine InitHillslope(bounds,fsurdat) ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds character(len=*) , intent(in) :: fsurdat ! surface data file name - real(r8), pointer :: ihillslope_in(:,:) ! read in - integer - real(r8), pointer :: fhillslope_in(:,:) ! read in - float - integer, allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope + integer, pointer :: ihillslope_in(:,:) ! read in - integer integer, allocatable :: hill_ndx(:,:) ! hillslope index integer, allocatable :: col_ndx(:,:) ! column index integer, allocatable :: col_dndx(:,:) ! downhill column index + real(r8), pointer :: fhillslope_in(:,:) ! read in - float + real(r8), allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] real(r8), allocatable :: hill_aspect(:,:) ! hillslope azimuth [radians] real(r8), allocatable :: hill_area(:,:) ! hillslope area [m2] @@ -104,9 +104,9 @@ subroutine InitHillslope(bounds,fsurdat) hill_height (bounds%begl:bounds%endl,nmax_col_per_hill), & stat=ierr) - allocate(ihillslope_in(bounds%begg:bounds%endg,nhillslope)) + allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) - call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) @@ -114,9 +114,9 @@ subroutine InitHillslope(bounds,fsurdat) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) - pct_hillslope(l,:) = ihillslope_in(g,:) + pct_hillslope(l,:) = fhillslope_in(g,:) enddo - deallocate(ihillslope_in) + deallocate(fhillslope_in) allocate(ihillslope_in(bounds%begg:bounds%endg,nmax_col_per_hill)) @@ -274,8 +274,10 @@ subroutine InitHillslope(bounds,fsurdat) hillslope_area = 0._r8 do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) - hillslope_area = hillslope_area & - + col%hill_area(c)*(real(pct_hillslope(l,nh),r8)*0.01_r8) + if (nh > 0) then + hillslope_area = hillslope_area & + + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + endif enddo ! if missing hillslope information on surface dataset, fill data @@ -291,15 +293,19 @@ subroutine InitHillslope(bounds,fsurdat) nh = col%hillslope_ndx(c) pct_hillslope(l,nh) = 100/nhillslope hillslope_area = hillslope_area & - + col%hill_area(c)*(real(pct_hillslope(l,nh),r8)*0.01_r8) + + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) enddo endif ! Recalculate column weights using input areas do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) - col%wtlunit(c) = col%hill_area(c) & - * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + if (nh > 0) then + col%wtlunit(c) = col%hill_area(c) & + * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + else + col%wtlunit(c) = 0._r8 + endif enddo endif From 7fbfe3835deeb60aa94d1ac2e2fde7233e2876c2 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 9 Oct 2020 07:10:22 -0600 Subject: [PATCH 034/153] fix elevation used in TopoMod --- src/main/TopoMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index 3450db9ba2..dbf7c903a4 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -141,7 +141,7 @@ subroutine InitCold(this, bounds) ! where this matters, this will get overwritten in the run loop by values sent ! from CISM if (lun%itype(l) == istsoil .and. use_hillslope) then - this%topo_col(c) = col%hill_elev(c) ! + atm_topo(g) + this%topo_col(c) = col%hill_elev(c) this%needs_downscaling_col(c) = .true. else this%topo_col(c) = 0._r8 @@ -259,7 +259,7 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & g = col%gridcell(c) l = col%landunit(c) if (lun%itype(l) == istsoil .and. use_hillslope) then - this%topo_col(c) = col%hill_elev(c) + atm_topo(g) + this%topo_col(c) = col%hill_elev(c) this%needs_downscaling_col(c) = .true. else this%topo_col(c) = atm_topo(g) From 3a50c6a0e0466411c2af250599181574e1f934fe Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 18 Nov 2020 14:16:31 -0700 Subject: [PATCH 035/153] add hillslope bedrock field --- src/biogeophys/HillslopeHydrologyMod.F90 | 184 ++++++++++++++++++++--- src/main/ColumnType.F90 | 12 +- src/main/TopoMod.F90 | 24 ++- 3 files changed, 201 insertions(+), 19 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 0a6605b293..5224b6d774 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -25,7 +25,8 @@ module HillslopeHydrologyMod public HillslopeSetLowlandUplandPfts public HillslopeDominantPft public HillslopeDominantLowlandPft - + public HillslopePftFromFile + ! PRIVATE character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -65,6 +66,7 @@ subroutine InitHillslope(bounds,fsurdat) integer, allocatable :: hill_ndx(:,:) ! hillslope index integer, allocatable :: col_ndx(:,:) ! column index integer, allocatable :: col_dndx(:,:) ! downhill column index + integer, allocatable :: hill_pftndx(:,:) ! hillslope pft index [] real(r8), pointer :: fhillslope_in(:,:) ! read in - float real(r8), allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] @@ -73,6 +75,7 @@ subroutine InitHillslope(bounds,fsurdat) real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] + real(r8), allocatable :: hill_bedrock(:,:) ! hillslope bedrock depth [m] type(file_desc_t) :: ncid ! netcdf id logical :: readvar ! check whether variable on file @@ -222,8 +225,36 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) hill_height(l,:) = fhillslope_in(g,:) enddo + + call ncd_io(ncid=ncid, varname='h_bedrock', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + allocate(hill_bedrock (bounds%begl:bounds%endl,nmax_col_per_hill), stat=ierr) + if (masterproc) then + write(iulog,*) 'h_bedrock found on surface data set' + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_bedrock(l,:) = fhillslope_in(g,:) + enddo + deallocate(fhillslope_in) + allocate(ihillslope_in(bounds%begg:bounds%endg,nmax_col_per_hill)) + call ncd_io(ncid=ncid, varname='h_pftndx', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + allocate(hill_pftndx (bounds%begl:bounds%endl,nmax_col_per_hill), stat=ierr) + if (masterproc) then + write(iulog,*) 'h_pftndx found on surface data set' + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_pftndx(l,:) = ihillslope_in(g,:) + enddo + end if + + deallocate(ihillslope_in) + ! Set hillslope hydrology column level variables ! This needs to match how columns set up in subgridMod do l = bounds%begl,bounds%endl @@ -269,6 +300,18 @@ subroutine InitHillslope(bounds,fsurdat) col%hill_area(c) = hill_area(l,ci) ! azimuth of column col%hill_aspect(c) = hill_aspect(l,ci) + ! pft index of column + if ( allocated(hill_bedrock) ) then + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < hill_bedrock(l,ci) .and. zisoi(j) >= hill_bedrock(l,ci)) then + col%nbedrock(c) = j + end if + endif + enddo + endif + if ( allocated(hill_pftndx) ) & + col%hill_pftndx(c) = hill_pftndx(l,ci) enddo @@ -317,24 +360,38 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(pct_hillslope,hill_ndx,col_ndx,col_dndx, & hill_slope,hill_area,hill_length, & hill_width,hill_height,hill_aspect) - - call ncd_pio_closefile(ncid) - - ! Modify pft distributions - !upland_ivt = 13 ! c3 non-arctic grass - !lowland_ivt = 7 ! broadleaf deciduous tree - !call HillslopeSetLowlandUplandPfts(lowland_ivt=7,upland_ivt=13) - call HillslopeDominantPft() + if ( allocated(hill_bedrock) ) then + deallocate(hill_bedrock) + else + ! Modify hillslope soil thickness profile + call HillslopeSoilThicknessProfile(bounds,& + soil_profile_method=soil_profile_set_lowland_upland,& + soil_depth_lowland_in=8.0_r8,soil_depth_upland_in=8.0_r8) + + endif + if ( allocated(hill_pftndx) ) then + deallocate(hill_pftndx) + call HillslopePftFromFile() + else + ! Modify pft distributions + ! this may require modifying subgridMod/natveg_patch_exists + ! to ensure patch exists in every gridcell + + call HillslopeDominantPft() - ! Modify hillslope soil thickness profile - !call HillslopeSoilThicknessProfile(bounds,& - !soil_profile_method=soil_profile_set_lowland_upland) + !upland_ivt = 13 ! c3 non-arctic grass + !lowland_ivt = 7 ! broadleaf deciduous tree + !call HillslopeSetLowlandUplandPfts(lowland_ivt=7,upland_ivt=13) + endif + + call ncd_pio_closefile(ncid) end subroutine InitHillslope !----------------------------------------------------------------------- - subroutine HillslopeSoilThicknessProfile(bounds,soil_profile_method) + subroutine HillslopeSoilThicknessProfile(bounds,& + soil_profile_method,soil_depth_lowland_in,soil_depth_upland_in) ! ! !DESCRIPTION: ! Modify soil thickness across hillslope by changing @@ -356,19 +413,34 @@ subroutine HillslopeSoilThicknessProfile(bounds,soil_profile_method) ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds integer, intent(in) :: soil_profile_method - integer :: c, l, g, i, j + real(r8), intent(in), optional :: soil_depth_lowland_in + real(r8), intent(in), optional :: soil_depth_upland_in + integer :: c, l, g, i, j real(r8) :: min_hill_dist, max_hill_dist real(r8) :: m, b ! linear soil thickness slope/intercept real(r8) :: soil_depth_col - ! soil_depth_* could be input args, but using parameters for now... - real(r8), parameter :: soil_depth_lowland = 3.0 - real(r8), parameter :: soil_depth_upland = 0.5 + real(r8) :: soil_depth_lowland + real(r8) :: soil_depth_upland + real(r8), parameter :: soil_depth_lowland_default = 8.0 + real(r8), parameter :: soil_depth_upland_default = 8.0 character(len=*), parameter :: subname = 'HillslopeSoilThicknessProfile' !----------------------------------------------------------------------- + if(present(soil_depth_lowland_in)) then + soil_depth_lowland = soil_depth_lowland_in + else + soil_depth_lowland = soil_depth_lowland_default + endif + + if(present(soil_depth_upland_in)) then + soil_depth_upland = soil_depth_upland_in + else + soil_depth_upland = soil_depth_upland_default + endif + do l = bounds%begl,bounds%endl if(lun%itype(l) == istsoil) then ! Specify lowland/upland soil thicknesses separately @@ -670,4 +742,82 @@ subroutine HillslopeDominantLowlandPft() end subroutine HillslopeDominantLowlandPft + !------------------------------------------------------------------------ + subroutine HillslopePftFromFile() + ! + ! !DESCRIPTION: + ! Reassign patch weights using indices from surface data file + ! + ! !USES + use LandunitType , only : lun + use ColumnType , only : col + use decompMod , only : get_clump_bounds, get_proc_clumps + use clm_varcon , only : ispval + use landunit_varcon , only : istsoil + use PatchType , only : patch + + use GridcellType , only : grc + ! + ! !ARGUMENTS: + ! + ! !LOCAL VARIABLES: + integer :: n,nc,p,pc,l,c ! indices + integer :: nclumps ! number of clumps on this processor + real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc + type(bounds_type) :: bounds_proc + type(bounds_type) :: bounds_clump + + !------------------------------------------------------------------------ + + nclumps = get_proc_clumps() + + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + do nc = 1, nclumps + + call get_clump_bounds(nc, bounds_clump) + + do l = bounds_clump%begl, bounds_clump%endl + + if (lun%itype(l) == istsoil) then + do c = lun%coli(l), lun%colf(l) + ! this may require modifying + ! subgridMod/natveg_patch_exists to ensure that + ! a patch exists on each column + + ! find patch index of specified vegetation type + pc = ispval + do p = col%patchi(c), col%patchf(c) + if(patch%itype(p) == col%hill_pftndx(c)) pc = p +!scs if(patch%itype(p) == 1) pc = p + enddo + + ! only reweight if pft exist within column + if (pc /= ispval) then + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + + patch%wtcol(pc) = sum_wtcol + patch%wtlunit(pc) = sum_wtlun + patch%wtgcell(pc) = sum_wtgrc + + else + write(iulog,*) 'no pft in column ',c, col%hill_pftndx(c) + write(iulog,*) 'pfts ',c,patch%itype(col%patchi(c):col%patchf(c)) + write(iulog,*) 'weights ',c,patch%wtcol(col%patchi(c):col%patchf(c)) + write(iulog,*) 'location ',c,grc%londeg(col%gridcell(c)),grc%latdeg(col%gridcell(c)) + + endif + enddo ! end loop c + endif + enddo ! end loop l + enddo ! end loop nc + !$OMP END PARALLEL DO + + end subroutine HillslopePftFromFile + end module HillslopeHydrologyMod diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 171aedb354..3e8ec7819d 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -69,6 +69,7 @@ module ColumnType integer, pointer :: colu (:) ! column index of uphill column (hillslope hydrology) integer, pointer :: cold (:) ! column index of downhill column (hillslope hydrology) integer, pointer :: hillslope_ndx (:) ! hillslope identifier + integer, pointer :: hill_pftndx (:) ! specified (single) pft index of column real(r8), pointer :: hill_elev (:) ! mean elevation of column relative to mean gridcell elevation real(r8), pointer :: hill_slope (:) ! mean along-hill slope real(r8), pointer :: hill_area (:) ! mean surface area @@ -139,6 +140,7 @@ subroutine Init(this, begc, endc) allocate(this%colu (begc:endc)) ; this%colu (:) = ispval allocate(this%cold (begc:endc)) ; this%cold (:) = ispval allocate(this%hillslope_ndx(begc:endc)) ; this%hillslope_ndx (:) = ispval + allocate(this%hill_pftndx(begc:endc)) ; this%hill_pftndx (:) = ispval allocate(this%hill_elev(begc:endc)) ; this%hill_elev (:) = spval allocate(this%hill_slope(begc:endc)) ; this%hill_slope (:) = spval allocate(this%hill_area(begc:endc)) ; this%hill_area (:) = spval @@ -190,7 +192,15 @@ subroutine Clean(this) deallocate(this%col_ndx ) deallocate(this%colu ) deallocate(this%cold ) - deallocate(this%urbpoi) + deallocate(this%hillslope_ndx) + deallocate(this%hill_pftndx ) + deallocate(this%hill_elev ) + deallocate(this%hill_slope ) + deallocate(this%hill_area ) + deallocate(this%hill_width ) + deallocate(this%hill_distance) + deallocate(this%hill_aspect ) + deallocate(this%urbpoi ) end subroutine Clean !----------------------------------------------------------------------- diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index dbf7c903a4..2bd3ad8026 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -226,6 +226,8 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & ! !LOCAL VARIABLES: integer :: begc, endc integer :: c, l, g + real(r8), allocatable :: mean_hillslope_elevation(:) + real(r8):: mhe_norm character(len=*), parameter :: subname = 'UpdateTopo' !----------------------------------------------------------------------- @@ -247,6 +249,25 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & this%topo_col(begc:endc), & this%needs_downscaling_col(begc:endc)) + ! calculate area-weighted mean hillslope elevation on each landunit + if (use_hillslope) then + allocate(mean_hillslope_elevation(bounds%begl:bounds%endl)) + mean_hillslope_elevation(:) = 0._r8 + do l = bounds%begl, bounds%endl + if (lun%itype(l) == istsoil) then + mhe_norm = 0._r8 + do c = lun%coli(l), lun%colf(l) + mean_hillslope_elevation(l) = mean_hillslope_elevation(l) & + + col%hill_elev(c)*col%hill_area(c) + mhe_norm = mhe_norm + col%hill_area(c) + enddo + if (mhe_norm > 0) then + mean_hillslope_elevation(l) = mean_hillslope_elevation(l)/mhe_norm + endif + endif + enddo + endif + ! For any point that isn't downscaled, set its topo value to the atmosphere's ! topographic height. This shouldn't matter, but is useful if topo_col is written to ! the history file. @@ -259,7 +280,8 @@ subroutine UpdateTopo(this, bounds, num_icemecc, filter_icemecc, & g = col%gridcell(c) l = col%landunit(c) if (lun%itype(l) == istsoil .and. use_hillslope) then - this%topo_col(c) = col%hill_elev(c) + this%topo_col(c) = atm_topo(g) & + + (col%hill_elev(c) - mean_hillslope_elevation(l)) this%needs_downscaling_col(c) = .true. else this%topo_col(c) = atm_topo(g) From fbbe8764d5041e0a309b28a635003543a3e27ede Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 9 Mar 2021 11:50:49 -0700 Subject: [PATCH 036/153] add precipitation downscaling --- src/main/atm2lndMod.F90 | 179 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 165 insertions(+), 14 deletions(-) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index ded56acc14..166e6a3064 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -18,7 +18,7 @@ module atm2lndMod use decompMod , only : bounds_type use atm2lndType , only : atm2lnd_type use TopoMod , only : topo_type - use SurfaceAlbedoType, only : surfalb_type !scs + use SurfaceAlbedoType, only : surfalb_type use filterColMod , only : filter_col_type use LandunitType , only : lun use ColumnType , only : col @@ -48,6 +48,9 @@ module atm2lndMod private :: build_normalization ! Compute normalization factors so that downscaled fields are conservative private :: check_downscale_consistency ! Check consistency of downscaling + private :: downscale_hillslope_solar ! Downscale incoming direct solar radiation based on local slope and aspect. + private :: downscale_hillslope_precipitation ! Downscale precipitation based on local topographic height. + character(len=*), parameter, private :: sourcefile = & __FILE__ !----------------------------------------------------------------------- @@ -132,9 +135,10 @@ subroutine downscale_forcings(bounds, & ! temporaries for topo downscaling real(r8) :: hsurf_g,hsurf_c real(r8) :: Hbot, zbot - real(r8) :: tbot_g, pbot_g, thbot_g, qbot_g, qs_g, rhos_g - real(r8) :: tbot_c, pbot_c, thbot_c, qbot_c, qs_c, rhos_c + real(r8) :: tbot_g, pbot_g, thbot_g, qbot_g, qs_g, es_g, rhos_g + real(r8) :: tbot_c, pbot_c, thbot_c, qbot_c, qs_c, es_c, rhos_c real(r8) :: rhos_c_estimate, rhos_g_estimate + real(r8) :: dum1, dum2 character(len=*), parameter :: subname = 'downscale_forcings' !----------------------------------------------------------------------- @@ -147,6 +151,8 @@ subroutine downscale_forcings(bounds, & ! Gridcell-level metadata: forc_topo_g => atm2lnd_inst%forc_topo_grc , & ! Input: [real(r8) (:)] atmospheric surface height (m) + forc_rain_g => wateratm2lndbulk_inst%forc_rain_not_downscaled_grc , & ! Input: [real(r8) (:)] rain rate [mm/s] + forc_snow_g => wateratm2lndbulk_inst%forc_snow_not_downscaled_grc , & ! Input: [real(r8) (:)] snow rate [mm/s] ! Column-level metadata: topo_c => topo_inst%topo_col , & ! Input: [real(r8) (:)] column surface height (m) @@ -158,11 +164,13 @@ subroutine downscale_forcings(bounds, & forc_pbot_g => atm2lnd_inst%forc_pbot_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric pressure (Pa) forc_rho_g => atm2lnd_inst%forc_rho_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric density (kg/m**3) forc_solad_g => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation - + ! Column-level downscaled fields: + forc_rain_c => wateratm2lndbulk_inst%forc_rain_downscaled_col , & ! Output: [real(r8) (:)] rain rate [mm/s] + forc_snow_c => wateratm2lndbulk_inst%forc_snow_downscaled_col , & ! Output: [real(r8) (:)] snow rate [mm/s] + forc_q_c => wateratm2lndbulk_inst%forc_q_downscaled_col , & ! Output: [real(r8) (:)] atmospheric specific humidity (kg/kg) forc_t_c => atm2lnd_inst%forc_t_downscaled_col , & ! Output: [real(r8) (:)] atmospheric temperature (Kelvin) forc_th_c => atm2lnd_inst%forc_th_downscaled_col , & ! Output: [real(r8) (:)] atmospheric potential temperature (Kelvin) - forc_q_c => wateratm2lndbulk_inst%forc_q_downscaled_col , & ! Output: [real(r8) (:)] atmospheric specific humidity (kg/kg) forc_pbot_c => atm2lnd_inst%forc_pbot_downscaled_col , & ! Output: [real(r8) (:)] atmospheric pressure (Pa) forc_rho_c => atm2lnd_inst%forc_rho_downscaled_col , & ! Output: [real(r8) (:)] atmospheric density (kg/m**3) forc_solad_c => atm2lnd_inst%forc_solad_col & ! Output: [real(r8) (:)] column direct incoming solar radiation @@ -173,6 +181,8 @@ subroutine downscale_forcings(bounds, & if (col%active(c)) then g = col%gridcell(c) + forc_rain_c(c) = forc_rain_g(g) + forc_snow_c(c) = forc_snow_g(g) forc_t_c(c) = forc_t_g(g) forc_th_c(c) = forc_th_g(g) forc_q_c(c) = forc_q_g(g) @@ -229,8 +239,8 @@ subroutine downscale_forcings(bounds, & thbot_c= thbot_g + (tbot_c - tbot_g)*exp((zbot/Hbot)*(rair/cpair)) ! pot temp calc - call Qsat(tbot_g,pbot_g,qs_g) - call Qsat(tbot_c,pbot_c,qs_c) + call Qsat(tbot_g,pbot_g,es_g,dum1,qs_g,dum2) + call Qsat(tbot_c,pbot_c,es_c,dum1,qs_c,dum2) qbot_c = qbot_g*(qs_c/qs_g) @@ -254,9 +264,12 @@ subroutine downscale_forcings(bounds, & end do + ! adjust hillslope precpitation before repartitioning rain/snow if(use_hillslope) then call downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) + call downscale_hillslope_precipitation(bounds, topo_inst, atm2lnd_inst, wateratm2lndbulk_inst) endif + call partition_precip(bounds, atm2lnd_inst, wateratm2lndbulk_inst, & eflx_sh_precip_conversion(bounds%begc:bounds%endc)) @@ -338,8 +351,6 @@ subroutine partition_precip(bounds, atm2lnd_inst, wateratm2lndbulk_inst, eflx_sh do c = bounds%begc,bounds%endc if (col%active(c)) then g = col%gridcell(c) - forc_rain_c(c) = forc_rain_g(g) - forc_snow_c(c) = forc_snow_g(g) rain_to_snow_conversion_c(c) = 0._r8 snow_to_rain_conversion_c(c) = 0._r8 eflx_sh_precip_conversion(c) = 0._r8 @@ -786,13 +797,8 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) g = col%gridcell(c) do n = 1,numrad norm(n) = (sum_solar(g,n)/sum_wt(g)) -! write(iulog,*) 'normsolad: ', sum_solar(g,n),sum_wt(g) if(norm(n) > 0._r8) then forc_solad_col(c,n) = forc_solad_col(c,n)*(forc_solad_grc(g,n)/norm(n)) - -! if(c==bounds%begc .and. n==1) write(iulog,*) 'c,n,coszen(c/g),fcol,fgrc,norm--------------------' -! write(iulog,'(a12,2i6,6f12.6)') 'forcsolad: ', c,n,coszen_col(c),coszen_grc(g),forc_solad_col(c,n),forc_solad_grc(g,n),norm(n) - endif enddo end if @@ -804,4 +810,149 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) end subroutine downscale_hillslope_solar + !----------------------------------------------------------------------- + subroutine downscale_hillslope_precipitation(bounds, & + topo_inst, atm2lnd_inst, wateratm2lndbulk_inst) + ! + ! !DESCRIPTION: + ! Downscale precipitation from gridcell to column. + ! + ! Downscaling is done based on the difference between each CLM column's elevation and + ! the atmosphere's surface elevation (which is the elevation at which the atmospheric + ! forcings are valid). + ! + ! !USES: + use clm_varcon , only : rair, cpair, grav + use clm_varctl , only : use_hillslope + ! + ! !ARGUMENTS: + type(bounds_type) , intent(in) :: bounds + class(topo_type) , intent(in) :: topo_inst + type(atm2lnd_type) , intent(in) :: atm2lnd_inst + type(wateratm2lndbulk_type) , intent(inout) :: wateratm2lndbulk_inst + ! + ! !LOCAL VARIABLES: + integer :: g, l, c, fc ! indices + + ! temporaries for topo downscaling + real(r8) :: precip_anom, topo_anom + real(r8) :: norm_rain(bounds%begg:bounds%endg) + real(r8) :: norm_snow(bounds%begg:bounds%endg) + real(r8) :: sum_wt(bounds%begg:bounds%endg) + real(r8) :: max_topo(bounds%begg:bounds%endg) + real(r8) :: min_topo(bounds%begg:bounds%endg) + real(r8) :: rain_scalar, snow_scalar + logical :: checkConservation = .true. + character(len=*), parameter :: subname = 'downscale_hillslope_precipitation' + !----------------------------------------------------------------------- + + associate(& + ! Gridcell-level metadata: + forc_topo_g => atm2lnd_inst%forc_topo_grc , & ! Input: [real(r8) (:)] atmospheric surface height (m) + forc_rain_g => wateratm2lndbulk_inst%forc_rain_not_downscaled_grc , & ! Input: [real(r8) (:)] rain rate [mm/s] + forc_snow_g => wateratm2lndbulk_inst%forc_snow_not_downscaled_grc , & ! Input: [real(r8) (:)] snow rate [mm/s] + ! Column-level metadata: + topo_c => topo_inst%topo_col , & ! Input: [real(r8) (:)] column surface height (m) + + ! Column-level downscaled fields: + forc_rain_c => wateratm2lndbulk_inst%forc_rain_downscaled_col , & ! Output: [real(r8) (:)] rain rate [mm/s] + forc_snow_c => wateratm2lndbulk_inst%forc_snow_downscaled_col & ! Output: [real(r8) (:)] snow rate [mm/s] + ) + + ! Extract maximum column-level topographic elevation + + min_topo(bounds%begg:bounds%endg) = 0._r8 + max_topo(bounds%begg:bounds%endg) = 0._r8 + do l = bounds%begl, bounds%endl + if (lun%itype(l) == istsoil) then + g = lun%gridcell(l) + min_topo(g) = minval(topo_c(lun%coli(l):lun%colf(l))) + max_topo(g) = maxval(topo_c(lun%coli(l):lun%colf(l))) + endif + enddo + + ! Redistribute precipitation based on departure + ! of column elevation from mean elevation + + do c = bounds%begc,bounds%endc + g = col%gridcell(c) + if (lun%itype(col%landunit(c)) == istsoil) then + + ! spatially uniform normalization, but separate rain/snow + rain_scalar = 1.2e-3 + rain_scalar = 1.5e-3 + topo_anom = max(-1._r8,(topo_c(c) - forc_topo_g(g))*rain_scalar) ! rain + precip_anom = forc_rain_g(g) * topo_anom + forc_rain_c(c) = forc_rain_c(c) + precip_anom + + snow_scalar = rain_scalar + topo_anom = max(-1._r8,(topo_c(c) - forc_topo_g(g))*snow_scalar) ! snow + precip_anom = forc_snow_g(g) * topo_anom + forc_snow_c(c) = forc_snow_c(c) + precip_anom + + end if + end do + + ! Initialize arrays of total landunit precipitation + norm_rain(bounds%begg:bounds%endg) = 0._r8 + norm_snow(bounds%begg:bounds%endg) = 0._r8 + sum_wt(bounds%begg:bounds%endg) = 0._r8 + ! Calculate normalization (area-weighted average precipitation) + do c = bounds%begc,bounds%endc + g = col%gridcell(c) + if (lun%itype(col%landunit(c)) == istsoil) then + norm_rain(g) = norm_rain(g) + col%wtlunit(c)*forc_rain_c(c) + norm_snow(g) = norm_snow(g) + col%wtlunit(c)*forc_snow_c(c) + sum_wt(g) = sum_wt(g) + col%wtlunit(c) + end if + end do + do g = bounds%begg,bounds%endg + if(sum_wt(g) > 0._r8) then + norm_rain(g) = norm_rain(g) / sum_wt(g) + norm_snow(g) = norm_snow(g) / sum_wt(g) + endif + enddo + + ! Normalize column precipitation to conserve gridcell average + do c = bounds%begc,bounds%endc + g = col%gridcell(c) + if (lun%itype(col%landunit(c)) == istsoil) then + if (norm_rain(g) > 0._r8) then + forc_rain_c(c) = forc_rain_c(c) * forc_rain_g(g) / norm_rain(g) + endif + if (norm_snow(g) > 0._r8) then + forc_snow_c(c) = forc_snow_c(c) * forc_snow_g(g) / norm_snow(g) + endif + end if + end do + + ! check conservation + if(checkConservation) then + norm_rain(bounds%begg:bounds%endg) = 0._r8 + norm_snow(bounds%begg:bounds%endg) = 0._r8 + sum_wt(bounds%begg:bounds%endg) = 0._r8 + ! Calculate normalization (area-weighted average precipitation) + do c = bounds%begc,bounds%endc + g = col%gridcell(c) + if (lun%itype(col%landunit(c)) == istsoil) then + norm_rain(g) = norm_rain(g) + col%wtlunit(c)*forc_rain_c(c) + norm_snow(g) = norm_snow(g) + col%wtlunit(c)*forc_snow_c(c) + sum_wt(g) = sum_wt(g) + col%wtlunit(c) + end if + end do + do g = bounds%begg,bounds%endg + if(abs(norm_rain(g) - sum_wt(g)*forc_rain_g(g)) > 1.e-6) then + write(iulog,*) 'rain not conserved', g, norm_rain(g), sum_wt(g)*forc_rain_g(g) + endif + if(abs(norm_snow(g) - sum_wt(g)*forc_snow_g(g)) > 1.e-6) then + write(iulog,*) 'snow not conserved', g, norm_snow(g), sum_wt(g)*forc_snow_g(g) + endif + enddo + endif + + end associate + + end subroutine downscale_hillslope_precipitation + + end module atm2lndMod From d86736ea0e708bd04cfa7de774807aac73c35940 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 10 Mar 2021 08:32:56 -0700 Subject: [PATCH 037/153] add conditional to histFileMod --- src/main/histFileMod.F90 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index eb06dac26c..55c2f653b0 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2771,11 +2771,8 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='levdcmp', xtype=tape(t)%ncprec, dim1name='levdcmp', & long_name='coordinate levels for soil decomposition variables', units='m', ncid=nfid(t)) - if(use_hillslope)then + if(use_hillslope .and. .not.tape(t)%dov2xy)then - if (tape(t)%dov2xy) then - !pass - else call ncd_defvar(varname='hslp_distance', xtype=ncd_double, & dim1name=namec, long_name='hillslope column distance', & units='m', ncid=nfid(t)) @@ -2804,7 +2801,6 @@ subroutine htape_timeconst(t, mode) dim1name=namec, long_name='hillslope uphill column index', & ncid=nfid(t)) end if - end if if(use_fates)then @@ -2878,7 +2874,7 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='levdcmp', data=zsoi_1d, ncid=nfid(t), flag='write') end if - if (.not.tape(t)%dov2xy) then + if (use_hillslope .and. .not.tape(t)%dov2xy) then call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') From ae6085e95815bbe9e6a832d970324c0fb8e989fc Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 18 Mar 2021 12:52:28 -0600 Subject: [PATCH 038/153] enable fates multi-column restarts --- src/main/decompInitMod.F90 | 3 ++- src/main/subgridMod.F90 | 9 ++++++++- src/utils/clmfates_interfaceMod.F90 | 17 ++++++++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/decompInitMod.F90 b/src/main/decompInitMod.F90 index 0fdd58540b..6f174c0e46 100644 --- a/src/main/decompInitMod.F90 +++ b/src/main/decompInitMod.F90 @@ -850,7 +850,8 @@ subroutine decompInit_glcp(lns,lni,lnj,glc_behavior) do coi = begCohort,endCohort gindex(coi) = coStart(gi) + ioff(gi) ioff(gi) = ioff(gi) + 1 - if ( mod(coi, fates_maxElementsPerSite ) == 0 ) gi = gi + 1 +!scs jks ! comment out FATES doesn't need + !if ( mod(coi, fates_maxElementsPerSite ) == 0 ) gi = gi + 1 enddo locsize = endCohort-begCohort+1 globsize = numCohort diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 779368fab1..959b7ad1ef 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -88,6 +88,12 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & call subgrid_get_info_natveg(gi, npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() + !scs jks HH-FATES + ! call this after natveg call because we allocate space for + ! FATES cohorts based on the number of naturally vegetated columns + ! and nothing else + call subgrid_get_info_cohort(gi, ncols_temp, ncohorts) + call subgrid_get_info_urban_tbd(gi, npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() @@ -110,7 +116,8 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & call subgrid_get_info_crop(gi, npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() - call subgrid_get_info_cohort(gi, ncols_temp, ncohorts) + !move up for FATES +!scs jks !call subgrid_get_info_cohort(gi, ncols_temp, ncohorts) contains subroutine accumulate_counters diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index 836668511f..03567bb2a2 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -1148,7 +1148,10 @@ subroutine restart( this, bounds_proc, ncid, flag, waterdiagnosticbulk_inst, & type(fates_bounds_type) :: fates_clump integer :: c ! HLM column index integer :: s ! Fates site index - integer :: g ! grid-cell index + !comment out for HH-FATES + !scs jks !integer :: g ! grid-cell index + !scs jks + integer :: s0 ! global site offset for the current clump integer :: dk_index integer :: nlevsoil character(len=fates_long_string_length) :: ioname @@ -1212,13 +1215,21 @@ subroutine restart( this, bounds_proc, ncid, flag, waterdiagnosticbulk_inst, & do nc = 1,nclumps call get_clump_bounds(nc, bounds_clump) + !scs jks HH-FATES START + ! This index "s0" is the number of fates sites that came before the first + ! site on this clump. + s0 = floor(real(bounds_clump%begCohort,r8)/real(fates_maxElementsPerSite,r8)) + !scs jks END allocate(this%fates_restart%restart_map(nc)%site_index(this%fates(nc)%nsites)) allocate(this%fates_restart%restart_map(nc)%cohort1_index(this%fates(nc)%nsites)) do s=1,this%fates(nc)%nsites c = this%f2hmap(nc)%fcolumn(s) this%fates_restart%restart_map(nc)%site_index(s) = c - g = col%gridcell(c) - this%fates_restart%restart_map(nc)%cohort1_index(s) = (g-1)*fates_maxElementsPerSite + 1 + !scs jks !g = col%gridcell(c) + !scs jks !this%fates_restart%restart_map(nc)%cohort1_index(s) = (g-1)*fates_maxElementsPerSite + 1 + ! scs jks modify for HH-FATES restarts + this%fates_restart%restart_map(nc)%cohort1_index(s) = (s+s0-1)*fates_maxElementsPerSite + 1 + end do end do From 9dd871b82a782bb32451a6f4c999c63a4415a76e Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 18 Mar 2021 14:52:23 -0600 Subject: [PATCH 039/153] add units in ColumnType --- src/main/ColumnType.F90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 65c160fa1b..aaac74bcbe 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -70,12 +70,12 @@ module ColumnType integer, pointer :: cold (:) ! column index of downhill column (hillslope hydrology) integer, pointer :: hillslope_ndx (:) ! hillslope identifier integer, pointer :: hill_pftndx (:) ! specified (single) pft index of column - real(r8), pointer :: hill_elev (:) ! mean elevation of column relative to mean gridcell elevation - real(r8), pointer :: hill_slope (:) ! mean along-hill slope - real(r8), pointer :: hill_area (:) ! mean surface area - real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column - real(r8), pointer :: hill_distance (:) ! along-hill distance of column from bottom of hillslope - real(r8), pointer :: hill_aspect (:) ! azimuth angle of column wrt to north, positive to east + real(r8), pointer :: hill_elev (:) ! mean elevation of column relative to mean gridcell elevation (m) + real(r8), pointer :: hill_slope (:) ! mean along-hill slope (m/m) + real(r8), pointer :: hill_area (:) ! mean surface area (m2) + real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column (m) + real(r8), pointer :: hill_distance (:) ! along-hill distance of column from bottom of hillslope (m) + real(r8), pointer :: hill_aspect (:) ! azimuth angle of column wrt to north, positive to east (radians) ! other column characteristics logical , pointer :: hydrologically_active(:) ! true if this column is a hydrologically active type From 069c9102fce2a3daea40f6a1200d88baf2ee91ae Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 23 Mar 2021 09:58:42 -0600 Subject: [PATCH 040/153] add stream channel to ctsm --- Externals.cfg | 4 +- src/biogeophys/HillslopeHydrologyMod.F90 | 263 +++++++++++++++++++++-- src/biogeophys/HydrologyDrainageMod.F90 | 16 +- src/biogeophys/SoilHydrologyMod.F90 | 48 +++-- src/biogeophys/WaterFluxType.F90 | 25 ++- src/biogeophys/WaterStateType.F90 | 33 ++- src/biogeophys/Wateratm2lndBulkType.F90 | 16 -- src/biogeophys/Waterlnd2atmType.F90 | 5 + src/cpl/mct/lnd_import_export.F90 | 3 - src/main/LandunitType.F90 | 17 +- src/main/lnd2atmMod.F90 | 18 +- 11 files changed, 384 insertions(+), 64 deletions(-) diff --git a/Externals.cfg b/Externals.cfg index 5cdb1589d6..d9952caa97 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -22,8 +22,8 @@ required = True [mosart] local_path = components/mosart protocol = git -repo_url = https://github.com/swensosc/mosart -branch = pass_tdepth +repo_url = https://github.com/ESCOMP/MOSART +tag = mosart1_0_38 required = True [mizuRoute] diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 5224b6d774..96cab378a0 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -26,6 +26,10 @@ module HillslopeHydrologyMod public HillslopeDominantPft public HillslopeDominantLowlandPft public HillslopePftFromFile + public HillslopeStreamOutflow + public HillslopeUpdateStreamWater + + integer, public, parameter :: streamflow_manning = 0 ! PRIVATE character(len=*), parameter, private :: sourcefile = & @@ -33,7 +37,6 @@ module HillslopeHydrologyMod integer, private, parameter :: soil_profile_set_lowland_upland = 0 integer, private, parameter :: soil_profile_linear = 1 - !----------------------------------------------------------------------- contains @@ -76,6 +79,7 @@ subroutine InitHillslope(bounds,fsurdat) real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] real(r8), allocatable :: hill_bedrock(:,:) ! hillslope bedrock depth [m] + real(r8), pointer :: fstream_in(:) ! read in - 1D - float type(file_desc_t) :: ncid ! netcdf id logical :: readvar ! check whether variable on file @@ -83,8 +87,11 @@ subroutine InitHillslope(bounds,fsurdat) integer :: ierr ! error code integer :: c, l, g, i, j, ci, nh ! indices - real(r8) :: hillslope_area ! total area of hillslope - + real(r8) :: ncol_per_hillslope(nhillslope) ! number of columns per hillslope + real(r8) :: hillslope_area(nhillslope) ! area of hillslope + real(r8) :: nhill_per_landunit(nhillslope) ! total number of each representative hillslope per landunit + real(r8) :: check_weight + character(len=*), parameter :: subname = 'InitHillslope' !----------------------------------------------------------------------- @@ -255,6 +262,40 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(ihillslope_in) + allocate(fstream_in(bounds%begg:bounds%endg)) + call ncd_io(ncid=ncid, varname='h_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + if (masterproc) then + write(iulog,*) 'h_stream_depth found on surface data set' + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_depth(l) = fstream_in(g) + enddo + endif + call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + if (masterproc) then + write(iulog,*) 'h_stream_width found on surface data set' + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_width(l) = fstream_in(g) + enddo + end if + call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + if (masterproc) then + write(iulog,*) 'h_stream_slope found on surface data set' + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_slope(l) = fstream_in(g) + enddo + end if + + deallocate(fstream_in) + ! Set hillslope hydrology column level variables ! This needs to match how columns set up in subgridMod do l = bounds%begl,bounds%endl @@ -317,43 +358,77 @@ subroutine InitHillslope(bounds,fsurdat) ! Calculate total (representative) hillslope area on landunit ! weighted relative to one another via pct_hillslope - hillslope_area = 0._r8 + ncol_per_hillslope(:)= 0._r8 + hillslope_area(:) = 0._r8 do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) if (nh > 0) then - hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + ncol_per_hillslope(nh) = ncol_per_hillslope(nh) + 1 + hillslope_area(nh) = hillslope_area(nh) + col%hill_area(c) + endif + enddo + + ! Total area occupied by each hillslope (m2) is + ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 + ! Number of representative hillslopes per landunit + ! is the total area divided by individual area + + do nh = 1, nhillslope + if(hillslope_area(nh) > 0._r8) then + nhill_per_landunit(nh) = grc%area(g)*1.e6*lun%wtgcell(l) & + *pct_hillslope(l,nh)*0.01/hillslope_area(nh) + endif + enddo + + ! Calculate steam channel length + ! Total length of stream banks is individual widths + ! times number of hillslopes per landunit divided + ! by 2 to convert from bank length to channel length + + lun%stream_channel_length(l) = 0._r8 + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) == ispval) then + lun%stream_channel_length(l) = lun%stream_channel_length(l) & + + col%hill_width(c) * nhill_per_landunit(col%hillslope_ndx(c)) endif enddo + lun%stream_channel_length(l) = 0.5_r8 * lun%stream_channel_length(l) ! if missing hillslope information on surface dataset, fill data ! and recalculate hillslope_area - if (hillslope_area == 0._r8) then + if (sum(hillslope_area) == 0._r8) then do c = lun%coli(l), lun%colf(l) + nh = col%hillslope_ndx(c) col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6 ! km2 to m2 - col%hill_distance(c) = sqrt(col%hill_area(c)) + col%hill_distance(c) = sqrt(col%hill_area(c)) & + *((c-lun%coli(l))/ncol_per_hillslope(nh)) col%hill_width(c) = sqrt(col%hill_area(c)) - col%hill_elev(c) = col%topo_std(c) + col%hill_elev(c) = col%topo_std(c) & + *((c-lun%coli(l))/ncol_per_hillslope(nh)) col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) col%hill_aspect(c) = (rpi/2.) ! east (arbitrarily chosen) nh = col%hillslope_ndx(c) pct_hillslope(l,nh) = 100/nhillslope - hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) enddo endif ! Recalculate column weights using input areas + check_weight = 0._r8 do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) if (nh > 0) then - col%wtlunit(c) = col%hill_area(c) & - * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + col%wtlunit(c) = (col%hill_area(c)/hillslope_area(nh)) & + * (pct_hillslope(l,nh)*0.01_r8) else col%wtlunit(c) = 0._r8 endif + check_weight = check_weight + col%wtlunit(c) enddo - + if (abs(1._r8 - check_weight) > 1.e-6) then + write(iulog,*) 'col%wtlunit does not sum to 1: ', check_weight + write(iulog,*) 'weights: ', col%wtlunit(lun%coli(l):lun%colf(l)) + write(iulog,*) ' ' + endif endif enddo @@ -820,4 +895,164 @@ subroutine HillslopePftFromFile() end subroutine HillslopePftFromFile + !----------------------------------------------------------------------- + subroutine HillslopeStreamOutflow(bounds, & + waterstatebulk_inst, waterfluxbulk_inst,streamflow_method) + ! + ! !DESCRIPTION: + ! Calculate discharge from stream channel + ! + ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use WaterFluxBulkType , only : waterfluxbulk_type + use WaterStateBulkType , only : waterstatebulk_type + use spmdMod , only : masterproc + use clm_varcon , only : spval, ispval, grlnd + use landunit_varcon , only : istsoil + use ncdio_pio + use clm_time_manager , only : get_step_size_real + + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + integer, intent(in) :: streamflow_method + type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst + type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst + + integer :: c, l, g, i, j + integer :: nstep + real(r8) :: dtime ! land model time step (sec) + real(r8) :: cross_sectional_area + real(r8) :: stream_depth + real(r8) :: hydraulic_radius + real(r8) :: flow_velocity + real(r8) :: overbank_area +! real(r8), parameter :: manning_roughness = 0.05 + real(r8), parameter :: manning_roughness = 0.03 + real(r8), parameter :: manning_exponent = 0.667 + + character(len=*), parameter :: subname = 'HillslopeStreamOutflow' + + !----------------------------------------------------------------------- + associate( & + stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) + qstreamflow => waterfluxbulk_inst%qstreamflow_lun & ! Input: [real(r8) (:) ] stream water discharge (m3/s) + ) + + ! Get time step + dtime = get_step_size_real() + + do l = bounds%begl,bounds%endl + if(lun%itype(l) == istsoil) then + ! Streamflow calculated from Manning equation + if(streamflow_method == streamflow_manning) then + cross_sectional_area = stream_water_volume(l) & + /lun%stream_channel_length(l) + stream_depth = cross_sectional_area & + /lun%stream_channel_width(l) + hydraulic_radius = cross_sectional_area & + /(lun%stream_channel_width(l) + 2*stream_depth) + + if(hydraulic_radius <= 0._r8) then + qstreamflow(l) = 0._r8 + else + flow_velocity = (hydraulic_radius)**manning_exponent & + * sqrt(lun%stream_channel_slope(l)) & + / manning_roughness + ! overbank flow + if (stream_depth > lun%stream_channel_depth(l)) then + ! try increasing flow area cross section +! overbank_area = (stream_depth -lun%stream_channel_depth(l)) * 30._r8 * lun%stream_channel_width(l) + ! qstreamflow(l) = (cross_sectional_area + overbank_area) * flow_velocity + + ! try increasing dynamic slope + qstreamflow(l) = cross_sectional_area * flow_velocity & + *(stream_depth/lun%stream_channel_depth(l)) + + ! try removing all overbank flow instantly +!!$ qstreamflow(l) = cross_sectional_area * flow_velocity & +!!$ + (stream_depth-lun%stream_channel_depth(l)) & +!!$ *lun%stream_channel_width(l)*lun%stream_channel_length(l)/dtime + else + qstreamflow(l) = cross_sectional_area * flow_velocity + endif + qstreamflow(l) = max(0._r8,min(qstreamflow(l),stream_water_volume(l)/dtime)) + end if + endif + endif ! end of istsoil + enddo ! end of loop over landunits + + end associate + + end subroutine HillslopeStreamOutflow + + !----------------------------------------------------------------------- + subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & + waterfluxbulk_inst,wateratm2lndbulk_inst) + ! + ! !DESCRIPTION: + ! Calculate discharge from stream channel + ! + ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use WaterFluxBulkType , only : waterfluxbulk_type + use WaterStateBulkType , only : waterstatebulk_type + use Wateratm2lndBulkType, only : wateratm2lndbulk_type + use spmdMod , only : masterproc + use clm_varcon , only : spval, ispval, grlnd + use landunit_varcon , only : istsoil + use clm_time_manager, only : get_step_size_real + + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst + type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst + type(wateratm2lndbulk_type), intent(inout) :: wateratm2lndbulk_inst + + integer :: c, l, g, i, j + real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) + real(r8) :: dtime ! land model time step (sec) + + character(len=*), parameter :: subname = 'HillslopeUpdateStreamWater' + + !----------------------------------------------------------------------- + associate( & + stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input/Output: [real(r8) (:) ] stream water volume (m3) + qstreamflow => waterfluxbulk_inst%qstreamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) + qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Input: [real(r8) (:) ] discharge from columns (m3/s) + qflx_surf => waterfluxbulk_inst%qflx_surf_col & ! Output: [real(r8) (:) ] total surface runoff (mm H2O /s) + ) + + ! Get time step + dtime = get_step_size_real() + + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + + if(lun%itype(l) == istsoil) then + do c = lun%coli(l), lun%colf(l) + qflx_surf_vol = qflx_surf(c)*1.e-3 & + *(grc%area(g)*1.e6*col%wtgcell(c)) + stream_water_volume(l) = stream_water_volume(l) & + + (qdischarge(c) + qflx_surf_vol) * dtime + enddo + stream_water_volume(l) = stream_water_volume(l) & + - qstreamflow(l) * dtime + + write(iulog,*) 'checktdepth2: ',stream_water_volume(l),qstreamflow(l) + write(iulog,*) 'checktdepth3: ',lun%stream_channel_length(l), & + lun%stream_channel_width(l),lun%stream_channel_depth(l) + write(iulog,*) ' ' + endif + enddo + + end associate + + end subroutine HillslopeUpdateStreamWater + end module HillslopeHydrologyMod diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 83d0f14e02..98751f7711 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -23,7 +23,6 @@ module HydrologyDrainageMod use TotalWaterAndHeatMod, only : ComputeWaterMassNonLake use LandunitType , only : lun use ColumnType , only : col - ! ! !PUBLIC TYPES: implicit none @@ -60,6 +59,8 @@ subroutine HydrologyDrainage(bounds, & use clm_time_manager , only : get_step_size_real, get_nstep use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, PerchedLateralFlowHillslope, LateralFlowPowerLaw, LateralFlowHillslope use SoilWaterMovementMod , only : use_aquifer_layer + use HillslopeHydrologyMod, only : streamflow_manning, HillslopeStreamOutflow, HillslopeUpdateStreamWater + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -80,9 +81,9 @@ subroutine HydrologyDrainage(bounds, & type(soilstate_type) , intent(inout) :: soilstate_inst type(waterstatebulk_type) , intent(inout) :: waterstatebulk_inst type(waterdiagnosticbulk_type) , intent(inout) :: waterdiagnosticbulk_inst - type(waterbalance_type) , intent(inout) :: waterbalancebulk_inst + type(waterbalance_type) , intent(inout) :: waterbalancebulk_inst type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst - type(wateratm2lndbulk_type) , intent(inout) :: wateratm2lndbulk_inst + type(wateratm2lndbulk_type) , intent(inout) :: wateratm2lndbulk_inst type(glacier_smb_type) , intent(in) :: glacier_smb_inst ! ! !LOCAL VARIABLES: @@ -156,6 +157,15 @@ subroutine HydrologyDrainage(bounds, & soilhydrology_inst, soilstate_inst, & waterstatebulk_inst, waterfluxbulk_inst, & wateratm2lndbulk_inst) + + call HillslopeStreamOutflow(bounds,& + waterstatebulk_inst, waterfluxbulk_inst, & + streamflow_method=streamflow_manning) + + call HillslopeUpdateStreamWater(bounds, & + waterstatebulk_inst, waterfluxbulk_inst, & + wateratm2lndbulk_inst) + else call PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 6249fcc34d..d01732fec2 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1855,6 +1855,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & ! ! !USES: use clm_varcon , only : pondmx, tfrz, watmin,rpi, secspday, nlvic + use LandunitType , only : lun use landunit_varcon , only : istsoil ! ! !ARGUMENTS: @@ -1869,7 +1870,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & ! ! !LOCAL VARIABLES: character(len=32) :: subname = 'PerchedLateralFlowHillslope' ! subroutine name - integer :: c,j,fc,i,g ! indices + integer :: c,j,fc,i,l,g ! indices real(r8) :: dtime ! land model time step (sec) real(r8) :: drainage_tot real(r8) :: drainage_layer @@ -1880,6 +1881,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & real(r8) :: wtsub real(r8) :: q_perch real(r8) :: q_perch_max + real(r8) :: stream_water_depth ! depth of water in stream channel character(len=32) :: transmissivity_method = 'layersum' ! character(len=32) :: baseflow_method = 'kinematic' @@ -1905,9 +1907,8 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Input: [real(r8) (:) ] perched water table depth (m) - - tdepth => wateratm2lndbulk_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) - tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) + stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) + qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col , & ! Output: [real(r8) (:) ] perched wt sub-surface runoff (mm H2O /s) @@ -1942,7 +1943,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & ! compute drainage from perched saturated region do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - + l = col%landunit(c) qflx_drain_perched(c) = 0._r8 qflx_drain_perched_out(c) = 0._r8 qflx_drain_perched_vol(c) = 0._r8 @@ -1952,7 +1953,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & if (lun%itype(col%landunit(c)) == istsoil) then ! calculate head gradient - g = col%gridcell(c) + ! kinematic wave approximation if (baseflow_method == 'kinematic') then dgrad = col%hill_slope(c) @@ -1964,16 +1965,19 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & - (col%hill_elev(col%cold(c))-zwt_perched(col%cold(c))) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else + stream_water_depth = stream_water_volume(l) & + /lun%stream_channel_length(l)/lun%stream_channel_width(l) + ! flow between channel and lowest column ! bankfull height is defined to be zero dgrad = (col%hill_elev(c)-zwt_perched(c)) & ! ignore overbankfull storage - - min(max((tdepth(g) - tdepth_bankfull(g)), & + - min(max((stream_water_depth - lun%stream_channel_depth(l)), & (col%hill_elev(c)-frost_table(c))),0._r8) dgrad = dgrad / (col%hill_distance(c)) ! dgrad cannot be negative when channel is empty - if (tdepth(g) <= 0._r8) then + if (stream_water_depth <= 0._r8) then dgrad = max(dgrad, 0._r8) endif endif @@ -2013,7 +2017,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & endif else ! transmissivity of losing stream (c_src == ispval) - transmis = k_anisotropic*(1.e-3_r8*hksat(c,k_perch(c_dst)))*tdepth(g) + transmis = k_anisotropic*(1.e-3_r8*hksat(c,k_perch(c_dst)))*stream_water_depth endif qflx_drain_perched_vol(c) = transmis*col%hill_width(c)*dgrad @@ -2583,6 +2587,7 @@ subroutine LateralFlowHillslope(bounds, & logical :: no_lateral_flow = .false. real(r8) :: transmis ! transmissivity real(r8) :: dgrad ! hydraulic head gradient + real(r8) :: stream_water_depth ! depth of water in stream channel real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 1._r8 ! anisotropy scalar real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) @@ -2611,9 +2616,6 @@ subroutine LateralFlowHillslope(bounds, & qflx_latflow_in => waterfluxbulk_inst%qflx_latflow_in_col, & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) - tdepth => wateratm2lndbulk_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) - tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) - depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) Dsmax => soilhydrology_inst%dsmax_col , & ! Input: [real(r8) (:) ] max. velocity of baseflow (mm/day) @@ -2630,6 +2632,7 @@ subroutine LateralFlowHillslope(bounds, & qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) origflag => soilhydrology_inst%origflag , & ! Input: logical h2osfcflag => soilhydrology_inst%h2osfcflag , & ! Input: logical + stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) qflx_snwcp_liq => waterfluxbulk_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] qflx_ice_runoff_xs => waterfluxbulk_inst%qflx_ice_runoff_xs_col , & ! Output: [real(r8) (:) ] solid runoff from excess ice in soil (mm H2O /s) [+] @@ -2702,6 +2705,7 @@ subroutine LateralFlowHillslope(bounds, & do fc = 1, num_hillslope c = filter_hillslopec(fc) + l = col%landunit(c) g = col%gridcell(c) ! kinematic wave approximation @@ -2716,16 +2720,18 @@ subroutine LateralFlowHillslope(bounds, & - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else + stream_water_depth = stream_water_volume(l) & + /lun%stream_channel_length(l)/lun%stream_channel_width(l) + ! flow between channel and lowest column ! bankfull height is defined to be zero dgrad = (col%hill_elev(c)-zwt(c)) & - ! - (tdepth(g) - tdepth_bankfull(g)) ! ignore overbankfull storage - - min((tdepth(g) - tdepth_bankfull(g)),0._r8) + - min((stream_water_depth - lun%stream_channel_depth(l)),0._r8) dgrad = dgrad / (col%hill_distance(c)) ! dgrad cannot be negative when channel is empty - if (tdepth(g) <= 0._r8) then + if (stream_water_depth <= 0._r8) then dgrad = max(dgrad, 0._r8) endif ! add vertical drainage for losing streams @@ -2772,7 +2778,7 @@ subroutine LateralFlowHillslope(bounds, & endif else ! transmissivity of losing stream (c_src == ispval) - transmis = (1.e-3_r8*ice_imped(c,jwt(c)+1)*hksat(c,jwt(c)+1))*tdepth(g) + transmis = (1.e-3_r8*ice_imped(c,jwt(c)+1)*hksat(c,jwt(c)+1))*stream_water_depth endif ! adjust transmissivity by 'anisotropy factor' transmis = k_anisotropic*transmis @@ -2785,9 +2791,13 @@ subroutine LateralFlowHillslope(bounds, & ! include ice impedance in transmissivity qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad - ! currently this is redundant to above - qdischarge(c) = qflx_latflow_out_vol(c) - + ! qdischarge from lowest column is qflx_latflow_out_vol + ! scaled by total area of column in gridcell divided by column area + if (col%cold(c) == ispval) then + qdischarge(c) = qflx_latflow_out_vol(c) & + *(grc%area(g)*1.e6*col%wtgcell(c)/col%hill_area(c)) + endif + ! convert volumetric flow to equivalent flux qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index 9ee00d5869..a978a60871 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -10,7 +10,7 @@ module WaterFluxType use clm_varpar , only : nlevsno, nlevsoi use clm_varcon , only : spval use decompMod , only : bounds_type - use decompMod , only : BOUNDS_SUBGRID_PATCH, BOUNDS_SUBGRID_COLUMN, BOUNDS_SUBGRID_GRIDCELL + use decompMod , only : BOUNDS_SUBGRID_PATCH, BOUNDS_SUBGRID_COLUMN, BOUNDS_SUBGRID_LANDUNIT, BOUNDS_SUBGRID_GRIDCELL use LandunitType , only : lun use ColumnType , only : col use AnnualFluxDribbler, only : annual_flux_dribbler_type, annual_flux_dribbler_gridcell @@ -26,7 +26,7 @@ module WaterFluxType class(water_info_base_type), pointer :: info - ! water fluxes are in units or mm/s + ! water fluxes are in units of mm/s real(r8), pointer :: qflx_through_snow_patch (:) ! patch canopy throughfall of snow (mm H2O/s) real(r8), pointer :: qflx_through_liq_patch (:) ! patch canopy throughfal of liquid (rain+irrigation) (mm H2O/s) @@ -75,6 +75,7 @@ module WaterFluxType real(r8), pointer :: qflx_latflow_in_col (:) ! col hillslope lateral flow input (mm/s) real(r8), pointer :: qflx_latflow_out_col (:) ! col hillslope lateral flow output (mm/s) real(r8), pointer :: qdischarge_col (:) ! col hillslope discharge (m3/s) + real(r8), pointer :: qstreamflow_lun (:) ! lun stream discharge (m3/s) real(r8), pointer :: qflx_drain_perched_col (:) ! col sub-surface runoff from perched wt (mm H2O /s) real(r8), pointer :: qflx_top_soil_col (:) ! col net water input into soil from top (mm/s) real(r8), pointer :: qflx_floodc_col (:) ! col flood water flux at column level @@ -290,6 +291,9 @@ subroutine InitAllocate(this, bounds, tracer_vars) call AllocateVar1d(var = this%qdischarge_col, name = 'qdischarge_col', & container = tracer_vars, & bounds = bounds, subgrid_level = BOUNDS_SUBGRID_COLUMN) + call AllocateVar1d(var = this%qstreamflow_lun, name = 'qstreamflow_lun', & + container = tracer_vars, & + bounds = bounds, subgrid_level = BOUNDS_SUBGRID_LANDUNIT) call AllocateVar1d(var = this%qflx_top_soil_col, name = 'qflx_top_soil_col', & container = tracer_vars, & bounds = bounds, subgrid_level = BOUNDS_SUBGRID_COLUMN) @@ -406,6 +410,7 @@ subroutine InitHistory(this, bounds) ! !LOCAL VARIABLES: integer :: begp, endp integer :: begc, endc + integer :: begl, endl integer :: begg, endg real(r8), pointer :: data2dptr(:,:), data1dptr(:) ! temp. pointers for slicing larger arrays !------------------------------------------------------------------------ @@ -511,6 +516,15 @@ subroutine InitHistory(this, bounds) long_name=this%info%lname('hillslope discharge from column'), & ptr_col=this%qdischarge_col, c2l_scale_type='urbanf') + this%qstreamflow_lun(begl:endl) = spval + call hist_addfld1d ( & + fname=this%info%fname('QSTREAMFLOW'), & + units='m3/s', & + avgflag='A', & + long_name=this%info%lname('streamflow discharge'), & + l2g_scale_type='veg', & + ptr_lunit=this%qstreamflow_lun) + this%qflx_drain_perched_col(begc:endc) = spval call hist_addfld1d ( & fname=this%info%fname('QDRAI_PERCH'), & @@ -894,7 +908,12 @@ subroutine InitCold(this, bounds) this%qdischarge_col(c) = 0._r8 end if end do - + do l = bounds%begl, bounds%endl + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + this%qstreamflow_lun(l) = 0._r8 + end if + end do + end subroutine InitCold !------------------------------------------------------------------------ diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index c0b7abc6a5..56d6ff49f4 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -12,9 +12,9 @@ module WaterStateType use shr_log_mod , only : errMsg => shr_log_errMsg use abortutils , only : endrun use decompMod , only : bounds_type - use decompMod , only : BOUNDS_SUBGRID_PATCH, BOUNDS_SUBGRID_COLUMN, BOUNDS_SUBGRID_GRIDCELL + use decompMod , only : BOUNDS_SUBGRID_PATCH, BOUNDS_SUBGRID_COLUMN, BOUNDS_SUBGRID_LANDUNIT, BOUNDS_SUBGRID_GRIDCELL use clm_varctl , only : use_bedrock, iulog - use clm_varctl , only : use_fates_planthydro + use clm_varctl , only : use_fates_planthydro, use_hillslope use clm_varpar , only : nlevgrnd, nlevsoi, nlevurb, nlevmaxurbgrnd, nlevsno use clm_varcon , only : spval, namec use LandunitType , only : lun @@ -51,6 +51,10 @@ module WaterStateType real(r8) :: aquifer_water_baseline ! baseline value for water in the unconfined aquifer (wa_col) for this bulk / tracer (mm) + ! Hillslope stream variables + real(r8), pointer :: stream_water_lun (:) ! landunit water in the streams (m3) + + contains procedure, public :: Init @@ -150,6 +154,9 @@ subroutine InitAllocate(this, bounds, tracer_vars) call AllocateVar1d(var = this%dynbal_baseline_ice_col, name = 'dynbal_baseline_ice_col', & container = tracer_vars, & bounds = bounds, subgrid_level = BOUNDS_SUBGRID_COLUMN) + call AllocateVar1d(var = this%stream_water_lun, name = 'stream_water_lun', & + container = tracer_vars, & + bounds = bounds, subgrid_level = BOUNDS_SUBGRID_LANDUNIT) end subroutine InitAllocate @@ -171,12 +178,14 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) ! !LOCAL VARIABLES: integer :: begp, endp integer :: begc, endc + integer :: begl, endl integer :: begg, endg real(r8), pointer :: data2dptr(:,:), data1dptr(:) ! temp. pointers for slicing larger arrays !------------------------------------------------------------------------ begp = bounds%begp; endp= bounds%endp begc = bounds%begc; endc= bounds%endc + begl = bounds%begl; endl= bounds%endl begg = bounds%begg; endg= bounds%endg data2dptr => this%h2osoi_liq_col(:,-nlevsno+1:0) @@ -268,6 +277,14 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) ptr_col=this%wa_col, l2g_scale_type='veg') end if + if (use_hillslope) then + this%stream_water_lun(begl:endl) = spval + call hist_addfld1d (fname=this%info%fname('STREAM_WATER_VOLUME'), units='m3', & + avgflag='A', & + long_name=this%info%lname('water in stream channel (hillslope hydrology only)'), & + ptr_lunit=this%stream_water_lun, l2g_scale_type='veg', default='inactive') + end if + ! (rgk 02-02-2017) There is intentionally no entry here for stored plant water ! I think that since the value is zero in all cases except ! for FATES plant hydraulics, it will be confusing for users @@ -628,6 +645,18 @@ subroutine Restart(this, bounds, ncid, flag, & units='kg/m2', & interpinic_flag='interp', readvar=readvar, data=this%dynbal_baseline_ice_col) + call restartvar(ncid=ncid, flag=flag, & + varname=this%info%fname('STREAM_WATER_VOLUME'), & + xtype=ncd_double, & + dim1name='landunit', & + long_name=this%info%lname('water in stream channel'), & + units='m3', & + interpinic_flag='interp', readvar=readvar, data=this%stream_water_lun) + + if (flag == 'read' .and. .not. is_restart()) then + this%stream_water_lun(bounds%begl:bounds%endl) = 0._r8 + end if + ! Determine volumetric soil water (for read only) if (flag == 'read' ) then do c = bounds%begc, bounds%endc diff --git a/src/biogeophys/Wateratm2lndBulkType.F90 b/src/biogeophys/Wateratm2lndBulkType.F90 index 4aacbe11c2..8fa4e77774 100644 --- a/src/biogeophys/Wateratm2lndBulkType.F90 +++ b/src/biogeophys/Wateratm2lndBulkType.F90 @@ -30,8 +30,6 @@ module Wateratm2lndBulkType real(r8), pointer :: volrmch_grc (:) ! rof volr main channel (m3) real(r8), pointer :: volr_grc (:) ! rof volr total volume (m3) - real(r8), pointer :: tdepth_grc (:) ! rof tributary water depth (m) - real(r8), pointer :: tdepthmax_grc (:) ! rof tributary bankfull water depth (m) real(r8), pointer :: forc_rh_grc (:) ! atmospheric relative humidity (%) real(r8) , pointer :: prec365_col (:) ! col 365-day running mean of tot. precipitation (see comment in UpdateAccVars regarding why this is col-level despite other prec accumulators being patch-level) real(r8) , pointer :: prec60_patch (:) ! patch 60-day running mean of tot. precipitation (mm/s) @@ -119,8 +117,6 @@ subroutine InitBulkAllocate(this, bounds) begc = bounds%begc; endc= bounds%endc begg = bounds%begg; endg= bounds%endg - allocate(this%tdepth_grc (begg:endg)) ; this%tdepth_grc (:) = ival - allocate(this%tdepthmax_grc (begg:endg)) ; this%tdepthmax_grc (:) = ival allocate(this%volr_grc (begg:endg)) ; this%volr_grc (:) = ival allocate(this%volrmch_grc (begg:endg)) ; this%volrmch_grc (:) = ival allocate(this%forc_rh_grc (begg:endg)) ; this%forc_rh_grc (:) = ival @@ -158,16 +154,6 @@ subroutine InitBulkHistory(this, bounds) begp = bounds%begp; endp= bounds%endp begg = bounds%begg; endg= bounds%endg - this%tdepth_grc(begg:endg) = spval - call hist_addfld1d (fname='TDEPTH', units='m', & - avgflag='A', long_name='tributary water depth', & - ptr_lnd=this%tdepth_grc, default = 'inactive') - - this%tdepthmax_grc(begg:endg) = spval - call hist_addfld1d (fname='TDEPTHMAX', units='m', & - avgflag='A', long_name='tributary bankfull water depth', & - ptr_lnd=this%tdepthmax_grc, default = 'inactive') - this%volr_grc(begg:endg) = spval call hist_addfld1d (fname=this%info%fname('VOLR'), units='m3', & avgflag='A', long_name=this%info%lname('river channel total water storage'), & @@ -475,8 +461,6 @@ subroutine Clean(this) ! rof->lnd deallocate(this%forc_flood_grc) - deallocate(this%tdepth_grc) - deallocate(this%tdepthmax_grc) deallocate(this%volr_grc) deallocate(this%volrmch_grc) diff --git a/src/biogeophys/Waterlnd2atmType.F90 b/src/biogeophys/Waterlnd2atmType.F90 index fb59d1c83c..3435b3c85e 100644 --- a/src/biogeophys/Waterlnd2atmType.F90 +++ b/src/biogeophys/Waterlnd2atmType.F90 @@ -32,6 +32,7 @@ module Waterlnd2atmType real(r8), pointer :: qflx_rofliq_qsub_grc (:) ! rof liq -- subsurface runoff component real(r8), pointer :: qflx_rofliq_qgwl_grc (:) ! rof liq -- glacier, wetland and lakes water balance residual component real(r8), pointer :: qflx_rofliq_drain_perched_grc (:) ! rof liq -- perched water table runoff component + real(r8), pointer :: qflx_rofliq_stream_grc (:) ! rof liq -- stream channel runoff component real(r8), pointer :: qflx_ice_runoff_col(:) ! rof ice forcing, col level real(r8), pointer :: qflx_rofice_grc (:) ! rof ice forcing, grc level real(r8), pointer :: qflx_liq_from_ice_col(:) ! liquid runoff from converted ice runoff @@ -120,6 +121,10 @@ subroutine InitAllocate(this, bounds, tracer_vars) container = tracer_vars, & bounds = bounds, subgrid_level = BOUNDS_SUBGRID_GRIDCELL, & ival=ival) + call AllocateVar1d(var = this%qflx_rofliq_stream_grc, name = 'qflx_rofliq_stream_grc', & + container = tracer_vars, & + bounds = bounds, subgrid_level = BOUNDS_SUBGRID_GRIDCELL, & + ival=ival) call AllocateVar1d(var = this%qflx_ice_runoff_col, name = 'qflx_ice_runoff_col', & container = tracer_vars, & bounds = bounds, subgrid_level = BOUNDS_SUBGRID_COLUMN, & diff --git a/src/cpl/mct/lnd_import_export.F90 b/src/cpl/mct/lnd_import_export.F90 index 4697a51a87..e1802968cd 100644 --- a/src/cpl/mct/lnd_import_export.F90 +++ b/src/cpl/mct/lnd_import_export.F90 @@ -10,7 +10,6 @@ module lnd_import_export use Waterlnd2atmBulkType , only: waterlnd2atmbulk_type use Wateratm2lndBulkType , only: wateratm2lndbulk_type use clm_cpl_indices -!scs use GridcellType , only : grc ! implicit none @@ -91,8 +90,6 @@ subroutine lnd_import( bounds, x2l, glc_present, atm2lnd_inst, glc2lnd_inst, wat wateratm2lndbulk_inst%volr_grc(g) = x2l(index_x2l_Flrr_volr,i) * (ldomain%area(g) * 1.e6_r8) wateratm2lndbulk_inst%volrmch_grc(g)= x2l(index_x2l_Flrr_volrmch,i) * (ldomain%area(g) * 1.e6_r8) - wateratm2lndbulk_inst%tdepth_grc(g) = x2l(index_x2l_Sr_tdepth,i) - wateratm2lndbulk_inst%tdepthmax_grc(g) = x2l(index_x2l_Sr_tdepth_max,i) ! Determine required receive fields diff --git a/src/main/LandunitType.F90 b/src/main/LandunitType.F90 index 01c79d2bb9..a575edc8ee 100644 --- a/src/main/LandunitType.F90 +++ b/src/main/LandunitType.F90 @@ -53,6 +53,12 @@ module LandunitType real(r8), pointer :: z_0_town (:) ! urban landunit momentum roughness length (m) real(r8), pointer :: z_d_town (:) ! urban landunit displacement height (m) + ! hillslope variables + real(r8), pointer :: stream_channel_depth (:) ! stream channel bankfull depth (m) + real(r8), pointer :: stream_channel_width (:) ! stream channel bankfull width (m) + real(r8), pointer :: stream_channel_length (:) ! stream channel length (m) + real(r8), pointer :: stream_channel_slope (:) ! stream channel slope (m/m) + contains procedure, public :: Init ! Allocate and initialize @@ -104,6 +110,12 @@ subroutine Init(this, begl, endl) allocate(this%z_0_town (begl:endl)); this%z_0_town (:) = nan allocate(this%z_d_town (begl:endl)); this%z_d_town (:) = nan + ! Hillslope variables initialized in HillslopeHydrologyMod + allocate(this%stream_channel_depth(begl:endl)); this%stream_channel_depth (:) = nan + allocate(this%stream_channel_width(begl:endl)); this%stream_channel_width (:) = nan + allocate(this%stream_channel_length(begl:endl)); this%stream_channel_length (:) = nan + allocate(this%stream_channel_slope(begl:endl)); this%stream_channel_slope (:) = nan + end subroutine Init !------------------------------------------------------------------------ @@ -137,7 +149,10 @@ subroutine Clean(this) deallocate(this%wtlunit_roof ) deallocate(this%z_0_town ) deallocate(this%z_d_town ) - + deallocate(this%stream_channel_depth) + deallocate(this%stream_channel_width) + deallocate(this%stream_channel_length) + deallocate(this%stream_channel_slope) end subroutine Clean end module LandunitType diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index b05013ea09..f10720f338 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -15,7 +15,7 @@ module lnd2atmMod use clm_varctl , only : iulog, use_lch4 use seq_drydep_mod , only : n_drydep, drydep_method, DD_XLND use decompMod , only : bounds_type - use subgridAveMod , only : p2g, c2g + use subgridAveMod , only : p2g, c2g, l2g use filterColMod , only : filter_col_type, col_filter_from_logical_array use lnd2atmType , only : lnd2atm_type use atm2lndType , only : atm2lnd_type @@ -346,6 +346,22 @@ subroutine lnd2atm(bounds, & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + call l2g( bounds, & + water_inst%waterfluxbulk_inst%qstreamflow_lun (bounds%begl:bounds%endl), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc (bounds%begg:bounds%endg), & + l2g_scale_type='unity' ) + ! convert from m3/s to mm/s (discharge to flux) + do g = bounds%begg, bounds%endg + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & + * 1.e3_r8 / (1.e6_r8 * grc%area(g)) + enddo + + ! for now, set surface runoff to zero and subsurface runoff to streamflow + ! instead of modifying src/cpl/*/lnd_import_export.F90 + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(bounds%begg:bounds%endg) = 0._r8 + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(bounds%begg:bounds%endg) = water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) + do c = bounds%begc, bounds%endc if (col%active(c)) then ! It's not entirely appropriate to put qflx_liq_from_ice_col into From cbd634141d9aec070daa0950272600aaeb4b5318 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 24 Mar 2021 11:08:22 -0600 Subject: [PATCH 041/153] add to gridcell balance check --- src/biogeophys/BalanceCheckMod.F90 | 27 ++++++++++++++++++----- src/biogeophys/HillslopeHydrologyMod.F90 | 28 ++++++++++++++---------- src/biogeophys/SoilHydrologyMod.F90 | 2 +- src/biogeophys/WaterStateType.F90 | 18 ++++++++++++--- src/main/lnd2atmMod.F90 | 10 ++++++--- 5 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index c0c754a44e..a31fb83482 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -215,6 +215,7 @@ subroutine WaterGridcellBalanceSingle(bounds, & ! ! !USES: use subgridAveMod, only: c2g + use LandunitType , only : lun ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -231,8 +232,8 @@ subroutine WaterGridcellBalanceSingle(bounds, & character(len=5) , intent(in) :: flag ! specifies begwb or endwb ! ! !LOCAL VARIABLES: - integer :: g ! indices - integer :: begc, endc, begg, endg ! bounds + integer :: g, l ! indices + integer :: begc, endc, begl, endl, begg, endg ! bounds real(r8) :: wb_col(bounds%begc:bounds%endc) ! temporary column-level water mass real(r8) :: wb_grc(bounds%begg:bounds%endg) ! temporary grid cell-level water mass real(r8) :: qflx_liq_dynbal_left_to_dribble(bounds%begg:bounds%endg) ! grc liq dynamic land cover change conversion runoff flux @@ -250,6 +251,8 @@ subroutine WaterGridcellBalanceSingle(bounds, & begc = bounds%begc endc = bounds%endc + begl = bounds%begl + endl = bounds%endl begg = bounds%begg endg = bounds%endg @@ -266,6 +269,13 @@ subroutine WaterGridcellBalanceSingle(bounds, & call c2g(bounds, wb_col(begc:endc), wb_grc(begg:endg), & c2l_scale_type='urbanf', l2g_scale_type='unity') + ! add landunit level state variable, convert from (m3) to (kg m-2) + do l = begl, endl + g = lun%gridcell(l) + wb_grc(g) = wb_grc(g) + waterstate_inst%stream_water_lun(l) & + *1e3_r8/(grc%area(g)*1.e6_r8) + enddo + ! Call the beginning or ending version of the subroutine according ! to flag value if (flag == 'begwb') then @@ -713,15 +723,22 @@ subroutine BalanceCheck( bounds, & + qflx_sfc_irrig_grc(g) & + qflx_glcice_dyn_water_flux_grc(g) & - qflx_evap_tot_grc(g) & - - qflx_surf_grc(g) & +! - qflx_surf_grc(g) & - qflx_qrgwl_grc(g) & - - qflx_drain_grc(g) & - - qflx_drain_perched_grc(g) & +! - qflx_drain_grc(g) & +! - qflx_drain_perched_grc(g) & - qflx_ice_runoff_grc(g) & - qflx_snwcp_discarded_liq_grc(g) & - qflx_snwcp_discarded_ice_grc(g)) * dtime end do + ! add landunit level flux variable, convert from (m3/s) to (kg m-2 s-1) + do l = bounds%begl, bounds%endl + g = lun%gridcell(l) + errh2o_grc(g) = errh2o_grc(g) + waterflux_inst%qstreamflow_lun(l) & + *1e3_r8/(grc%area(g)*1.e6_r8) * dtime + enddo + errh2o_max_val = maxval(abs(errh2o_grc(bounds%begg:bounds%endg))) if (errh2o_max_val > h2o_warning_thresh) then diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 96cab378a0..c0740d7202 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -375,7 +375,7 @@ subroutine InitHillslope(bounds,fsurdat) do nh = 1, nhillslope if(hillslope_area(nh) > 0._r8) then - nhill_per_landunit(nh) = grc%area(g)*1.e6*lun%wtgcell(l) & + nhill_per_landunit(nh) = grc%area(g)*1.e6_r8*lun%wtgcell(l) & *pct_hillslope(l,nh)*0.01/hillslope_area(nh) endif enddo @@ -399,7 +399,7 @@ subroutine InitHillslope(bounds,fsurdat) if (sum(hillslope_area) == 0._r8) then do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) - col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6 ! km2 to m2 + col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6_r8 ! km2 to m2 col%hill_distance(c) = sqrt(col%hill_area(c)) & *((c-lun%coli(l))/ncol_per_hillslope(nh)) col%hill_width(c) = sqrt(col%hill_area(c)) @@ -424,7 +424,7 @@ subroutine InitHillslope(bounds,fsurdat) endif check_weight = check_weight + col%wtlunit(c) enddo - if (abs(1._r8 - check_weight) > 1.e-6) then + if (abs(1._r8 - check_weight) > 1.e-6_r8) then write(iulog,*) 'col%wtlunit does not sum to 1: ', check_weight write(iulog,*) 'weights: ', col%wtlunit(lun%coli(l):lun%colf(l)) write(iulog,*) ' ' @@ -1016,6 +1016,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & integer :: c, l, g, i, j real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) + real(r8) :: qflx_drain_perched_vol ! volumetric perched water table runoff (m3/s) real(r8) :: dtime ! land model time step (sec) character(len=*), parameter :: subname = 'HillslopeUpdateStreamWater' @@ -1025,7 +1026,9 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input/Output: [real(r8) (:) ] stream water volume (m3) qstreamflow => waterfluxbulk_inst%qstreamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Input: [real(r8) (:) ] discharge from columns (m3/s) - qflx_surf => waterfluxbulk_inst%qflx_surf_col & ! Output: [real(r8) (:) ] total surface runoff (mm H2O /s) + qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) + qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) + stream_water_depth => waterstatebulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) ) ! Get time step @@ -1036,18 +1039,21 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & if(lun%itype(l) == istsoil) then do c = lun%coli(l), lun%colf(l) - qflx_surf_vol = qflx_surf(c)*1.e-3 & - *(grc%area(g)*1.e6*col%wtgcell(c)) + qflx_surf_vol = qflx_surf(c)*1.e-3_r8 & + *(grc%area(g)*1.e6_r8*col%wtgcell(c)) + qflx_drain_perched_vol = qflx_drain_perched(c)*1.e-3_r8 & + *(grc%area(g)*1.e6_r8*col%wtgcell(c)) stream_water_volume(l) = stream_water_volume(l) & - + (qdischarge(c) + qflx_surf_vol) * dtime + + (qdischarge(c) + qflx_drain_perched_vol & + + qflx_surf_vol) * dtime enddo stream_water_volume(l) = stream_water_volume(l) & - qstreamflow(l) * dtime + + stream_water_depth(l) = stream_water_volume(l) & + /lun%stream_channel_length(l) & + /lun%stream_channel_width(l) - write(iulog,*) 'checktdepth2: ',stream_water_volume(l),qstreamflow(l) - write(iulog,*) 'checktdepth3: ',lun%stream_channel_length(l), & - lun%stream_channel_width(l),lun%stream_channel_depth(l) - write(iulog,*) ' ' endif enddo diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index d01732fec2..8f35b93d05 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2795,7 +2795,7 @@ subroutine LateralFlowHillslope(bounds, & ! scaled by total area of column in gridcell divided by column area if (col%cold(c) == ispval) then qdischarge(c) = qflx_latflow_out_vol(c) & - *(grc%area(g)*1.e6*col%wtgcell(c)/col%hill_area(c)) + *(grc%area(g)*1.e6_r8*col%wtgcell(c)/col%hill_area(c)) endif ! convert volumetric flow to equivalent flux diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 56d6ff49f4..9a244d2e5f 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -52,9 +52,9 @@ module WaterStateType real(r8) :: aquifer_water_baseline ! baseline value for water in the unconfined aquifer (wa_col) for this bulk / tracer (mm) ! Hillslope stream variables - real(r8), pointer :: stream_water_lun (:) ! landunit water in the streams (m3) + real(r8), pointer :: stream_water_lun (:) ! landunit volume of water in the streams (m3) + real(r8), pointer :: stream_water_depth_lun (:) ! landunit depth of water in the streams (m3) - contains procedure, public :: Init @@ -157,6 +157,9 @@ subroutine InitAllocate(this, bounds, tracer_vars) call AllocateVar1d(var = this%stream_water_lun, name = 'stream_water_lun', & container = tracer_vars, & bounds = bounds, subgrid_level = BOUNDS_SUBGRID_LANDUNIT) + call AllocateVar1d(var = this%stream_water_depth_lun, name = 'stream_water_depth_lun', & + container = tracer_vars, & + bounds = bounds, subgrid_level = BOUNDS_SUBGRID_LANDUNIT) end subroutine InitAllocate @@ -169,6 +172,8 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) ! !USES: use histFileMod , only : hist_addfld1d, hist_addfld2d, no_snow_normal use clm_varctl , only : use_soil_moisture_streams + use GridcellType , only : grc + ! ! !ARGUMENTS: class(waterstate_type), intent(in) :: this @@ -281,8 +286,15 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) this%stream_water_lun(begl:endl) = spval call hist_addfld1d (fname=this%info%fname('STREAM_WATER_VOLUME'), units='m3', & avgflag='A', & - long_name=this%info%lname('water in stream channel (hillslope hydrology only)'), & + long_name=this%info%lname('volume of water in stream channel (hillslope hydrology only)'), & ptr_lunit=this%stream_water_lun, l2g_scale_type='veg', default='inactive') + + this%stream_water_depth_lun(begl:endl) = spval + call hist_addfld1d (fname=this%info%fname('STREAM_WATER_DEPTH'), units='m', & + avgflag='A', & + long_name=this%info%lname('depth of water in stream channel (hillslope hydrology only)'), & + ptr_lunit=this%stream_water_depth_lun, l2g_scale_type='veg', default='inactive') + end if ! (rgk 02-02-2017) There is intentionally no entry here for stored plant water diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index f10720f338..09d3c8a7cc 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -159,6 +159,7 @@ subroutine lnd2atm(bounds, & ! ! !USES: use ch4varcon , only : ch4offline + use clm_varctl , only : use_hillslope ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -350,7 +351,8 @@ subroutine lnd2atm(bounds, & water_inst%waterfluxbulk_inst%qstreamflow_lun (bounds%begl:bounds%endl), & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc (bounds%begg:bounds%endg), & l2g_scale_type='unity' ) - ! convert from m3/s to mm/s (discharge to flux) + + ! convert streamflow from m3/s to mm/s (discharge to flux) do g = bounds%begg, bounds%endg water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & @@ -359,8 +361,10 @@ subroutine lnd2atm(bounds, & ! for now, set surface runoff to zero and subsurface runoff to streamflow ! instead of modifying src/cpl/*/lnd_import_export.F90 - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(bounds%begg:bounds%endg) = 0._r8 - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(bounds%begg:bounds%endg) = water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) + if(use_hillslope) then + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(bounds%begg:bounds%endg) = 0._r8 + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(bounds%begg:bounds%endg) = water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) + endif do c = bounds%begc, bounds%endc if (col%active(c)) then From 2bf70fd460552e44a0b6b11a917d76b05d20a168 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 31 Mar 2021 14:57:08 -0600 Subject: [PATCH 042/153] fix wtlunit --- src/biogeophys/HillslopeHydrologyMod.F90 | 53 +++++++++++++++++------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 5224b6d774..49578b3112 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -83,7 +83,10 @@ subroutine InitHillslope(bounds,fsurdat) integer :: ierr ! error code integer :: c, l, g, i, j, ci, nh ! indices - real(r8) :: hillslope_area ! total area of hillslope + real(r8) :: ncol_per_hillslope(nhillslope) ! number of columns per hillslope + real(r8) :: hillslope_area(nhillslope) ! area of hillslope + real(r8) :: nhill_per_landunit(nhillslope) ! total number of each representative hillslope per landunit + real(r8) :: check_weight character(len=*), parameter :: subname = 'InitHillslope' @@ -315,45 +318,65 @@ subroutine InitHillslope(bounds,fsurdat) enddo - ! Calculate total (representative) hillslope area on landunit - ! weighted relative to one another via pct_hillslope - hillslope_area = 0._r8 + ! Calculate total area of each hillslope in landunit and + ! number of columns in each hillslope + ncol_per_hillslope(:)= 0._r8 + hillslope_area(:) = 0._r8 do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) if (nh > 0) then - hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) + ncol_per_hillslope(nh) = ncol_per_hillslope(nh) + 1 + hillslope_area(nh) = hillslope_area(nh) + col%hill_area(c) endif enddo + + ! Total area occupied by each hillslope (m2) is + ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 + ! Number of representative hillslopes per landunit + ! is the total area divided by individual area + do nh = 1, nhillslope + if(hillslope_area(nh) > 0._r8) then + nhill_per_landunit(nh) = grc%area(g)*1.e6_r8*lun%wtgcell(l) & + *pct_hillslope(l,nh)*0.01/hillslope_area(nh) + endif + enddo + ! if missing hillslope information on surface dataset, fill data ! and recalculate hillslope_area - if (hillslope_area == 0._r8) then + if (sum(hillslope_area) == 0._r8) then do c = lun%coli(l), lun%colf(l) - col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6 ! km2 to m2 - col%hill_distance(c) = sqrt(col%hill_area(c)) + nh = col%hillslope_ndx(c) + col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6_r8 ! km2 to m2 + col%hill_distance(c) = sqrt(col%hill_area(c)) & + *((c-lun%coli(l))/ncol_per_hillslope(nh)) col%hill_width(c) = sqrt(col%hill_area(c)) - col%hill_elev(c) = col%topo_std(c) + col%hill_elev(c) = col%topo_std(c) & + *((c-lun%coli(l))/ncol_per_hillslope(nh)) col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) col%hill_aspect(c) = (rpi/2.) ! east (arbitrarily chosen) nh = col%hillslope_ndx(c) pct_hillslope(l,nh) = 100/nhillslope - hillslope_area = hillslope_area & - + col%hill_area(c)*(pct_hillslope(l,nh)*0.01_r8) enddo endif ! Recalculate column weights using input areas + check_weight = 0._r8 do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) if (nh > 0) then - col%wtlunit(c) = col%hill_area(c) & - * (pct_hillslope(l,nh)*0.01_r8)/hillslope_area + col%wtlunit(c) = (col%hill_area(c)/hillslope_area(nh)) & + * (pct_hillslope(l,nh)*0.01_r8) else col%wtlunit(c) = 0._r8 endif + check_weight = check_weight + col%wtlunit(c) enddo - + if (abs(1._r8 - check_weight) > 1.e-6_r8) then + write(iulog,*) 'col%wtlunit does not sum to 1: ', check_weight + write(iulog,*) 'weights: ', col%wtlunit(lun%coli(l):lun%colf(l)) + write(iulog,*) ' ' + endif endif enddo From 03967e09189b198b36ff41be83490ee9a20b6eb5 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 31 Mar 2021 15:08:53 -0600 Subject: [PATCH 043/153] scale qdischarge --- src/biogeophys/SoilHydrologyMod.F90 | 8 ++++++-- src/main/histFileMod.F90 | 9 ++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 6249fcc34d..54ec1acf06 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2785,8 +2785,12 @@ subroutine LateralFlowHillslope(bounds, & ! include ice impedance in transmissivity qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad - ! currently this is redundant to above - qdischarge(c) = qflx_latflow_out_vol(c) + ! qdischarge from lowest column is qflx_latflow_out_vol + ! scaled by total area of column in gridcell divided by column area + if (col%cold(c) == ispval) then + qdischarge(c) = qflx_latflow_out_vol(c) & + *(grc%area(g)*1.e6*col%wtgcell(c)/col%hill_area(c)) + endif ! convert volumetric flow to equivalent flux qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index eb06dac26c..2d0d087b3e 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -2771,11 +2771,7 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='levdcmp', xtype=tape(t)%ncprec, dim1name='levdcmp', & long_name='coordinate levels for soil decomposition variables', units='m', ncid=nfid(t)) - if(use_hillslope)then - - if (tape(t)%dov2xy) then - !pass - else + if(use_hillslope .and. .not.tape(t)%dov2xy) then call ncd_defvar(varname='hslp_distance', xtype=ncd_double, & dim1name=namec, long_name='hillslope column distance', & units='m', ncid=nfid(t)) @@ -2804,7 +2800,6 @@ subroutine htape_timeconst(t, mode) dim1name=namec, long_name='hillslope uphill column index', & ncid=nfid(t)) end if - end if if(use_fates)then @@ -2878,7 +2873,7 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='levdcmp', data=zsoi_1d, ncid=nfid(t), flag='write') end if - if (.not.tape(t)%dov2xy) then + if(use_hillslope .and. .not.tape(t)%dov2xy) then call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') From 3dea895cf473c0db8cd63c070d2b8806802f8edc Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 14 Jul 2021 08:03:26 -0600 Subject: [PATCH 044/153] add use_hillslope_routing namelist variable --- bld/CLMBuildNamelist.pm | 7 ++ bld/namelist_files/namelist_defaults_ctsm.xml | 1 + .../namelist_definition_ctsm.xml | 5 ++ src/biogeophys/HillslopeHydrologyMod.F90 | 77 +++++++++++-------- src/biogeophys/HydrologyDrainageMod.F90 | 20 ++--- src/biogeophys/SoilHydrologyMod.F90 | 19 ++++- src/main/clm_varctl.F90 | 1 + src/main/controlMod.F90 | 5 ++ 8 files changed, 89 insertions(+), 46 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index def5eff0a1..1ef52cede8 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3048,6 +3048,13 @@ sub setup_logic_hillslope { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope_routing', 'use_hillslope'=>$nl_flags->{'use_hillslope'} ); + my $use_hillslope = $nl->get_value('use_hillslope'); + my $use_hillslope_routing = $nl->get_value('use_hillslope_routing'); + if ( (! &value_is_true($use_hillslope)) && &value_is_true($use_hillslope_routing) ) { + $log->fatal_error("Cannot turn use_hillslope_routing on when use_hillslope is off\n" ); + } + } #------------------------------------------------------------------------------- diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index d6ce1a4a7b..81f5da3701 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -592,6 +592,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .false. +.false. .false. diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 1bd8ead631..5b9630de8b 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -724,6 +724,11 @@ LUNA: Leaf Utilization of Nitrogen for Assimilation Toggle to turn on the hillslope hydrology model + +Toggle to turn on surface water routing in the hillslope hydrology model + + Toggle to turn on the plant hydraulic stress model diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index c0740d7202..cb59127ed8 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -11,6 +11,7 @@ module HillslopeHydrologyMod use spmdMod , only : masterproc use abortutils , only : endrun use clm_varctl , only : iulog + use clm_varctl , only : use_hillslope_routing use decompMod , only : bounds_type use clm_varcon , only : rpi @@ -262,40 +263,42 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(ihillslope_in) - allocate(fstream_in(bounds%begg:bounds%endg)) - call ncd_io(ncid=ncid, varname='h_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - if (masterproc) then - write(iulog,*) 'h_stream_depth found on surface data set' - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - lun%stream_channel_depth(l) = fstream_in(g) - enddo - endif - call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - if (masterproc) then - write(iulog,*) 'h_stream_width found on surface data set' + if (use_hillslope_routing) then + allocate(fstream_in(bounds%begg:bounds%endg)) + call ncd_io(ncid=ncid, varname='h_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + if (masterproc) then + write(iulog,*) 'h_stream_depth found on surface data set' + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_depth(l) = fstream_in(g) + enddo + endif + call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + if (masterproc) then + write(iulog,*) 'h_stream_width found on surface data set' + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_width(l) = fstream_in(g) + enddo end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - lun%stream_channel_width(l) = fstream_in(g) - enddo - end if - call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - if (masterproc) then - write(iulog,*) 'h_stream_slope found on surface data set' + call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + if (masterproc) then + write(iulog,*) 'h_stream_slope found on surface data set' + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_slope(l) = fstream_in(g) + enddo end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - lun%stream_channel_slope(l) = fstream_in(g) - enddo - end if - deallocate(fstream_in) - + deallocate(fstream_in) + endif + ! Set hillslope hydrology column level variables ! This needs to match how columns set up in subgridMod do l = bounds%begl,bounds%endl @@ -356,8 +359,8 @@ subroutine InitHillslope(bounds,fsurdat) enddo - ! Calculate total (representative) hillslope area on landunit - ! weighted relative to one another via pct_hillslope + ! Calculate total hillslope area on landunit and + ! number of columns in each hillslope ncol_per_hillslope(:)= 0._r8 hillslope_area(:) = 0._r8 do c = lun%coli(l), lun%colf(l) @@ -1054,6 +1057,14 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & /lun%stream_channel_length(l) & /lun%stream_channel_width(l) + if (1==2) then + write(iulog,*) 'checktdepth2: ',g,l,stream_water_volume(l),stream_water_volume(l)*(1.e3/(grc%area(g)*1.e6_r8)) + write(iulog,*) 'checktdepth3: ',g,l,qstreamflow(l),& + qstreamflow(l)*(1.e3/(grc%area(g)*1.e6_r8))*dtime + write(iulog,*) 'checktdepth4: ',lun%stream_channel_length(l), & + lun%stream_channel_width(l),lun%stream_channel_depth(l) + write(iulog,*) ' ' + endif endif enddo diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 98751f7711..4cd70d48b8 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -54,7 +54,8 @@ subroutine HydrologyDrainage(bounds, & use landunit_varcon , only : istwet, istsoil, istice_mec, istcrop use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv, icol_sunwall, icol_shadewall use clm_varcon , only : denh2o, denice - use clm_varctl , only : use_vichydro, use_hillslope + use clm_varctl , only : use_vichydro, use_hillslope, use_hillslope_routing + use clm_varpar , only : nlevgrnd, nlevurb use clm_time_manager , only : get_step_size_real, get_nstep use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, PerchedLateralFlowHillslope, LateralFlowPowerLaw, LateralFlowHillslope @@ -157,15 +158,16 @@ subroutine HydrologyDrainage(bounds, & soilhydrology_inst, soilstate_inst, & waterstatebulk_inst, waterfluxbulk_inst, & wateratm2lndbulk_inst) - - call HillslopeStreamOutflow(bounds,& - waterstatebulk_inst, waterfluxbulk_inst, & - streamflow_method=streamflow_manning) - - call HillslopeUpdateStreamWater(bounds, & - waterstatebulk_inst, waterfluxbulk_inst, & - wateratm2lndbulk_inst) + if(use_hillslope_routing) then + call HillslopeStreamOutflow(bounds,& + waterstatebulk_inst, waterfluxbulk_inst, & + streamflow_method=streamflow_manning) + + call HillslopeUpdateStreamWater(bounds, & + waterstatebulk_inst, waterfluxbulk_inst, & + wateratm2lndbulk_inst) + endif else call PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 8f35b93d05..87ffb698ef 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2520,6 +2520,7 @@ subroutine LateralFlowHillslope(bounds, & use clm_time_manager , only : get_step_size use clm_varpar , only : nlevsoi, nlevgrnd, nlayer, nlayert use clm_varcon , only : pondmx, watmin,rpi, secspday, nlvic + use clm_varctl , only : use_hillslope_routing use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv use abortutils , only : endrun use GridcellType , only : grc @@ -2588,13 +2589,14 @@ subroutine LateralFlowHillslope(bounds, & real(r8) :: transmis ! transmissivity real(r8) :: dgrad ! hydraulic head gradient real(r8) :: stream_water_depth ! depth of water in stream channel + real(r8) :: stream_channel_depth ! depth of stream channel real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 1._r8 ! anisotropy scalar real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) real(r8) :: qflx_latflow_avg(bounds%begc:bounds%endc) real(r8) :: larea - integer :: c0, c_src, c_dst, nstep, nbase + integer :: c0, c_src, c_dst, nstep integer :: l !----------------------------------------------------------------------- @@ -2616,6 +2618,9 @@ subroutine LateralFlowHillslope(bounds, & qflx_latflow_in => waterfluxbulk_inst%qflx_latflow_in_col, & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) + tdepth => wateratm2lndbulk_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) + tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) + depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) Dsmax => soilhydrology_inst%dsmax_col , & ! Input: [real(r8) (:) ] max. velocity of baseflow (mm/day) @@ -2720,14 +2725,20 @@ subroutine LateralFlowHillslope(bounds, & - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else - stream_water_depth = stream_water_volume(l) & - /lun%stream_channel_length(l)/lun%stream_channel_width(l) + if(use_hillslope_routing) then + stream_water_depth = stream_water_volume(l) & + /lun%stream_channel_length(l)/lun%stream_channel_width(l) + stream_channel_depth = lun%stream_channel_depth(l) + else + stream_water_depth = tdepth(g) + stream_channel_depth = tdepth_bankfull(g) + endif ! flow between channel and lowest column ! bankfull height is defined to be zero dgrad = (col%hill_elev(c)-zwt(c)) & ! ignore overbankfull storage - - min((stream_water_depth - lun%stream_channel_depth(l)),0._r8) + - min((stream_water_depth - stream_channel_depth),0._r8) dgrad = dgrad / (col%hill_distance(c)) ! dgrad cannot be negative when channel is empty diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 388aff1169..4fc479ac34 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -310,6 +310,7 @@ module clm_varctl !---------------------------------------------------------- logical, public :: use_hillslope = .false. ! true => use multi-column hillslope hydrology + logical, public :: use_hillslope_routing = .false. ! true => use surface water routing in hillslope hydrology !---------------------------------------------------------- ! plant hydraulic stress switch diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 90875a8749..43cd48f617 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -247,6 +247,8 @@ subroutine control_init(dtime) namelist /clm_inparm/ use_hillslope + namelist /clm_inparm/ use_hillslope_routing + namelist /clm_inparm/ use_hydrstress namelist /clm_inparm/ use_dynroot @@ -748,6 +750,8 @@ subroutine control_spmd() call mpi_bcast (use_hillslope, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_hillslope_routing, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_hydrstress, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_dynroot, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -1015,6 +1019,7 @@ subroutine control_print () write(iulog,*) ' land-ice albedos (unitless 0-1) = ', albice write(iulog,*) ' hillslope hydrology = ', use_hillslope + write(iulog,*) ' hillslope routing = ', use_hillslope_routing write(iulog,*) ' pre-defined soil layer structure = ', soil_layerstruct_predefined write(iulog,*) ' user-defined soil layer structure = ', soil_layerstruct_userdefined write(iulog,*) ' user-defined number of soil layers = ', soil_layerstruct_userdefined_nlevsoi From 98d1c450d17a08a1f94a8c4427c79ae5439e4a12 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 14 Jul 2021 08:29:25 -0600 Subject: [PATCH 045/153] re-add tdepth --- src/biogeophys/Wateratm2lndBulkType.F90 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/biogeophys/Wateratm2lndBulkType.F90 b/src/biogeophys/Wateratm2lndBulkType.F90 index 8fa4e77774..4aacbe11c2 100644 --- a/src/biogeophys/Wateratm2lndBulkType.F90 +++ b/src/biogeophys/Wateratm2lndBulkType.F90 @@ -30,6 +30,8 @@ module Wateratm2lndBulkType real(r8), pointer :: volrmch_grc (:) ! rof volr main channel (m3) real(r8), pointer :: volr_grc (:) ! rof volr total volume (m3) + real(r8), pointer :: tdepth_grc (:) ! rof tributary water depth (m) + real(r8), pointer :: tdepthmax_grc (:) ! rof tributary bankfull water depth (m) real(r8), pointer :: forc_rh_grc (:) ! atmospheric relative humidity (%) real(r8) , pointer :: prec365_col (:) ! col 365-day running mean of tot. precipitation (see comment in UpdateAccVars regarding why this is col-level despite other prec accumulators being patch-level) real(r8) , pointer :: prec60_patch (:) ! patch 60-day running mean of tot. precipitation (mm/s) @@ -117,6 +119,8 @@ subroutine InitBulkAllocate(this, bounds) begc = bounds%begc; endc= bounds%endc begg = bounds%begg; endg= bounds%endg + allocate(this%tdepth_grc (begg:endg)) ; this%tdepth_grc (:) = ival + allocate(this%tdepthmax_grc (begg:endg)) ; this%tdepthmax_grc (:) = ival allocate(this%volr_grc (begg:endg)) ; this%volr_grc (:) = ival allocate(this%volrmch_grc (begg:endg)) ; this%volrmch_grc (:) = ival allocate(this%forc_rh_grc (begg:endg)) ; this%forc_rh_grc (:) = ival @@ -154,6 +158,16 @@ subroutine InitBulkHistory(this, bounds) begp = bounds%begp; endp= bounds%endp begg = bounds%begg; endg= bounds%endg + this%tdepth_grc(begg:endg) = spval + call hist_addfld1d (fname='TDEPTH', units='m', & + avgflag='A', long_name='tributary water depth', & + ptr_lnd=this%tdepth_grc, default = 'inactive') + + this%tdepthmax_grc(begg:endg) = spval + call hist_addfld1d (fname='TDEPTHMAX', units='m', & + avgflag='A', long_name='tributary bankfull water depth', & + ptr_lnd=this%tdepthmax_grc, default = 'inactive') + this%volr_grc(begg:endg) = spval call hist_addfld1d (fname=this%info%fname('VOLR'), units='m3', & avgflag='A', long_name=this%info%lname('river channel total water storage'), & @@ -461,6 +475,8 @@ subroutine Clean(this) ! rof->lnd deallocate(this%forc_flood_grc) + deallocate(this%tdepth_grc) + deallocate(this%tdepthmax_grc) deallocate(this%volr_grc) deallocate(this%volrmch_grc) From 31585dfc6d9d2eb582794fd86729b04c38a8661c Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 19 Jul 2021 12:25:03 -0600 Subject: [PATCH 046/153] initialize stream_water_lun --- src/biogeophys/WaterStateType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 9a244d2e5f..9b280c3089 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -347,7 +347,7 @@ subroutine InitCold(this, bounds, & this%h2osfc_col(bounds%begc:bounds%endc) = 0._r8 this%snocan_patch(bounds%begp:bounds%endp) = 0._r8 this%liqcan_patch(bounds%begp:bounds%endp) = 0._r8 - + this%stream_water_lun(bounds%begl:bounds%endl) = 0._r8 !-------------------------------------------- ! Set soil water From cf9f512a720978585f8d1ede9ac527ec44259d0b Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 21 Jul 2021 08:06:46 -0600 Subject: [PATCH 047/153] fix solar normalization --- src/main/atm2lndMod.F90 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 166e6a3064..ccf42804bb 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -757,7 +757,7 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) integer :: c,l,g,n ! indices real(r8) :: norm(numrad) real(r8) :: sum_solar(bounds%begg:bounds%endg,numrad) - real(r8) :: sum_wt(bounds%begg:bounds%endg) + real(r8) :: sum_wtlunit(bounds%begg:bounds%endg) character(len=*), parameter :: subname = 'downscale_hillslope_solar' !----------------------------------------------------------------------- @@ -776,7 +776,7 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) ! Initialize column forcing sum_solar(bounds%begg:bounds%endg,1:numrad) = 0._r8 - sum_wt(bounds%begg:bounds%endg) = 0._r8 + sum_wtlunit(bounds%begg:bounds%endg) = 0._r8 do c = bounds%begc,bounds%endc g = col%gridcell(c) forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad) @@ -787,7 +787,7 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) endif sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtlunit(c)*forc_solad_col(c,1:numrad) - sum_wt(g) = sum_wt(g) + col%wtlunit(c) + sum_wtlunit(g) = sum_wtlunit(g) + col%wtlunit(c) end if end do ! Normalize column level solar @@ -796,10 +796,13 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) if (lun%itype(col%landunit(c)) == istsoil) then g = col%gridcell(c) do n = 1,numrad - norm(n) = (sum_solar(g,n)/sum_wt(g)) - if(norm(n) > 0._r8) then - forc_solad_col(c,n) = forc_solad_col(c,n)*(forc_solad_grc(g,n)/norm(n)) + ! absorbed energy is solar flux x area landunit (sum_wtlunit) + if(sum_solar(g,n) > 0._r8) then + norm(n) = sum_wtlunit(g)*forc_solad_grc(g,n)/sum_solar(g,n) + else + norm(n) = 0._r8 endif + forc_solad_col(c,n) = forc_solad_col(c,n)*norm(n) enddo end if forc_solar_col(c) = sum(forc_solad_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) From 7df3ddef583c8262f798ca66e17dca4fbd99ecdf Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 7 Sep 2021 07:34:37 -0600 Subject: [PATCH 048/153] add downscaling flag --- bld/CLMBuildNamelist.pm | 3 ++- bld/namelist_files/namelist_defaults_ctsm.xml | 3 +++ bld/namelist_files/namelist_definition_ctsm.xml | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index def5eff0a1..e11fba9b23 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3043,11 +3043,12 @@ sub setup_logic_luna { sub setup_logic_hillslope { # - # Hillslope hydrology model + # Hillslope model # my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'downscale_hillslope_meteorology' ); } #------------------------------------------------------------------------------- diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index d6ce1a4a7b..c30ed17f59 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -593,6 +593,9 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .false. +.false. +.true. + .false. .true. diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 1bd8ead631..77bcc13b9b 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -721,7 +721,12 @@ LUNA: Leaf Utilization of Nitrogen for Assimilation -Toggle to turn on the hillslope hydrology model +Toggle to turn on the hillslope model + + + +Toggle to turn on meteorological downscaling in hillslope model Date: Tue, 7 Sep 2021 13:52:17 -0600 Subject: [PATCH 049/153] add files --- bld/namelist_files/namelist_defaults_ctsm.xml | 3 +- src/biogeophys/BalanceCheckMod.F90 | 6 ++-- src/biogeophys/HillslopeHydrologyMod.F90 | 16 --------- src/biogeophys/SoilHydrologyMod.F90 | 19 ++++++++--- src/cpl/nuopc/lnd_import_export.F90 | 3 +- src/main/atm2lndMod.F90 | 4 +-- src/main/clm_varctl.F90 | 1 + src/main/controlMod.F90 | 5 +++ src/main/lnd2atmMod.F90 | 33 ++++++++++--------- 9 files changed, 46 insertions(+), 44 deletions(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index a3a8e21902..3c95967bd4 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -610,8 +610,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .false. -.false. -.true. +.true. .false. diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index a5412c2696..db3ab68be2 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -724,10 +724,10 @@ subroutine BalanceCheck( bounds, & + qflx_sfc_irrig_grc(g) & + qflx_glcice_dyn_water_flux_grc(g) & - qflx_evap_tot_grc(g) & -! - qflx_surf_grc(g) & + - qflx_surf_grc(g) & - qflx_qrgwl_grc(g) & -! - qflx_drain_grc(g) & -! - qflx_drain_perched_grc(g) & + - qflx_drain_grc(g) & + - qflx_drain_perched_grc(g) & - qflx_ice_runoff_grc(g) & - qflx_snwcp_discarded_liq_grc(g) & - qflx_snwcp_discarded_ice_grc(g)) * dtime diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 0d1c441cff..12fc303858 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -394,14 +394,6 @@ subroutine InitHillslope(bounds,fsurdat) ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 ! Number of representative hillslopes per landunit ! is the total area divided by individual area -======= - endif - enddo - - ! Total area occupied by each hillslope (m2) is - ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 - ! Number of representative hillslopes per landunit - ! is the total area divided by individual area do nh = 1, nhillslope if(hillslope_area(nh) > 0._r8) then @@ -1092,14 +1084,6 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & /lun%stream_channel_length(l) & /lun%stream_channel_width(l) - if (1==2) then - write(iulog,*) 'checktdepth2: ',g,l,stream_water_volume(l),stream_water_volume(l)*(1.e3/(grc%area(g)*1.e6_r8)) - write(iulog,*) 'checktdepth3: ',g,l,qstreamflow(l),& - qstreamflow(l)*(1.e3/(grc%area(g)*1.e6_r8))*dtime - write(iulog,*) 'checktdepth4: ',lun%stream_channel_length(l), & - lun%stream_channel_width(l),lun%stream_channel_depth(l) - write(iulog,*) ' ' - endif endif enddo diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index f369a24085..2ea37e2c7b 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1804,6 +1804,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & ! ! !USES: use clm_varcon , only : pondmx, tfrz, watmin,rpi, secspday, nlvic + use clm_varctl , only : use_hillslope_routing use LandunitType , only : lun use landunit_varcon , only : istsoil ! @@ -1831,6 +1832,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & real(r8) :: q_perch real(r8) :: q_perch_max real(r8) :: stream_water_depth ! depth of water in stream channel + real(r8) :: stream_channel_depth ! depth of stream channel character(len=32) :: transmissivity_method = 'layersum' ! character(len=32) :: baseflow_method = 'kinematic' @@ -1856,6 +1858,8 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Input: [real(r8) (:) ] perched water table depth (m) + tdepth => wateratm2lndbulk_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) + tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) @@ -1893,6 +1897,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) l = col%landunit(c) + g = col%gridcell(c) qflx_drain_perched(c) = 0._r8 qflx_drain_perched_out(c) = 0._r8 qflx_drain_perched_vol(c) = 0._r8 @@ -1914,14 +1919,20 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & - (col%hill_elev(col%cold(c))-zwt_perched(col%cold(c))) dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else - stream_water_depth = stream_water_volume(l) & - /lun%stream_channel_length(l)/lun%stream_channel_width(l) + if(use_hillslope_routing) then + stream_water_depth = stream_water_volume(l) & + /lun%stream_channel_length(l)/lun%stream_channel_width(l) + stream_channel_depth = lun%stream_channel_depth(l) + else + stream_water_depth = tdepth(g) + stream_channel_depth = tdepth_bankfull(g) + endif ! flow between channel and lowest column ! bankfull height is defined to be zero dgrad = (col%hill_elev(c)-zwt_perched(c)) & ! ignore overbankfull storage - - min(max((stream_water_depth - lun%stream_channel_depth(l)), & + - min(max((stream_water_depth - stream_channel_depth), & (col%hill_elev(c)-frost_table(c))),0._r8) dgrad = dgrad / (col%hill_distance(c)) @@ -2772,7 +2783,7 @@ subroutine LateralFlowHillslope(bounds, & 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) endif enddo - + ! recalculate average flux for no-lateral flow case if(no_lateral_flow) then if (baseflow_method /= 'kinematic') then diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 97ecef55f8..15da342b1d 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -863,7 +863,7 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & ! subsurface runoff is the sum of qflx_drain and qflx_perched_drain do g = begg, endg data1d(g) = waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(g) + & - waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(g) + waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(g) end do call state_setexport_1d(exportState, Flrl_rofsub, data1d(begg:), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -1135,6 +1135,7 @@ subroutine state_setexport_1d(state, fldname, ctsmdata, minus, rc) fldptr1d(g) = ctsmdata(g) end do end if + call check_for_nans(ctsmdata, trim(fldname), 1) end subroutine state_setexport_1d diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 90d2420edc..ee6fd4f403 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -116,7 +116,7 @@ subroutine downscale_forcings(bounds, & ! ! !USES: use clm_varcon , only : rair, cpair, grav - use clm_varctl , only : use_hillslope + use clm_varctl , only : use_hillslope,downscale_hillslope_meteorology use QsatMod , only : Qsat ! ! !ARGUMENTS: @@ -265,7 +265,7 @@ subroutine downscale_forcings(bounds, & end do ! adjust hillslope precpitation before repartitioning rain/snow - if(use_hillslope) then + if(use_hillslope .and. downscale_hillslope_meteorology) then call downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) call downscale_hillslope_precipitation(bounds, topo_inst, atm2lnd_inst, wateratm2lndbulk_inst) endif diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 44cc625c8e..fab2f1e3ae 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -308,6 +308,7 @@ module clm_varctl !---------------------------------------------------------- logical, public :: use_hillslope = .false. ! true => use multi-column hillslope hydrology + logical, public :: downscale_hillslope_meteorology = .false. ! true => downscale meteorological forcing in hillslope model logical, public :: use_hillslope_routing = .false. ! true => use surface water routing in hillslope hydrology !---------------------------------------------------------- diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 8a7c9d6d04..059b423c1f 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -246,6 +246,8 @@ subroutine control_init(dtime) namelist /clm_inparm/ use_hillslope + namelist /clm_inparm/ downscale_hillslope_meteorology + namelist /clm_inparm/ use_hillslope_routing namelist /clm_inparm/ use_hydrstress @@ -741,6 +743,8 @@ subroutine control_spmd() call mpi_bcast (use_hillslope, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (downscale_hillslope_meteorology, 1, MPI_LOGICAL, 0, mpicom, ier) + call mpi_bcast (use_hillslope_routing, 1, MPI_LOGICAL, 0, mpicom, ier) call mpi_bcast (use_hydrstress, 1, MPI_LOGICAL, 0, mpicom, ier) @@ -1006,6 +1010,7 @@ subroutine control_print () write(iulog,*) ' land-ice albedos (unitless 0-1) = ', albice write(iulog,*) ' hillslope hydrology = ', use_hillslope + write(iulog,*) ' downscale hillslope meteorology = ', downscale_hillslope_meteorology write(iulog,*) ' hillslope routing = ', use_hillslope_routing write(iulog,*) ' pre-defined soil layer structure = ', soil_layerstruct_predefined write(iulog,*) ' user-defined soil layer structure = ', soil_layerstruct_userdefined diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index 20c3f04bc3..676def3273 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -159,7 +159,7 @@ subroutine lnd2atm(bounds, & ! ! !USES: use ch4varcon , only : ch4offline - use clm_varctl , only : use_hillslope + use clm_varctl , only : use_hillslope_routing ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -341,27 +341,28 @@ subroutine lnd2atm(bounds, & water_inst%waterfluxbulk_inst%qflx_surf_col (bounds%begc:bounds%endc), & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc (bounds%begg:bounds%endg), & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) - + call c2g( bounds, & water_inst%waterfluxbulk_inst%qflx_drain_col (bounds%begc:bounds%endc), & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) - call l2g( bounds, & - water_inst%waterfluxbulk_inst%qstreamflow_lun (bounds%begl:bounds%endl), & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc (bounds%begg:bounds%endg), & - l2g_scale_type='unity' ) - - ! convert streamflow from m3/s to mm/s (discharge to flux) - do g = bounds%begg, bounds%endg - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & - * 1.e3_r8 / (1.e6_r8 * grc%area(g)) - enddo + if(use_hillslope_routing) then + + call l2g( bounds, & + water_inst%waterfluxbulk_inst%qstreamflow_lun (bounds%begl:bounds%endl), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc (bounds%begg:bounds%endg), & + l2g_scale_type='unity' ) + + ! convert streamflow from m3/s to mm/s (discharge to flux) + do g = bounds%begg, bounds%endg + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & + * 1.e3_r8 / (1.e6_r8 * grc%area(g)) + enddo - ! for now, set surface runoff to zero and subsurface runoff to streamflow - ! instead of modifying src/cpl/*/lnd_import_export.F90 - if(use_hillslope) then + ! for now, set surface runoff to zero and subsurface runoff to streamflow + ! instead of modifying src/cpl/*/lnd_import_export.F90 water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(bounds%begg:bounds%endg) = 0._r8 water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(bounds%begg:bounds%endg) = water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) endif From 2ccca4ef948bafc7143be7ca8054d6013bf4a81a Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 8 Sep 2021 13:11:46 -0600 Subject: [PATCH 050/153] update Externals.cfg --- Externals.cfg | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/Externals.cfg b/Externals.cfg index 448866da08..4d9696c958 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -22,8 +22,8 @@ required = True [mosart] local_path = components/mosart protocol = git -repo_url = https://github.com/ESCOMP/MOSART -tag = mosart1_0_38 +repo_url = https://github.com/swensosc/mosart +branch = pass_tdepth required = True [mizuRoute] @@ -41,20 +41,48 @@ branch = hillslope_hydrology required = True [cmeps] -local_path = cime/src/drivers/nuopc/ +local_path = components/cmeps protocol = git repo_url = https://github.com/ESCOMP/CMEPS.git -tag = cmeps0.13.2 +tag = cmeps0.13.23 required = True [cdeps] local_path = components/cdeps protocol = git repo_url = https://github.com/ESCOMP/CDEPS.git -tag = cdeps0.12.11 +tag = cdeps0.12.19 externals = Externals_CDEPS.cfg required = True +[cpl7] +tag = cpl7.0.3 +protocol = git +repo_url = https://github.com/ESCOMP/CESM_CPL7andDataComps +local_path = components/cpl7 +required = True + +[share] +tag = share1.0.2 +protocol = git +repo_url = https://github.com/ESCOMP/CESM_share +local_path = share +required = True + +[mct] +tag = MCT_2.11.0 +protocol = git +repo_url = https://github.com/MCSclimate/MCT +local_path = libraries/mct +required = True + +[parallelio] +tag = pio2_5_4 +protocol = git +repo_url = https://github.com/NCAR/ParallelIO +local_path = libraries/parallelio +required = True + [doc-builder] local_path = doc/doc-builder protocol = git From 81d4fb2068de03b1db6f039061a4e3e2d6109052 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 20 Sep 2021 12:55:15 -0600 Subject: [PATCH 051/153] add downscale_hillslope_meteorology flag to TopoMod --- src/main/TopoMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index f3d1bb8c74..6e40b0ca08 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -15,7 +15,7 @@ module TopoMod use glcBehaviorMod , only : glc_behavior_type use landunit_varcon, only : istice, istsoil use filterColMod , only : filter_col_type, col_filter_from_logical_array_active_only - use clm_varctl , only : use_hillslope + use clm_varctl , only : use_hillslope,downscale_hillslope_meteorology ! ! !PUBLIC TYPES: implicit none @@ -140,7 +140,7 @@ subroutine InitCold(this, bounds) ! For other landunits, arbitrarily initialize topo_col to 0 m; for landunits ! where this matters, this will get overwritten in the run loop by values sent ! from CISM - if (lun%itype(l) == istsoil .and. use_hillslope) then + if (lun%itype(l) == istsoil .and. use_hillslope .and. downscale_hillslope_meteorology) then this%topo_col(c) = col%hill_elev(c) this%needs_downscaling_col(c) = .true. else @@ -279,7 +279,7 @@ subroutine UpdateTopo(this, bounds, num_icec, filter_icec, & if (.not. this%needs_downscaling_col(c)) then g = col%gridcell(c) l = col%landunit(c) - if (lun%itype(l) == istsoil .and. use_hillslope) then + if (lun%itype(l) == istsoil .and. use_hillslope .and. downscale_hillslope_meteorology) then this%topo_col(c) = atm_topo(g) & + (col%hill_elev(c) - mean_hillslope_elevation(l)) this%needs_downscaling_col(c) = .true. From 6a9f979f625200cf20e72e993bda7dda34aa8036 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 23 Sep 2021 08:50:55 -0600 Subject: [PATCH 052/153] correct hillslope routing water balance --- src/biogeophys/BalanceCheckMod.F90 | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 6b701ffb37..d3bedf3be0 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -35,7 +35,7 @@ module BalanceCheckMod use landunit_varcon , only : istdlak, istsoil,istcrop,istwet,istice use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_perv, icol_road_imperv - use clm_varctl , only : use_hillslope + use clm_varctl , only : use_hillslope, use_hillslope_routing ! ! !PUBLIC TYPES: implicit none @@ -270,11 +270,21 @@ subroutine WaterGridcellBalanceSingle(bounds, & c2l_scale_type='urbanf', l2g_scale_type='unity') ! add landunit level state variable, convert from (m3) to (kg m-2) - do l = begl, endl - g = lun%gridcell(l) - wb_grc(g) = wb_grc(g) + waterstate_inst%stream_water_lun(l) & - *1e3_r8/(grc%area(g)*1.e6_r8) - enddo + if (use_hillslope_routing) then + do l = bounds%begl, bounds%endl + g = lun%gridcell(l) + ! input water flux to stream channel (-) + errh2o_grc(g) = errh2o_grc(g) & + - (qflx_surf_grc(g) & + + qflx_drain_grc(g) & + + qflx_drain_perched_grc(g)) * dtime + + ! output water flux from streamflow (+) + errh2o_grc(g) = errh2o_grc(g) & + + waterflux_inst%qstreamflow_lun(l) & + *1e3_r8/(grc%area(g)*1.e6_r8) * dtime + enddo + endif ! Call the beginning or ending version of the subroutine according ! to flag value From e8814ecd462dd9491d52f2ab3888f78802599d5d Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 23 Sep 2021 09:38:16 -0600 Subject: [PATCH 053/153] move streamflow variable --- src/biogeophys/BalanceCheckMod.F90 | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index d3bedf3be0..777b4de322 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -271,18 +271,10 @@ subroutine WaterGridcellBalanceSingle(bounds, & ! add landunit level state variable, convert from (m3) to (kg m-2) if (use_hillslope_routing) then - do l = bounds%begl, bounds%endl + do l = begl, endl g = lun%gridcell(l) - ! input water flux to stream channel (-) - errh2o_grc(g) = errh2o_grc(g) & - - (qflx_surf_grc(g) & - + qflx_drain_grc(g) & - + qflx_drain_perched_grc(g)) * dtime - - ! output water flux from streamflow (+) - errh2o_grc(g) = errh2o_grc(g) & - + waterflux_inst%qstreamflow_lun(l) & - *1e3_r8/(grc%area(g)*1.e6_r8) * dtime + wb_grc(g) = wb_grc(g) + waterstate_inst%stream_water_lun(l) & + *1e3_r8/(grc%area(g)*1.e6_r8) enddo endif @@ -745,11 +737,21 @@ subroutine BalanceCheck( bounds, & end do ! add landunit level flux variable, convert from (m3/s) to (kg m-2 s-1) - do l = bounds%begl, bounds%endl - g = lun%gridcell(l) - errh2o_grc(g) = errh2o_grc(g) + waterflux_inst%qstreamflow_lun(l) & - *1e3_r8/(grc%area(g)*1.e6_r8) * dtime - enddo + if (use_hillslope_routing) then + do l = bounds%begl, bounds%endl + g = lun%gridcell(l) + ! input water flux to stream channel (-) + errh2o_grc(g) = errh2o_grc(g) & + - (qflx_surf_grc(g) & + + qflx_drain_grc(g) & + + qflx_drain_perched_grc(g)) * dtime + + ! output water flux from streamflow (+) + errh2o_grc(g) = errh2o_grc(g) & + + waterflux_inst%qstreamflow_lun(l) & + *1e3_r8/(grc%area(g)*1.e6_r8) * dtime + enddo + endif errh2o_max_val = maxval(abs(errh2o_grc(bounds%begg:bounds%endg))) From e8d9c815fba90622a27777cc1ca039d209f1d676 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 23 Sep 2021 11:30:23 -0600 Subject: [PATCH 054/153] add drain_perched term in lnd2atmMod --- src/main/lnd2atmMod.F90 | 42 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index 676def3273..c9bcd73036 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -347,26 +347,6 @@ subroutine lnd2atm(bounds, & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) - if(use_hillslope_routing) then - - call l2g( bounds, & - water_inst%waterfluxbulk_inst%qstreamflow_lun (bounds%begl:bounds%endl), & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc (bounds%begg:bounds%endg), & - l2g_scale_type='unity' ) - - ! convert streamflow from m3/s to mm/s (discharge to flux) - do g = bounds%begg, bounds%endg - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & - * 1.e3_r8 / (1.e6_r8 * grc%area(g)) - enddo - - ! for now, set surface runoff to zero and subsurface runoff to streamflow - ! instead of modifying src/cpl/*/lnd_import_export.F90 - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(bounds%begg:bounds%endg) = 0._r8 - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(bounds%begg:bounds%endg) = water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) - endif - do c = bounds%begc, bounds%endc if (col%active(c)) then ! It's not entirely appropriate to put qflx_liq_from_ice_col into @@ -410,6 +390,28 @@ subroutine lnd2atm(bounds, & c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + if(use_hillslope_routing) then + + call l2g( bounds, & + water_inst%waterfluxbulk_inst%qstreamflow_lun (bounds%begl:bounds%endl), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc (bounds%begg:bounds%endg), & + l2g_scale_type='unity' ) + + ! convert streamflow from m3/s to mm/s (discharge to flux) + do g = bounds%begg, bounds%endg + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & + * 1.e3_r8 / (1.e6_r8 * grc%area(g)) + enddo + + ! for now, set surface runoff and perched drainage to zero, and + ! set subsurface runoff to streamflow (which accounts for all three fluxes) + ! instead of modifying src/cpl/*/lnd_import_export.F90 + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(bounds%begg:bounds%endg) = 0._r8 + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(bounds%begg:bounds%endg) = 0._r8 + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(bounds%begg:bounds%endg) = water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) + endif + call c2g( bounds, & water_inst%waterfluxbulk_inst%qflx_sfc_irrig_col (bounds%begc:bounds%endc), & water_inst%waterlnd2atmbulk_inst%qirrig_grc(bounds%begg:bounds%endg), & From 230b15c2dc44ccd1e7ef34f48f34ca61a6481ae4 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 16 Nov 2021 10:23:52 -0700 Subject: [PATCH 055/153] merge lateral subsurface flow subroutines --- src/biogeophys/HillslopeHydrologyMod.F90 | 117 ++-- src/biogeophys/HydrologyDrainageMod.F90 | 41 +- src/biogeophys/SoilHydrologyMod.F90 | 794 +++++------------------ src/biogeophys/WaterFluxType.F90 | 66 +- src/main/ColumnType.F90 | 3 + 5 files changed, 279 insertions(+), 742 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 12fc303858..534ad7dd8e 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -14,6 +14,7 @@ module HillslopeHydrologyMod use clm_varctl , only : use_hillslope_routing use decompMod , only : bounds_type use clm_varcon , only : rpi + use spmdMod , only : masterproc, iam ! !PUBLIC TYPES: implicit none @@ -67,6 +68,7 @@ subroutine InitHillslope(bounds,fsurdat) type(bounds_type), intent(in) :: bounds character(len=*) , intent(in) :: fsurdat ! surface data file name integer, pointer :: ihillslope_in(:,:) ! read in - integer + integer, pointer :: ncolumns_hillslope_in(:) ! read in number of columns integer, allocatable :: hill_ndx(:,:) ! hillslope index integer, allocatable :: col_ndx(:,:) ! column index integer, allocatable :: col_dndx(:,:) ! downhill column index @@ -114,7 +116,26 @@ subroutine InitHillslope(bounds,fsurdat) hill_width (bounds%begl:bounds%endl,max_columns_hillslope), & hill_height (bounds%begl:bounds%endl,max_columns_hillslope), & stat=ierr) + + allocate(ncolumns_hillslope_in(bounds%begg:bounds%endg)) + call ncd_io(ncid=ncid, varname='nhillcolumns', flag='read', data=ncolumns_hillslope_in, dim1name=grlnd, readvar=readvar) + if (.not. readvar) then + if (masterproc) then + call endrun( 'ERROR:: nhillcolumns not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + ! vegetated landunits having nonzero hillslope columns + if(lun%itype(l) == istsoil .and. ncolumns_hillslope_in(g) > 0) then + do c = lun%coli(l), lun%colf(l) + col%is_hillslope_column(c) = .true. + enddo + endif + enddo + deallocate(ncolumns_hillslope_in) + allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) @@ -162,15 +183,6 @@ subroutine InitHillslope(bounds,fsurdat) do l = bounds%begl,bounds%endl g = lun%gridcell(l) col_dndx(l,:) = ihillslope_in(g,:) -!scs -!!$ do c=1,max_columns_hillslope -!!$ if (abs(col_dndx(l,c)-col_ndx(l,c)) > 16 .and. col_dndx(l,c) > -999) then -!!$ write(iulog,*) 'colndx ',c,col_ndx(l,c),col_dndx(l,c) -!!$ write(iulog,*) 'colndx2 ',grc%londeg(g),grc%latdeg(g) -!!$ write(iulog,*) 'ihill ',ihillslope_in(g,:) -!!$ endif -!!$ enddo - enddo deallocate(ihillslope_in) @@ -375,7 +387,7 @@ subroutine InitHillslope(bounds,fsurdat) endif if ( allocated(hill_pftndx) ) & col%hill_pftndx(c) = hill_pftndx(l,ci) - + enddo ! Calculate total hillslope area on landunit and @@ -390,38 +402,34 @@ subroutine InitHillslope(bounds,fsurdat) endif enddo - ! Total area occupied by each hillslope (m2) is - ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 - ! Number of representative hillslopes per landunit - ! is the total area divided by individual area - - do nh = 1, nhillslope - if(hillslope_area(nh) > 0._r8) then - nhill_per_landunit(nh) = grc%area(g)*1.e6_r8*lun%wtgcell(l) & - *pct_hillslope(l,nh)*0.01/hillslope_area(nh) - endif - enddo + if (use_hillslope_routing) then + + ! Total area occupied by each hillslope (m2) is + ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 + ! Number of representative hillslopes per landunit + ! is the total area divided by individual area - ! Calculate steam channel length - ! Total length of stream banks is individual widths - ! times number of hillslopes per landunit divided - ! by 2 to convert from bank length to channel length + do nh = 1, nhillslope + if(hillslope_area(nh) > 0._r8) then + nhill_per_landunit(nh) = grc%area(g)*1.e6_r8*lun%wtgcell(l) & + *pct_hillslope(l,nh)*0.01/hillslope_area(nh) + endif + enddo + + ! Calculate steam channel length + ! Total length of stream banks is individual widths + ! times number of hillslopes per landunit divided + ! by 2 to convert from bank length to channel length - lun%stream_channel_length(l) = 0._r8 - do c = lun%coli(l), lun%colf(l) - if(col%cold(c) == ispval) then - lun%stream_channel_length(l) = lun%stream_channel_length(l) & - + col%hill_width(c) * nhill_per_landunit(col%hillslope_ndx(c)) - endif - enddo - lun%stream_channel_length(l) = 0.5_r8 * lun%stream_channel_length(l) - - do nh = 1, nhillslope - if(hillslope_area(nh) > 0._r8) then - nhill_per_landunit(nh) = grc%area(g)*1.e6_r8*lun%wtgcell(l) & - *pct_hillslope(l,nh)*0.01/hillslope_area(nh) - endif - enddo + lun%stream_channel_length(l) = 0._r8 + do c = lun%coli(l), lun%colf(l) + if(col%cold(c) == ispval) then + lun%stream_channel_length(l) = lun%stream_channel_length(l) & + + col%hill_width(c) * nhill_per_landunit(col%hillslope_ndx(c)) + endif + enddo + lun%stream_channel_length(l) = 0.5_r8 * lun%stream_channel_length(l) + endif ! if missing hillslope information on surface dataset, fill data ! and recalculate hillslope_area @@ -429,33 +437,40 @@ subroutine InitHillslope(bounds,fsurdat) do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6_r8 ! km2 to m2 - col%hill_distance(c) = sqrt(col%hill_area(c)) & - *((c-lun%coli(l))/ncol_per_hillslope(nh)) col%hill_width(c) = sqrt(col%hill_area(c)) - col%hill_elev(c) = col%topo_std(c) & - *((c-lun%coli(l))/ncol_per_hillslope(nh)) col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) col%hill_aspect(c) = (rpi/2.) ! east (arbitrarily chosen) - nh = col%hillslope_ndx(c) - pct_hillslope(l,nh) = 100/nhillslope + if (nh > 0) then + col%hill_elev(c) = col%topo_std(c) & + *((c-lun%coli(l))/ncol_per_hillslope(nh)) + col%hill_distance(c) = sqrt(col%hill_area(c)) & + *((c-lun%coli(l))/ncol_per_hillslope(nh)) + pct_hillslope(l,nh) = 100/nhillslope + else + col%hill_elev(c) = col%topo_std(c) + col%hill_distance(c) = sqrt(col%hill_area(c)) + endif enddo + endif ! Recalculate column weights using input areas check_weight = 0._r8 do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) - if (nh > 0) then + if (col%is_hillslope_column(c)) then col%wtlunit(c) = (col%hill_area(c)/hillslope_area(nh)) & * (pct_hillslope(l,nh)*0.01_r8) else - col%wtlunit(c) = 0._r8 + ! do not reweight if no input hillslope data + !col%wtlunit(c) = 0._r8 endif check_weight = check_weight + col%wtlunit(c) enddo if (abs(1._r8 - check_weight) > 1.e-6_r8) then write(iulog,*) 'col%wtlunit does not sum to 1: ', check_weight write(iulog,*) 'weights: ', col%wtlunit(lun%coli(l):lun%colf(l)) + write(iulog,*) 'location: ',grc%londeg(g),grc%latdeg(g) write(iulog,*) ' ' endif endif @@ -483,8 +498,12 @@ subroutine InitHillslope(bounds,fsurdat) ! this may require modifying subgridMod/natveg_patch_exists ! to ensure patch exists in every gridcell + ! Specify single dominant pft per gridcell call HillslopeDominantPft() - + + ! Specify different pfts for uplands / lowlands + !call HillslopeDominantLowlandPft() + !upland_ivt = 13 ! c3 non-arctic grass !lowland_ivt = 7 ! broadleaf deciduous tree !call HillslopeSetLowlandUplandPfts(lowland_ivt=7,upland_ivt=13) diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 606cc03178..8440d838d8 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -58,7 +58,7 @@ subroutine HydrologyDrainage(bounds, & use clm_varpar , only : nlevgrnd, nlevurb use clm_time_manager , only : get_step_size_real, get_nstep - use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, PerchedLateralFlowHillslope, LateralFlowPowerLaw, LateralFlowHillslope + use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, SubsurfaceLateralFlow use SoilWaterMovementMod , only : use_aquifer_layer use HillslopeHydrologyMod, only : streamflow_manning, HillslopeStreamOutflow, HillslopeUpdateStreamWater @@ -144,42 +144,27 @@ subroutine HydrologyDrainage(bounds, & waterstatebulk_inst, waterfluxbulk_inst) else - if(use_hillslope) then - call PerchedLateralFlowHillslope(bounds, & - num_hydrologyc, filter_hydrologyc, & + call PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst,& + waterstatebulk_inst, waterfluxbulk_inst, & wateratm2lndbulk_inst) - - call LateralFlowHillslope(bounds, & - num_hillslope, filter_hillslopec, & + call SubsurfaceLateralFlow(bounds, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,& soilhydrology_inst, soilstate_inst, & waterstatebulk_inst, waterfluxbulk_inst, & wateratm2lndbulk_inst) + + if(use_hillslope_routing) then + call HillslopeStreamOutflow(bounds,& + waterstatebulk_inst, waterfluxbulk_inst, & + streamflow_method=streamflow_manning) - if(use_hillslope_routing) then - call HillslopeStreamOutflow(bounds,& - waterstatebulk_inst, waterfluxbulk_inst, & - streamflow_method=streamflow_manning) - - call HillslopeUpdateStreamWater(bounds, & - waterstatebulk_inst, waterfluxbulk_inst, & - wateratm2lndbulk_inst) - endif - else - call PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc,& - soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst) - - call LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc,& - soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst) + call HillslopeUpdateStreamWater(bounds, & + waterstatebulk_inst, waterfluxbulk_inst, & + wateratm2lndbulk_inst) endif - + endif do j = 1, nlevgrnd diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index c3a2d147fa..aae64abe89 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -33,6 +33,7 @@ module SoilHydrologyMod use LandunitType , only : lun use ColumnType , only : column_type, col use PatchType , only : patch + use spmdMod , only : masterproc, iam ! ! !PUBLIC TYPES: implicit none @@ -51,10 +52,8 @@ module SoilHydrologyMod public :: CLMVICMap public :: PerchedWaterTable ! Calculate perched water table public :: PerchedLateralFlow ! Calculate lateral flow from perched saturated zone - public :: PerchedLateralFlowHillslope ! Calculate lateral flow from perched saturated zone in hillslope configuration public :: ThetaBasedWaterTable ! Calculate water table from soil moisture state - public :: LateralFlowPowerLaw ! Calculate lateral flow based on power law drainage function - public :: LateralFlowHillslope ! Calculate lateral in multi-column hillslope configuration + public :: SubsurfaceLateralFlow ! Calculate subsurface lateral flow from saturated zone public :: RenewCondensation ! Misc. corrections public :: CalcIrrigWithdrawals ! Calculate irrigation withdrawals from groundwater by layer public :: WithdrawGroundwaterIrrigation ! Remove groundwater irrigation from unconfined and confined aquifers @@ -1634,169 +1633,9 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & end subroutine PerchedWaterTable -!#4 +!#4 !----------------------------------------------------------------------- - subroutine PerchedLateralFlow(bounds, num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc, soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst) - ! - ! !DESCRIPTION: - ! Calculate subsurface drainage from perched saturated zone - ! - ! !USES: - use clm_varcon , only : pondmx, tfrz, watmin,rpi, secspday, nlvic - use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv - - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter - integer , intent(in) :: num_urbanc ! number of column urban points in column filter - integer , intent(in) :: filter_urbanc(:) ! column filter for urban points - integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points - type(soilstate_type) , intent(in) :: soilstate_inst - type(soilhydrology_type) , intent(inout) :: soilhydrology_inst - type(waterstatebulk_type) , intent(inout) :: waterstatebulk_inst - type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst - ! - ! !LOCAL VARIABLES: - character(len=32) :: subname = 'PerchedLateralFlow' ! subroutine name - integer :: c,j,fc,i ! indices - real(r8) :: dtime ! land model time step (sec) - real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) - real(r8) :: wtsub ! summation of hk*dzmm for layers below water table (mm**2/s) - real(r8) :: icefracsum ! summation of icefrac*dzmm of layers below water table (-) - real(r8) :: fracice_rsub(bounds%begc:bounds%endc) ! fractional impermeability of soil layers (-) - real(r8) :: h2osoi_vol - real(r8) :: imped - real(r8) :: drainage_tot - real(r8) :: drainage_layer - real(r8) :: s_y - integer :: k,k_frz,k_perch - real(r8) :: sat_lev - real(r8) :: s1, s2, m, b - real(r8) :: q_perch - real(r8) :: q_perch_max - real(r8) :: vol_ice - !----------------------------------------------------------------------- - - associate( & - z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) - zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) - dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) - bsw => soilstate_inst%bsw_col , & ! Input: [real(r8) (:,:) ] Clapp and Hornberger "b" - hksat => soilstate_inst%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) - sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) - watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) - - icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] fraction of ice in layer - frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) - zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) - zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Input: [real(r8) (:) ] perched water table depth (m) - origflag => soilhydrology_inst%origflag , & ! Input: logical - - qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col , & ! Output: [real(r8) (:) ] perched wt sub-surface runoff (mm H2O /s) - - h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) - h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) - ) - - ! Get time step - - dtime = get_step_size_real() - - ! Compute ice fraction in each layer - - do j = 1,nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - dzmm(c,j) = dz(c,j)*1.e3_r8 - - vol_ice = min(watsat(c,j), h2osoi_ice(c,j)/(dz(c,j)*denice)) - icefrac(c,j) = min(1._r8,vol_ice/watsat(c,j)) - end do - end do - - ! compute drainage from perched saturated region - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - - qflx_drain_perched(c) = 0._r8 - - if ((frost_table(c) > zwt_perched(c)) .and. origflag == 0) then - - ! specify maximum drainage rate - q_perch_max = 1.e-5_r8 * sin(col%topo_slope(c) * (rpi/180._r8)) - - ! calculate frost table and perched water table locations - do k=1, nlevsoi - if (frost_table(c) >= zi(c,k-1) .and. frost_table(c) <= zi(c,k)) then - k_frz=k - exit - endif - enddo - - do k=1, nlevsoi - if (zwt_perched(c) >= zi(c,k-1) .and. zwt_perched(c) <= zi(c,k)) then - k_perch=k - exit - endif - enddo - - wtsub = 0._r8 - q_perch = 0._r8 - do k = k_perch, k_frz - imped=10._r8**(-params_inst%e_ice*(0.5_r8*(icefrac(c,k)+icefrac(c,min(nlevsoi, k+1))))) - q_perch = q_perch + imped*hksat(c,k)*dzmm(c,k) - wtsub = wtsub + dzmm(c,k) - end do - if (wtsub > 0._r8) q_perch = q_perch/wtsub - - qflx_drain_perched(c) = q_perch_max * q_perch & - *(frost_table(c) - zwt_perched(c)) - - ! no perched water table drainage if using original formulation - if(origflag == 1) qflx_drain_perched(c) = 0._r8 - - ! if perched water table exists - if (k_frz > k_perch) then - ! remove drainage from perched saturated layers - drainage_tot = - qflx_drain_perched(c) * dtime - do k = k_perch+1, k_frz - drainage_layer=max(drainage_tot,-(h2osoi_liq(c,k)-watmin)) - drainage_layer=min(drainage_layer,0._r8) - drainage_tot = drainage_tot - drainage_layer - - h2osoi_liq(c,k) = h2osoi_liq(c,k) + drainage_layer - - s_y = watsat(c,k) & - * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,k))**(-1./bsw(c,k))) - s_y=max(s_y, params_inst%aq_sp_yield_min) - if (drainage_tot >= 0.) then - zwt_perched(c) = zwt_perched(c) - drainage_layer/s_y/1000._r8 - exit - else - zwt_perched(c) = zi(c,k) - endif - enddo - - ! if drainage_tot is greater than available water - ! (above frost table), then decrease qflx_drain_perched - ! by residual amount for water balance - qflx_drain_perched(c) = qflx_drain_perched(c) + drainage_tot/dtime - else - qflx_drain_perched(c) = 0._r8 - endif !k_frz > k_perch - endif - enddo - - end associate - - end subroutine PerchedLateralFlow - -!#41 - !----------------------------------------------------------------------- - subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & + subroutine PerchedLateralFlow(bounds, num_hydrologyc, & filter_hydrologyc, soilhydrology_inst, soilstate_inst, & waterstatebulk_inst, waterfluxbulk_inst, wateratm2lndbulk_inst) ! @@ -1904,8 +1743,8 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & qflx_drain_perched_vol(c) = 0._r8 if (frost_table(c) > zwt_perched(c)) then - ! hillslope columns - if (lun%itype(col%landunit(c)) == istsoil) then + ! Hillslope columns + if (col%is_hillslope_column(c)) then ! calculate head gradient @@ -1985,9 +1824,10 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & qflx_drain_perched_out(c) = 1.e3_r8*(qflx_drain_perched_vol(c)/col%hill_area(c)) else - ! non-hillslope columns - ! specify maximum drainage rate - q_perch_max = 1.e-5_r8 * sin(col%topo_slope(c) * (rpi/180._r8)) + ! Non-hillslope columns + ! specify maximum drainage rate + q_perch_max = perched_baseflow_scalar & + * sin(col%topo_slope(c) * (rpi/180._r8)) wtsub = 0._r8 q_perch = 0._r8 @@ -2009,7 +1849,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & c = filter_hydrologyc(fc) ! drainage-out qflx_drain_perched(c) = qflx_drain_perched(c) + qflx_drain_perched_out(c) - if (lun%itype(col%landunit(c)) == istsoil) then + if (col%is_hillslope_column(c)) then ! drainage-in if (col%cold(c) /= ispval) then qflx_drain_perched(col%cold(c)) = & @@ -2029,7 +1869,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & s_y = watsat(c,k) & * ( 1. - (1.+1.e3*zwt_perched(c)/sucsat(c,k))**(-1./bsw(c,k))) - s_y=max(s_y,0.02_r8) + s_y=max(s_y,params_inst%aq_sp_yield_min) if (k== k_perch(c)) then drainage_layer=min(drainage_tot,(s_y*(zi(c,k) - zwt_perched(c))*1.e3)) else @@ -2050,7 +1890,7 @@ subroutine PerchedLateralFlowHillslope(bounds, num_hydrologyc, & end associate - end subroutine PerchedLateralFlowHillslope + end subroutine PerchedLateralFlow !#5 !----------------------------------------------------------------------- @@ -2150,327 +1990,7 @@ end subroutine ThetaBasedWaterTable !#6 !----------------------------------------------------------------------- - subroutine LateralFlowPowerLaw(bounds, num_hydrologyc, filter_hydrologyc, & - num_urbanc, filter_urbanc,soilhydrology_inst, soilstate_inst, & - waterstatebulk_inst, waterfluxbulk_inst) - ! - ! !DESCRIPTION: - ! Calculate subsurface drainage - ! - ! !USES: - use clm_varcon , only : pondmx, watmin,rpi, secspday, nlvic - use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv - use GridcellType , only : grc - - ! - ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter - integer , intent(in) :: num_urbanc ! number of column urban points in column filter - integer , intent(in) :: filter_urbanc(:) ! column filter for urban points - integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points - type(soilstate_type) , intent(in) :: soilstate_inst - type(soilhydrology_type) , intent(inout) :: soilhydrology_inst - type(waterstatebulk_type) , intent(inout) :: waterstatebulk_inst - type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst - ! - ! !LOCAL VARIABLES: - character(len=32) :: subname = 'LateralFlowPowerLaw' ! subroutine name - integer :: c,j,fc,i ! indices - real(r8) :: dtime ! land model time step (sec) - real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) - real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) - integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) - real(r8) :: rsub_top(bounds%begc:bounds%endc) ! subsurface runoff - topographic control (mm/s) - real(r8) :: xsi(bounds%begc:bounds%endc) ! excess soil water above saturation at layer i (mm) - real(r8) :: xsia(bounds%begc:bounds%endc) ! available pore space at layer i (mm) - real(r8) :: xs1(bounds%begc:bounds%endc) ! excess soil water above saturation at layer 1 (mm) - real(r8) :: smpfz(1:nlevsoi) ! matric potential of layer right above water table (mm) - real(r8) :: wtsub ! summation of hk*dzmm for layers below water table (mm**2/s) - real(r8) :: dzsum ! summation of dzmm of layers below water table (mm) - real(r8) :: icefracsum ! summation of icefrac*dzmm of layers below water table (-) - real(r8) :: fracice_rsub(bounds%begc:bounds%endc) ! fractional impermeability of soil layers (-) - real(r8) :: available_h2osoi_liq ! available soil liquid water in a layer - real(r8) :: h2osoi_vol - real(r8) :: imped - real(r8) :: rsub_top_tot - real(r8) :: rsub_top_layer - real(r8) :: theta_unsat - real(r8) :: f_unsat - real(r8) :: s_y - integer :: k - real(r8) :: s1 - real(r8) :: s2 - real(r8) :: m - real(r8) :: b - real(r8) :: vol_ice - real(r8) :: dsmax_tmp(bounds%begc:bounds%endc) ! temporary variable for ARNO subsurface runoff calculation - real(r8) :: rsub_tmp ! temporary variable for ARNO subsurface runoff calculation - real(r8) :: frac ! temporary variable for ARNO subsurface runoff calculation - real(r8) :: rel_moist ! relative moisture, temporary variable - real(r8) :: wtsub_vic ! summation of hk*dzmm for layers in the third VIC layer - integer :: g - !----------------------------------------------------------------------- - - associate( & - nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) - z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) - zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) - dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) - snl => col%snl , & ! Input: [integer (:) ] number of snow layers - h2osfc => waterstatebulk_inst%h2osfc_col , & ! Input: [real(r8) (:) ] surface water (mm) - bsw => soilstate_inst%bsw_col , & ! Input: [real(r8) (:,:) ] Clapp and Hornberger "b" - hksat => soilstate_inst%hksat_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity at saturation (mm H2O /s) - sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) - watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) - eff_porosity => soilstate_inst%eff_porosity_col , & ! Input: [real(r8) (:,:) ] effective porosity = porosity - vol_ice - hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) - - depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth - c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) - Dsmax => soilhydrology_inst%dsmax_col , & ! Input: [real(r8) (:) ] max. velocity of baseflow (mm/day) - max_moist => soilhydrology_inst%max_moist_col , & ! Input: [real(r8) (:,:) ] maximum soil moisture (ice + liq) - moist => soilhydrology_inst%moist_col , & ! Input: [real(r8) (:,:) ] soil layer moisture (mm) - Ds => soilhydrology_inst%ds_col , & ! Input: [real(r8) (:) ] fracton of Dsmax where non-linear baseflow begins - Wsvic => soilhydrology_inst%Wsvic_col , & ! Input: [real(r8) (:) ] fraction of maximum soil moisutre where non-liear base flow occurs - icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] fraction of ice in layer - frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) - zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) - wa => waterstatebulk_inst%wa_col , & ! Input: [real(r8) (:) ] water in the unconfined aquifer (mm) - ice => soilhydrology_inst%ice_col , & ! Input: [real(r8) (:,:) ] soil layer moisture (mm) - qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) - origflag => soilhydrology_inst%origflag , & ! Input: logical - h2osfcflag => soilhydrology_inst%h2osfcflag , & ! Input: integer - - qflx_snwcp_liq => waterfluxbulk_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] - qflx_ice_runoff_xs => waterfluxbulk_inst%qflx_ice_runoff_xs_col , & ! Output: [real(r8) (:) ] solid runoff from excess ice in soil (mm H2O /s) [+] - qflx_liqdew_to_top_layer => waterfluxbulk_inst%qflx_liqdew_to_top_layer_col , & ! Output: [real(r8) (:) ] rate of liquid water deposited on top soil or snow layer (dew) (mm H2O /s) [+] - qflx_soliddew_to_top_layer => waterfluxbulk_inst%qflx_soliddew_to_top_layer_col , & ! Output: [real(r8) (:) ] rate of solid water deposited on top soil or snow layer (frost) (mm H2O /s) [+] - qflx_solidevap_from_top_layer => waterfluxbulk_inst%qflx_solidevap_from_top_layer_col, & ! Output: [real(r8) (:) ] rate of ice evaporated from top soil or snow layer (sublimation) (mm H2O /s) [+] - qflx_drain => waterfluxbulk_inst%qflx_drain_col , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) - qflx_qrgwl => waterfluxbulk_inst%qflx_qrgwl_col , & ! Output: [real(r8) (:) ] qflx_surf at glaciers, wetlands, lakes (mm H2O /s) - qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Output: [real(r8) (:) ] soil saturation excess [mm h2o/s] - h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) - h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col & ! Output: [real(r8) (:,:) ] ice lens (kg/m2) - ) - - ! Get time step - - dtime = get_step_size_real() - - ! Convert layer thicknesses from m to mm - - do j = 1,nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - dzmm(c,j) = dz(c,j)*1.e3_r8 - - vol_ice = min(watsat(c,j), h2osoi_ice(c,j)/(dz(c,j)*denice)) - icefrac(c,j) = min(1._r8,vol_ice/watsat(c,j)) - end do - end do - - ! Initial set - - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - qflx_drain(c) = 0._r8 - qflx_rsub_sat(c) = 0._r8 - rsub_top(c) = 0._r8 - fracice_rsub(c) = 0._r8 - end do - - ! The layer index of the first unsaturated layer, - ! i.e., the layer right above the water table - - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - jwt(c) = nlevsoi - ! allow jwt to equal zero when zwt is in top layer - do j = 1,nlevsoi - if(zwt(c) <= zi(c,j)) then - jwt(c) = j-1 - exit - end if - enddo - end do - - !-- Topographic runoff ------------------------- - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - - dzsum = 0._r8 - icefracsum = 0._r8 - do j = max(jwt(c),1), nlevsoi - dzsum = dzsum + dzmm(c,j) - icefracsum = icefracsum + icefrac(c,j) * dzmm(c,j) - end do - imped=10._r8**(-params_inst%e_ice*(icefracsum/dzsum)) - !@@ - ! baseflow is power law expression relative to bedrock layer - if(zwt(c) <= zi(c,nbedrock(c))) then - rsub_top(c) = imped * baseflow_scalar * tan(rpi/180._r8*col%topo_slope(c))* & - (zi(c,nbedrock(c)) - zwt(c))**(params_inst%n_baseflow) - else - rsub_top(c) = 0._r8 - endif - - !-- Now remove water via rsub_top - rsub_top_tot = - rsub_top(c)* dtime - - !should never be positive... but include for completeness - if(rsub_top_tot > 0.) then !rising water table - - call endrun(subgrid_index=c, subgrid_level=subgrid_level_column, & - msg="RSUB_TOP IS POSITIVE in Drainage!"//errmsg(sourcefile, __LINE__)) - - else ! deepening water table - do j = jwt(c)+1, nbedrock(c) - ! use analytical expression for specific yield - s_y = watsat(c,j) & - * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) - s_y=max(s_y, params_inst%aq_sp_yield_min) - rsub_top_layer=max(rsub_top_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) - rsub_top_layer=min(rsub_top_layer,0._r8) - h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer - - rsub_top_tot = rsub_top_tot - rsub_top_layer - - if (rsub_top_tot >= 0.) then - zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 - - exit - else - zwt(c) = zi(c,j) - endif - enddo - - !-- remove residual rsub_top -------------------------------- - ! make sure no extra water removed from soil column - rsub_top(c) = rsub_top(c) - rsub_top_tot/dtime - endif - - zwt(c) = max(0.0_r8,zwt(c)) - zwt(c) = min(80._r8,zwt(c)) - end do - - ! excessive water above saturation added to the above unsaturated layer like a bucket - ! if column fully saturated, excess water goes to runoff - - do j = nlevsoi,2,-1 - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - xsi(c) = max(h2osoi_liq(c,j)-eff_porosity(c,j)*dzmm(c,j),0._r8) - h2osoi_liq(c,j) = min(eff_porosity(c,j)*dzmm(c,j), h2osoi_liq(c,j)) - h2osoi_liq(c,j-1) = h2osoi_liq(c,j-1) + xsi(c) - end do - end do - - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - - ! watmin addition to fix water balance errors - xs1(c) = max(max(h2osoi_liq(c,1)-watmin,0._r8)- & - max(0._r8,(pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_ice(c,1)-watmin)),0._r8) - h2osoi_liq(c,1) = h2osoi_liq(c,1) - xs1(c) - - if (lun%urbpoi(col%landunit(c))) then - qflx_rsub_sat(c) = xs1(c) / dtime - else - ! send this water up to h2osfc rather than sending to drainage - h2osfc(c) = h2osfc(c) + xs1(c) - qflx_rsub_sat(c) = 0._r8 - endif - ! add in ice check - xs1(c) = max(max(h2osoi_ice(c,1),0._r8)-max(0._r8,(pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_liq(c,1))),0._r8) - h2osoi_ice(c,1) = min(max(0._r8,pondmx+watsat(c,1)*dzmm(c,1)-h2osoi_liq(c,1)), h2osoi_ice(c,1)) - qflx_ice_runoff_xs(c) = xs1(c) / dtime - end do - - ! Limit h2osoi_liq to be greater than or equal to watmin. - ! Get water needed to bring h2osoi_liq equal watmin from lower layer. - ! If insufficient water in soil layers, get from aquifer water - - do j = 1, nlevsoi-1 - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (h2osoi_liq(c,j) < watmin) then - xs(c) = watmin - h2osoi_liq(c,j) - ! deepen water table if water is passed from below zwt layer - if(j == jwt(c)) then - zwt(c) = zwt(c) + xs(c)/eff_porosity(c,j)/1000._r8 - endif - else - xs(c) = 0._r8 - end if - h2osoi_liq(c,j ) = h2osoi_liq(c,j ) + xs(c) - h2osoi_liq(c,j+1) = h2osoi_liq(c,j+1) - xs(c) - end do - end do - - ! Get water for bottom layer from layers above if possible - j = nlevsoi - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - if (h2osoi_liq(c,j) < watmin) then - xs(c) = watmin-h2osoi_liq(c,j) - searchforwater: do i = nlevsoi-1, 1, -1 - available_h2osoi_liq = max(h2osoi_liq(c,i)-watmin-xs(c),0._r8) - if (available_h2osoi_liq >= xs(c)) then - h2osoi_liq(c,j) = h2osoi_liq(c,j) + xs(c) - h2osoi_liq(c,i) = h2osoi_liq(c,i) - xs(c) - xs(c) = 0._r8 - exit searchforwater - else - h2osoi_liq(c,j) = h2osoi_liq(c,j) + available_h2osoi_liq - h2osoi_liq(c,i) = h2osoi_liq(c,i) - available_h2osoi_liq - xs(c) = xs(c) - available_h2osoi_liq - end if - end do searchforwater - else - xs(c) = 0._r8 - end if - ! Needed in case there is no water to be found - h2osoi_liq(c,j) = h2osoi_liq(c,j) + xs(c) - ! Instead of removing water from aquifer where it eventually - ! shows up as excess drainage to the ocean, take it back out of - ! drainage - qflx_rsub_sat(c) = qflx_rsub_sat(c) - xs(c)/dtime - - end do - - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - - ! Sub-surface runoff and drainage - - qflx_drain(c) = qflx_rsub_sat(c) + rsub_top(c) - - ! Set imbalance for snow capping - - qflx_qrgwl(c) = qflx_snwcp_liq(c) - - end do - - ! No drainage for urban columns (except for pervious road as computed above) - - do fc = 1, num_urbanc - c = filter_urbanc(fc) - if (col%itype(c) /= icol_road_perv) then - qflx_drain(c) = 0._r8 - ! This must be done for roofs and impervious road (walls will be zero) - qflx_qrgwl(c) = qflx_snwcp_liq(c) - end if - end do - - end associate - - end subroutine LateralFlowPowerLaw - -!#61 - !----------------------------------------------------------------------- - subroutine LateralFlowHillslope(bounds, & - num_hillslope, filter_hillslopec, & + subroutine SubsurfaceLateralFlow(bounds, & num_hydrologyc, filter_hydrologyc, & num_urbanc, filter_urbanc,soilhydrology_inst, soilstate_inst, & waterstatebulk_inst, waterfluxbulk_inst, wateratm2lndbulk_inst) @@ -2501,19 +2021,16 @@ subroutine LateralFlowHillslope(bounds, & type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst - integer , intent(in) :: num_hillslope ! number of hillslope soil cols - integer , intent(in) :: filter_hillslopec(:) ! column filter for designating all hillslope cols. ! ! !LOCAL VARIABLES: - character(len=32) :: subname = 'LateralFlowHillslope' ! subroutine name + character(len=32) :: subname = 'SubsurfaceLateralFlow' ! subroutine name integer :: c,j,fc,i ! indices real(r8) :: dtime ! land model time step (sec) real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) real(r8) :: rsub_top(bounds%begc:bounds%endc) ! subsurface runoff - topographic control (mm/s) - real(r8) :: fff(bounds%begc:bounds%endc) ! decay factor (m-1) real(r8) :: xsi(bounds%begc:bounds%endc) ! excess soil water above saturation at layer i (mm) real(r8) :: xsia(bounds%begc:bounds%endc) ! available pore space at layer i (mm) real(r8) :: xs1(bounds%begc:bounds%endc) ! excess soil water above saturation at layer 1 (mm) @@ -2591,14 +2108,8 @@ subroutine LateralFlowHillslope(bounds, & Ds => soilhydrology_inst%ds_col , & ! Input: [real(r8) (:) ] fracton of Dsmax where non-linear baseflow begins Wsvic => soilhydrology_inst%Wsvic_col , & ! Input: [real(r8) (:) ] fraction of maximum soil moisutre where non-liear base flow occurs icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] fraction of ice in layer - hkdepth => soilhydrology_inst%hkdepth_col , & ! Input: [real(r8) (:) ] decay factor (m) frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) - wa => waterstatebulk_inst%wa_col , & ! Input: [real(r8) (:) ] water in the unconfined aquifer (mm) - ice => soilhydrology_inst%ice_col , & ! Input: [real(r8) (:,:) ] soil layer moisture (mm) - qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) - origflag => soilhydrology_inst%origflag , & ! Input: logical - h2osfcflag => soilhydrology_inst%h2osfcflag , & ! Input: logical stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) qflx_snwcp_liq => waterfluxbulk_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] @@ -2635,7 +2146,6 @@ subroutine LateralFlowHillslope(bounds, & qflx_drain(c) = 0._r8 qflx_rsub_sat(c) = 0._r8 rsub_top(c) = 0._r8 - qflx_latflow_in(c) = 0._r8 qflx_latflow_out(c) = 0._r8 qflx_net_latflow(c) = 0._r8 @@ -2667,122 +2177,137 @@ subroutine LateralFlowHillslope(bounds, & dzsum = dzsum + dzmm(c,j) icefracsum = icefracsum + icefrac(c,j) * dzmm(c,j) end do - ice_imped_col(c)=10._r8**(-params_inst%e_ice*(icefracsum/dzsum)) + ice_imped_col(c)=10._r8**(-params_inst%e_ice*(icefracsum/dzsum)) enddo - - do fc = 1, num_hillslope - c = filter_hillslopec(fc) + + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) l = col%landunit(c) g = col%gridcell(c) - - ! kinematic wave approximation - if (baseflow_method == 'kinematic') then - dgrad = col%hill_slope(c) - endif + ! Hillslope columns + if (col%is_hillslope_column(c)) then - ! darcy's law - if (baseflow_method == 'darcy') then - if (col%cold(c) /= ispval) then - dgrad = (col%hill_elev(c)-zwt(c)) & - - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) - dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) - else - if(use_hillslope_routing) then - stream_water_depth = stream_water_volume(l) & - /lun%stream_channel_length(l)/lun%stream_channel_width(l) - stream_channel_depth = lun%stream_channel_depth(l) + ! kinematic wave approximation + if (baseflow_method == 'kinematic') then + dgrad = col%hill_slope(c) + endif + + ! darcy's law + if (baseflow_method == 'darcy') then + if (col%cold(c) /= ispval) then + dgrad = (col%hill_elev(c)-zwt(c)) & + - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) + dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else - stream_water_depth = tdepth(g) - stream_channel_depth = tdepth_bankfull(g) - endif - - ! flow between channel and lowest column - ! bankfull height is defined to be zero - dgrad = (col%hill_elev(c)-zwt(c)) & - ! ignore overbankfull storage - - min((stream_water_depth - stream_channel_depth),0._r8) - - dgrad = dgrad / (col%hill_distance(c)) - ! dgrad cannot be negative when channel is empty - if (stream_water_depth <= 0._r8) then - dgrad = max(dgrad, 0._r8) - endif - ! add vertical drainage for losing streams - ! (this could be a separate term from lateral flow...) - if (dgrad < 0._r8) then - ! dgrad = dgrad - 1._r8 - ! adjust lateral gradient w/ k_anisotropic - dgrad = dgrad - 1._r8/k_anisotropic + if(use_hillslope_routing) then + stream_water_depth = stream_water_volume(l) & + /lun%stream_channel_length(l)/lun%stream_channel_width(l) + stream_channel_depth = lun%stream_channel_depth(l) + else + stream_water_depth = tdepth(g) + stream_channel_depth = tdepth_bankfull(g) + endif + + ! flow between channel and lowest column + ! bankfull height is defined to be zero + dgrad = (col%hill_elev(c)-zwt(c)) & + ! ignore overbankfull storage + - min((stream_water_depth - stream_channel_depth),0._r8) + + dgrad = dgrad / (col%hill_distance(c)) + ! dgrad cannot be negative when channel is empty + if (stream_water_depth <= 0._r8) then + dgrad = max(dgrad, 0._r8) + endif + ! add vertical drainage for losing streams + ! (this could be a separate term from lateral flow...) + if (dgrad < 0._r8) then + ! dgrad = dgrad - 1._r8 + ! adjust lateral gradient w/ k_anisotropic + dgrad = dgrad - 1._r8/k_anisotropic + endif endif + end if + + ! Calculate transmissivity of source column + if (dgrad >= 0._r8) then + c_src = c + else + c_src = col%cold(c) endif - end if - - ! Calculate transmissivity of source column - if (dgrad >= 0._r8) then - c_src = c - else - c_src = col%cold(c) - endif - - transmis = 0._r8 - if(c_src /= ispval) then - ! transmissivity non-zero only when saturated conditions exist - if(zwt(c_src) <= zi(c_src,nbedrock(c_src))) then - ! sum of layer transmissivities - if (transmissivity_method == 'layersum') then - do j = jwt(c_src)+1, nbedrock(c_src) - if(j == jwt(c_src)+1) then - transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*(zi(c_src,j) - zwt(c_src)) - else - transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*dz(c_src,j) - endif - end do - endif - ! constant conductivity based on shallowest saturated layer hk - if (transmissivity_method == 'constant') then - transmis = (1.e-3_r8*ice_imped(c_src,jwt(c_src)+1)*hksat(c_src,jwt(c_src)+1)) & - *(zi(c_src,nbedrock(c_src)) - zwt(c_src) ) - endif - ! power law profile based on shallowest saturated layer hk - if (transmissivity_method == 'power') then - ! transmis = ice_imped(c_src,jwt(c_src)+1)*hksat(c_src,jwt(c_src)+1)*0.001_r8*dzsumall* & - ! ((1-1000._r8*zwt(c_src)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) + + transmis = 0._r8 + if(c_src /= ispval) then + ! transmissivity non-zero only when saturated conditions exist + if(zwt(c_src) <= zi(c_src,nbedrock(c_src))) then + ! sum of layer transmissivities + if (transmissivity_method == 'layersum') then + do j = jwt(c_src)+1, nbedrock(c_src) + if(j == jwt(c_src)+1) then + transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*(zi(c_src,j) - zwt(c_src)) + else + transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*dz(c_src,j) + endif + end do + endif + ! constant conductivity based on shallowest saturated layer hk + if (transmissivity_method == 'constant') then + transmis = (1.e-3_r8*ice_imped(c_src,jwt(c_src)+1)*hksat(c_src,jwt(c_src)+1)) & + *(zi(c_src,nbedrock(c_src)) - zwt(c_src) ) + endif + ! power law profile based on shallowest saturated layer hk + if (transmissivity_method == 'power') then + ! transmis = ice_imped(c_src,jwt(c_src)+1)*hksat(c_src,jwt(c_src)+1)*0.001_r8*dzsumall* & + ! ((1-1000._r8*zwt(c_src)/dzsumall)**n_baseflow )/n_baseflow ! (m2/s) + endif endif + else + ! transmissivity of losing stream (c_src == ispval) + transmis = (1.e-3_r8*ice_imped(c,jwt(c)+1)*hksat(c,jwt(c)+1))*stream_water_depth + endif + ! adjust transmissivity by 'anisotropy factor' + transmis = k_anisotropic*transmis + + ! the qflx_latflow_out_vol calculations use the + ! transmissivity to determine whether saturated flow + ! conditions exist, b/c gradients will be nonzero + ! even when no saturated layers are present + ! qflx_latflow_out_vol(c) = ice_imped(c)*transmis*col%hill_width(c)*dgrad + ! include ice impedance in transmissivity + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad + + ! qdischarge from lowest column is qflx_latflow_out_vol + ! scaled by total area of column in gridcell divided by column area + if (col%cold(c) == ispval) then + qdischarge(c) = qflx_latflow_out_vol(c) & + *(grc%area(g)*1.e6_r8*col%wtgcell(c)/col%hill_area(c)) endif - else - ! transmissivity of losing stream (c_src == ispval) - transmis = (1.e-3_r8*ice_imped(c,jwt(c)+1)*hksat(c,jwt(c)+1))*stream_water_depth - endif - ! adjust transmissivity by 'anisotropy factor' - transmis = k_anisotropic*transmis - - ! the qflx_latflow_out_vol calculations use the - ! transmissivity to determine whether saturated flow - ! conditions exist, b/c gradients will be nonzero - ! even when no saturated layers are present - ! qflx_latflow_out_vol(c) = ice_imped(c)*transmis*col%hill_width(c)*dgrad - ! include ice impedance in transmissivity - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad - - ! qdischarge from lowest column is qflx_latflow_out_vol - ! scaled by total area of column in gridcell divided by column area - if (col%cold(c) == ispval) then - qdischarge(c) = qflx_latflow_out_vol(c) & - *(grc%area(g)*1.e6_r8*col%wtgcell(c)/col%hill_area(c)) - endif - ! convert volumetric flow to equivalent flux - qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) - - ! hilltop column has no inflow - if (col%colu(c) == ispval) then - qflx_latflow_in(c) = 0._r8 - endif - - ! current outflow is inflow to downhill column normalized by downhill area - if (col%cold(c) /= ispval) then - qflx_latflow_in(col%cold(c)) = qflx_latflow_in(col%cold(c)) + & - 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) + ! convert volumetric flow to equivalent flux + qflx_latflow_out(c) = 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(c) + + ! hilltop column has no inflow + if (col%colu(c) == ispval) then + qflx_latflow_in(c) = 0._r8 + endif + + ! current outflow is inflow to downhill column normalized by downhill area + if (col%cold(c) /= ispval) then + qflx_latflow_in(col%cold(c)) = qflx_latflow_in(col%cold(c)) + & + 1.e3_r8*qflx_latflow_out_vol(c)/col%hill_area(col%cold(c)) + endif + + else + ! Non-hillslope columns + ! baseflow is power law expression relative to bedrock layer + if(zwt(c) <= zi(c,nbedrock(c))) then + qflx_latflow_out(c) = ice_imped_col(c) * baseflow_scalar & + * tan(rpi/180._r8*col%topo_slope(c))* & + (zi(c,nbedrock(c)) - zwt(c))**(params_inst%n_baseflow) + endif + ! convert flux to volumetric flow + qflx_latflow_out_vol(c) = 1.e-3_r8*qflx_latflow_out(c)*(grc%area(g)*1.e6_r8*col%wtgcell(c)) + qdischarge(c) = qflx_latflow_out_vol(c) endif enddo @@ -2793,20 +2318,24 @@ subroutine LateralFlowHillslope(bounds, & endif do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - l = col%landunit(c) - !need to sum all columns w/ same hillslope id for each column - qflx_latflow_avg(c) = 0._r8 - larea = 0._r8 - do c0 = lun%coli(l), lun%colf(l) - if(col%hillslope_ndx(c0) == col%hillslope_ndx(c)) then - qflx_latflow_avg(c) = qflx_latflow_avg(c) + qflx_latflow_out_vol(c0) - larea = larea + col%hill_area(c0) - endif - enddo - qflx_latflow_avg(c) = 1.e3_r8*qflx_latflow_avg(c)/larea + if (col%is_hillslope_column(c)) then + l = col%landunit(c) + !need to sum all columns w/ same hillslope id for each column + qflx_latflow_avg(c) = 0._r8 + larea = 0._r8 + do c0 = lun%coli(l), lun%colf(l) + if(col%hillslope_ndx(c0) == col%hillslope_ndx(c)) then + qflx_latflow_avg(c) = qflx_latflow_avg(c) + qflx_latflow_out_vol(c0) + larea = larea + col%hill_area(c0) + endif + enddo + qflx_latflow_avg(c) = 1.e3_r8*qflx_latflow_avg(c)/larea + else + qflx_latflow_avg(c) = qflx_latflow_out(c) + endif enddo endif - + !-- Topographic runoff ------------------------- do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) @@ -2817,18 +2346,11 @@ subroutine LateralFlowHillslope(bounds, & qflx_net_latflow(c) = qflx_latflow_avg(c) endif - fff(c) = 1._r8/ hkdepth(c) !@@ ! baseflow if(zwt(c) <= zi(c,nbedrock(c))) then - if (lun%itype(col%landunit(c)) == istsoil) then - ! apply net lateral flow here - rsub_top(c) = qflx_net_latflow(c) - else - rsub_top(c) = ice_imped_col(c) * baseflow_scalar & - * tan(rpi/180._r8*col%topo_slope(c))* & - (zi(c,nbedrock(c)) - zwt(c))**(n_baseflow) - endif + ! apply net lateral flow here + rsub_top(c) = qflx_net_latflow(c) else rsub_top(c) = 0._r8 endif @@ -2841,7 +2363,7 @@ subroutine LateralFlowHillslope(bounds, & ! analytical expression for specific yield s_y = watsat(c,j) & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) - s_y=max(s_y,0.02_r8) + s_y=max(s_y,params_inst%aq_sp_yield_min) rsub_top_layer=min(rsub_top_tot,(s_y*dz(c,j)*1.e3)) @@ -2867,7 +2389,7 @@ subroutine LateralFlowHillslope(bounds, & ! analytical expression for specific yield s_y = watsat(c,j) & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) - s_y=max(s_y,0.02_r8) + s_y=max(s_y,params_inst%aq_sp_yield_min) rsub_top_layer=max(rsub_top_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) rsub_top_layer=min(rsub_top_layer,0._r8) @@ -2883,7 +2405,7 @@ subroutine LateralFlowHillslope(bounds, & endif enddo - !-- remove residual rsub_top --------------------------------------------- + !-- remove residual rsub_top ----------------------- ! make sure no extra water removed from soil column rsub_top(c) = rsub_top(c) + rsub_top_tot/dtime endif @@ -3004,7 +2526,7 @@ subroutine LateralFlowHillslope(bounds, & end associate - end subroutine LateralFlowHillslope + end subroutine SubsurfaceLateralFlow !#7 !----------------------------------------------------------------------- diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index ea8259923e..8e03525791 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -402,6 +402,7 @@ subroutine InitHistory(this, bounds) ! ! !USES: use histFileMod , only : hist_addfld1d, hist_addfld2d, no_snow_normal + use clm_varctl , only : use_hillslope, use_hillslope_routing ! ! !ARGUMENTS: class(waterflux_type), intent(in) :: this @@ -500,30 +501,34 @@ subroutine InitHistory(this, bounds) long_name=this%info%lname('sub-surface drainage'), & ptr_col=this%qflx_drain_col, c2l_scale_type='urbanf') - this%qflx_latflow_out_col(begc:endc) = spval - call hist_addfld1d ( & - fname=this%info%fname('QLATFLOWOUT'), & - units='mm/s', & - avgflag='A', & - long_name=this%info%lname('hillcol lateral outflow'), & - ptr_col=this%qflx_latflow_out_col, c2l_scale_type='urbanf') - - this%qdischarge_col(begc:endc) = spval - call hist_addfld1d ( & - fname=this%info%fname('QDISCHARGE'), & - units='m3/s', & - avgflag='A', & - long_name=this%info%lname('hillslope discharge from column'), & - ptr_col=this%qdischarge_col, c2l_scale_type='urbanf') - - this%qstreamflow_lun(begl:endl) = spval - call hist_addfld1d ( & - fname=this%info%fname('QSTREAMFLOW'), & - units='m3/s', & - avgflag='A', & - long_name=this%info%lname('streamflow discharge'), & - l2g_scale_type='veg', & - ptr_lunit=this%qstreamflow_lun) + if (use_hillslope) then + this%qflx_latflow_out_col(begc:endc) = spval + call hist_addfld1d ( & + fname=this%info%fname('QLATFLOWOUT'), & + units='mm/s', & + avgflag='A', & + long_name=this%info%lname('hillcol lateral outflow'), & + ptr_col=this%qflx_latflow_out_col, c2l_scale_type='urbanf') + + this%qdischarge_col(begc:endc) = spval + call hist_addfld1d ( & + fname=this%info%fname('QDISCHARGE'), & + units='m3/s', & + avgflag='A', & + long_name=this%info%lname('hillslope discharge from column'), & + ptr_col=this%qdischarge_col, c2l_scale_type='urbanf') + + if (use_hillslope_routing) then + this%qstreamflow_lun(begl:endl) = spval + call hist_addfld1d ( & + fname=this%info%fname('QSTREAMFLOW'), & + units='m3/s', & + avgflag='A', & + long_name=this%info%lname('streamflow discharge'), & + l2g_scale_type='veg', & + ptr_lunit=this%qstreamflow_lun) + endif + endif this%qflx_drain_perched_col(begc:endc) = spval call hist_addfld1d ( & @@ -852,6 +857,7 @@ subroutine InitCold(this, bounds) ! ! !USES: use landunit_varcon, only : istsoil, istcrop + use clm_varctl , only : use_hillslope_routing ! ! !ARGUMENTS: class(waterflux_type), intent(in) :: this @@ -908,11 +914,13 @@ subroutine InitCold(this, bounds) this%qdischarge_col(c) = 0._r8 end if end do - do l = bounds%begl, bounds%endl - if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then - this%qstreamflow_lun(l) = 0._r8 - end if - end do + if (use_hillslope_routing) then + do l = bounds%begl, bounds%endl + if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then + this%qstreamflow_lun(l) = 0._r8 + end if + end do + endif end subroutine InitCold diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 736aa161e8..819d0fe79f 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -82,6 +82,7 @@ module ColumnType real(r8), pointer :: hill_aspect (:) ! azimuth angle of column wrt to north, positive to east (radians) ! other column characteristics + logical , pointer :: is_hillslope_column(:) ! true if this column is a hillslope element logical , pointer :: hydrologically_active(:) ! true if this column is a hydrologically active type logical , pointer :: urbpoi (:) ! true=>urban point @@ -158,6 +159,7 @@ subroutine Init(this, begc, endc) allocate(this%micro_sigma (begc:endc)) ; this%micro_sigma (:) = nan allocate(this%topo_slope (begc:endc)) ; this%topo_slope (:) = nan allocate(this%topo_std (begc:endc)) ; this%topo_std (:) = nan + allocate(this%is_hillslope_column(begc:endc)) ; this%is_hillslope_column(:) = .false. allocate(this%hydrologically_active(begc:endc)) ; this%hydrologically_active(:) = .false. allocate(this%urbpoi (begc:endc)) ; this%urbpoi (:) = .false. @@ -195,6 +197,7 @@ subroutine Clean(this) deallocate(this%topo_std ) deallocate(this%nbedrock ) deallocate(this%levgrnd_class) + deallocate(this%is_hillslope_column) deallocate(this%hydrologically_active) deallocate(this%col_ndx ) deallocate(this%colu ) From f64b69e822c3a6278a849f39e67e5d346a38ec0f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 16 Nov 2021 11:03:49 -0700 Subject: [PATCH 056/153] fix typo --- src/biogeophys/SoilHydrologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index aae64abe89..e2fc6c1805 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1826,7 +1826,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & else ! Non-hillslope columns ! specify maximum drainage rate - q_perch_max = perched_baseflow_scalar & + q_perch_max = params_inst%perched_baseflow_scalar & * sin(col%topo_slope(c) * (rpi/180._r8)) wtsub = 0._r8 From 0f57012033c037e3ef47325a1ac0987906d5da8d Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 3 Dec 2021 10:11:07 -0700 Subject: [PATCH 057/153] move InitHillslope before SoilStateInitTimeConst --- src/main/clm_instMod.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 5da3b7b030..511937ae7f 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -295,6 +295,10 @@ subroutine clm_instInit(bounds) call canopystate_inst%Init(bounds) + if(use_hillslope) then + call InitHillslope(bounds, fsurdat) + endif + call soilstate_inst%Init(bounds) call SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) ! sets hydraulic and thermal soil properties @@ -332,10 +336,6 @@ subroutine clm_instInit(bounds) call saturated_excess_runoff_inst%Init(bounds) call infiltration_excess_runoff_inst%Init(bounds) - if(use_hillslope) then - call InitHillslope(bounds, fsurdat) - endif - call solarabs_inst%Init(bounds) call surfalb_inst%Init(bounds) From 73095584e1a8636a4db3e8a512e9bd8e058e78ed Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 8 Dec 2021 07:52:26 -0700 Subject: [PATCH 058/153] add downscaling flag to SurfaceAlbedoMod --- src/biogeophys/SurfaceAlbedoMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/SurfaceAlbedoMod.F90 b/src/biogeophys/SurfaceAlbedoMod.F90 index 987900483a..12b42d3688 100644 --- a/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/src/biogeophys/SurfaceAlbedoMod.F90 @@ -262,7 +262,7 @@ subroutine SurfaceAlbedo(bounds,nc, & use clm_varctl , only : use_subgrid_fluxes, use_snicar_frc, use_fates use CLMFatesInterfaceMod, only : hlm_fates_interface_type use landunit_varcon , only : istsoil - use clm_varctl , only : use_hillslope + use clm_varctl , only : use_hillslope,downscale_hillslope_meteorology ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! bounds @@ -420,7 +420,7 @@ subroutine SurfaceAlbedo(bounds,nc, & do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (use_hillslope .and. lun%itype(col%landunit(c)) == istsoil) then + if (use_hillslope .and. downscale_hillslope_meteorology .and. lun%itype(col%landunit(c)) == istsoil) then ! calculate local incidence angle based on column slope and aspect zenith_angle = acos(coszen_grc(g)) From 7bd8c92221bffc3aad26e23406bc5c21b09e80bb Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 6 Jan 2022 07:58:22 -0700 Subject: [PATCH 059/153] add coszen_grc restart field --- src/biogeophys/SurfaceAlbedoType.F90 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/biogeophys/SurfaceAlbedoType.F90 b/src/biogeophys/SurfaceAlbedoType.F90 index 22df81c20c..05cec3ae1a 100644 --- a/src/biogeophys/SurfaceAlbedoType.F90 +++ b/src/biogeophys/SurfaceAlbedoType.F90 @@ -327,6 +327,11 @@ subroutine Restart(this, bounds, ncid, flag, & begp = bounds%begp; endp = bounds%endp begc = bounds%begc; endc = bounds%endc + call restartvar(ncid=ncid, flag=flag, varname='coszen_grc', xtype=ncd_double, & + dim1name='gridcell', & + long_name='cosine of solar zenith angle', units='unitless', & + interpinic_flag='interp', readvar=readvar, data=this%coszen_grc) + call restartvar(ncid=ncid, flag=flag, varname='coszen', xtype=ncd_double, & dim1name='column', & long_name='cosine of solar zenith angle', units='unitless', & From d655c0c49369b81364b284ada7b6ca852c04ea04 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 15 Apr 2022 08:57:41 -0600 Subject: [PATCH 060/153] fix hillslope routing water balance --- src/biogeophys/BalanceCheckMod.F90 | 18 +- src/biogeophys/HillslopeHydrologyMod.F90 | 165 +++++++------ src/biogeophys/SoilHydrologyMod.F90 | 147 ++++++++---- src/biogeophys/SurfaceAlbedoMod.F90 | 8 +- src/cpl/nuopc/lnd_import_export.F90 | 6 +- src/main/LandunitType.F90 | 3 + src/main/TopoMod.F90 | 18 +- src/main/atm2lndMod.F90 | 16 +- src/main/lnd2atmMod.F90 | 82 ++++--- src/main/subgridAveMod.F90 | 286 +++++++++-------------- 10 files changed, 387 insertions(+), 362 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 777b4de322..93772fcc9d 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -559,6 +559,7 @@ subroutine BalanceCheck( bounds, & qflx_qrgwl_grc => waterlnd2atm_inst%qflx_rofliq_qgwl_grc , & ! Input: [real(r8) (:) ] grid cell-level qflx_surf at glaciers, wetlands, lakes qflx_drain_col => waterflux_inst%qflx_drain_col , & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) qflx_drain_grc => waterlnd2atm_inst%qflx_rofliq_qsub_grc , & ! Input: [real(r8) (:) ] grid cell-level drainage (mm H20 /s) + qflx_streamflow_grc => waterlnd2atm_inst%qflx_rofliq_stream_grc, & ! Input: [real(r8) (:) ] streamflow [mm H2O/s] qflx_ice_runoff_col => waterlnd2atm_inst%qflx_ice_runoff_col , & ! Input: [real(r8) (:) ] column level solid runoff from snow capping and from excess ice in soil (mm H2O /s) qflx_ice_runoff_grc => waterlnd2atm_inst%qflx_rofice_grc , & ! Input: [real(r8) (:) ] grid cell-level solid runoff from snow capping and from excess ice in soil (mm H2O /s) qflx_sl_top_soil => waterflux_inst%qflx_sl_top_soil_col , & ! Input: [real(r8) (:) ] liquid water + ice from layer above soil to top soil layer or sent to qflx_qrgwl (mm H2O/s) @@ -738,18 +739,10 @@ subroutine BalanceCheck( bounds, & ! add landunit level flux variable, convert from (m3/s) to (kg m-2 s-1) if (use_hillslope_routing) then - do l = bounds%begl, bounds%endl - g = lun%gridcell(l) - ! input water flux to stream channel (-) + ! output water flux from streamflow (+) + do g = bounds%begg, bounds%endg errh2o_grc(g) = errh2o_grc(g) & - - (qflx_surf_grc(g) & - + qflx_drain_grc(g) & - + qflx_drain_perched_grc(g)) * dtime - - ! output water flux from streamflow (+) - errh2o_grc(g) = errh2o_grc(g) & - + waterflux_inst%qstreamflow_lun(l) & - *1e3_r8/(grc%area(g)*1.e6_r8) * dtime + + qflx_streamflow_grc(g) * dtime enddo endif @@ -912,8 +905,7 @@ subroutine BalanceCheck( bounds, & ! in the urban radiation module if (.not. lun%urbpoi(l)) then ! patch radiation will no longer balance gridcell values -!scs: should add a check that columns add to gridcell - if(use_hillslope .and. lun%itype(l) == istsoil) then + if(col%is_hillslope_column(c)) then errsol(p) = fsa(p) + fsr(p) & - (forc_solad_col(c,1) + forc_solad_col(c,2) + forc_solai(g,1) + forc_solai(g,2)) else diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 534ad7dd8e..c94506160a 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -295,6 +295,10 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) lun%stream_channel_depth(l) = fstream_in(g) enddo + else + if (masterproc) then + call endrun( 'ERROR:: h_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if endif call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then @@ -305,6 +309,10 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) lun%stream_channel_width(l) = fstream_in(g) enddo + else + if (masterproc) then + call endrun( 'ERROR:: h_stream_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if end if call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then @@ -315,6 +323,10 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) lun%stream_channel_slope(l) = fstream_in(g) enddo + else + if (masterproc) then + call endrun( 'ERROR:: h_stream_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if end if deallocate(fstream_in) @@ -408,11 +420,15 @@ subroutine InitHillslope(bounds,fsurdat) ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 ! Number of representative hillslopes per landunit ! is the total area divided by individual area - + + lun%stream_channel_number(l) = 0._r8 do nh = 1, nhillslope if(hillslope_area(nh) > 0._r8) then nhill_per_landunit(nh) = grc%area(g)*1.e6_r8*lun%wtgcell(l) & *pct_hillslope(l,nh)*0.01/hillslope_area(nh) + + lun%stream_channel_number(l) = lun%stream_channel_number(l) & + + nhill_per_landunit(nh) endif enddo @@ -566,10 +582,10 @@ subroutine HillslopeSoilThicknessProfile(bounds,& endif do l = bounds%begl,bounds%endl - if(lun%itype(l) == istsoil) then - ! Specify lowland/upland soil thicknesses separately - if(soil_profile_method == soil_profile_set_lowland_upland) then - do c = lun%coli(l), lun%colf(l) + ! Specify lowland/upland soil thicknesses separately + if(soil_profile_method == soil_profile_set_lowland_upland) then + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c)) then if(col%cold(c) /= ispval) then do j = 1,nlevsoi if(zisoi(j-1) > zmin_bedrock) then @@ -587,19 +603,21 @@ subroutine HillslopeSoilThicknessProfile(bounds,& end if enddo endif - end do - endif + endif + end do + endif - ! Linear soil thickness profile - if(soil_profile_method == soil_profile_linear) then - - min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) - max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) - m = (soil_depth_lowland - soil_depth_upland)/ & - (max_hill_dist - min_hill_dist) - b = soil_depth_upland - - do c = lun%coli(l), lun%colf(l) + ! Linear soil thickness profile + if(soil_profile_method == soil_profile_linear) then + + min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) + max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) + m = (soil_depth_lowland - soil_depth_upland)/ & + (max_hill_dist - min_hill_dist) + b = soil_depth_upland + + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c)) then soil_depth_col = m*(max_hill_dist - col%hill_distance(c)) + b do j = 1,nlevsoi @@ -607,10 +625,9 @@ subroutine HillslopeSoilThicknessProfile(bounds,& col%nbedrock(c) = j end if enddo - enddo - endif - - endif ! end of istsoil + endif + enddo + endif enddo ! end of loop over landunits end subroutine HillslopeSoilThicknessProfile @@ -635,7 +652,7 @@ subroutine HillslopeSetLowlandUplandPfts(lowland_ivt,upland_ivt) ! !ARGUMENTS: ! ! !LOCAL VARIABLES: - integer :: n,nc,p,pu,pl,l,c ! indices + integer :: nc,p,pu,pl,l,c ! indices integer :: nclumps ! number of clumps on this processor integer, intent(in) :: upland_ivt @@ -648,16 +665,14 @@ subroutine HillslopeSetLowlandUplandPfts(lowland_ivt,upland_ivt) nclumps = get_proc_clumps() - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, c) do nc = 1, nclumps call get_clump_bounds(nc, bounds_clump) do l = bounds_clump%begl, bounds_clump%endl - - if (lun%itype(l) == istsoil) then - do c = lun%coli(l), lun%colf(l) - + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c)) then sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) @@ -685,8 +700,8 @@ subroutine HillslopeSetLowlandUplandPfts(lowland_ivt,upland_ivt) patch%wtgcell(pu) = sum_wtgrc endif endif - enddo ! end loop c - endif + endif + enddo ! end loop c enddo ! end loop l enddo ! end loop nc !$OMP END PARALLEL DO @@ -712,7 +727,7 @@ subroutine HillslopeDominantPft() ! !ARGUMENTS: ! ! !LOCAL VARIABLES: - integer :: n,nc,p,pu,pl,l,c ! indices + integer :: nc,p,pu,pl,l,c ! indices integer :: nclumps ! number of clumps on this processor integer :: pdom(1) real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc @@ -723,16 +738,14 @@ subroutine HillslopeDominantPft() nclumps = get_proc_clumps() - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, c) do nc = 1, nclumps call get_clump_bounds(nc, bounds_clump) do l = bounds_clump%begl, bounds_clump%endl - - if (lun%itype(l) == istsoil) then - do c = lun%coli(l), lun%colf(l) - + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c)) then pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) pdom = pdom + (col%patchi(c) - 1) @@ -747,8 +760,8 @@ subroutine HillslopeDominantPft() patch%wtcol(pdom(1)) = sum_wtcol patch%wtlunit(pdom(1)) = sum_wtlun patch%wtgcell(pdom(1)) = sum_wtgrc - enddo ! end loop c - endif + endif + enddo ! end loop c enddo ! end loop l enddo ! end loop nc !$OMP END PARALLEL DO @@ -775,7 +788,7 @@ subroutine HillslopeDominantLowlandPft() ! !ARGUMENTS: ! ! !LOCAL VARIABLES: - integer :: n,nc,p,pu,pl,l,c ! indices + integer :: nc,p,pu,pl,l,c ! indices integer :: nclumps ! number of clumps on this processor integer :: pdom(1),psubdom(1) integer :: plow, phigh @@ -788,16 +801,14 @@ subroutine HillslopeDominantLowlandPft() nclumps = get_proc_clumps() - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, c) do nc = 1, nclumps call get_clump_bounds(nc, bounds_clump) do l = bounds_clump%begl, bounds_clump%endl - - if (lun%itype(l) == istsoil) then - do c = lun%coli(l), lun%colf(l) - + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c)) then pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) ! create mask to exclude pdom allocate(mask(col%npatches(c))) @@ -858,8 +869,8 @@ subroutine HillslopeDominantLowlandPft() patch%wtlunit(phigh) = sum_wtlun patch%wtgcell(phigh) = sum_wtgrc endif - enddo ! end loop c - endif + endif + enddo ! end loop c enddo ! end loop l enddo ! end loop nc !$OMP END PARALLEL DO @@ -885,7 +896,7 @@ subroutine HillslopePftFromFile() ! !ARGUMENTS: ! ! !LOCAL VARIABLES: - integer :: n,nc,p,pc,l,c ! indices + integer :: nc,p,pc,l,c ! indices integer :: nclumps ! number of clumps on this processor real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc type(bounds_type) :: bounds_proc @@ -895,15 +906,14 @@ subroutine HillslopePftFromFile() nclumps = get_proc_clumps() - !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, nh, n, c) + !$OMP PARALLEL DO PRIVATE (nc, bounds_clump, l, c) do nc = 1, nclumps call get_clump_bounds(nc, bounds_clump) do l = bounds_clump%begl, bounds_clump%endl - - if (lun%itype(l) == istsoil) then - do c = lun%coli(l), lun%colf(l) + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c)) then ! this may require modifying ! subgridMod/natveg_patch_exists to ensure that ! a patch exists on each column @@ -912,7 +922,6 @@ subroutine HillslopePftFromFile() pc = ispval do p = col%patchi(c), col%patchf(c) if(patch%itype(p) == col%hill_pftndx(c)) pc = p -!scs if(patch%itype(p) == 1) pc = p enddo ! only reweight if pft exist within column @@ -936,8 +945,8 @@ subroutine HillslopePftFromFile() write(iulog,*) 'location ',c,grc%londeg(col%gridcell(c)),grc%latdeg(col%gridcell(c)) endif - enddo ! end loop c - endif + endif + enddo ! end loop c enddo ! end loop l enddo ! end loop nc !$OMP END PARALLEL DO @@ -994,7 +1003,8 @@ subroutine HillslopeStreamOutflow(bounds, & dtime = get_step_size_real() do l = bounds%begl,bounds%endl - if(lun%itype(l) == istsoil) then + qstreamflow(l) = 0._r8 + if(lun%itype(l) == istsoil) then ! Streamflow calculated from Manning equation if(streamflow_method == streamflow_manning) then cross_sectional_area = stream_water_volume(l) & @@ -1027,11 +1037,15 @@ subroutine HillslopeStreamOutflow(bounds, & else qstreamflow(l) = cross_sectional_area * flow_velocity endif + + ! scale streamflow by number of channel 'branches' + qstreamflow(l) = qstreamflow(l) * lun%stream_channel_number(l) * 1e3 + qstreamflow(l) = max(0._r8,min(qstreamflow(l),stream_water_volume(l)/dtime)) - end if - endif - endif ! end of istsoil - enddo ! end of loop over landunits + endif + endif + endif ! end of istsoil + enddo ! end of loop over landunits end associate @@ -1066,6 +1080,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & integer :: c, l, g, i, j real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) real(r8) :: qflx_drain_perched_vol ! volumetric perched water table runoff (m3/s) + real(r8) :: qflx_rsub_sat_vol ! volumetric correction runoff (m3/s) real(r8) :: dtime ! land model time step (sec) character(len=*), parameter :: subname = 'HillslopeUpdateStreamWater' @@ -1075,7 +1090,8 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input/Output: [real(r8) (:) ] stream water volume (m3) qstreamflow => waterfluxbulk_inst%qstreamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Input: [real(r8) (:) ] discharge from columns (m3/s) - qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) + qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, &! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) + qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Input: [real(r8) (:) ] column level correction runoff (mm H2O /s) qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) stream_water_depth => waterstatebulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) ) @@ -1084,21 +1100,32 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & dtime = get_step_size_real() do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - - if(lun%itype(l) == istsoil) then + if(lun%itype(l) == istsoil) then + g = lun%gridcell(l) + do c = lun%coli(l), lun%colf(l) - qflx_surf_vol = qflx_surf(c)*1.e-3_r8 & - *(grc%area(g)*1.e6_r8*col%wtgcell(c)) - qflx_drain_perched_vol = qflx_drain_perched(c)*1.e-3_r8 & - *(grc%area(g)*1.e6_r8*col%wtgcell(c)) - stream_water_volume(l) = stream_water_volume(l) & - + (qdischarge(c) + qflx_drain_perched_vol & - + qflx_surf_vol) * dtime + if (col%is_hillslope_column(c)) then + qflx_surf_vol = qflx_surf(c)*1.e-3_r8 & + *(grc%area(g)*1.e6_r8*col%wtgcell(c)) + qflx_drain_perched_vol = qflx_drain_perched(c)*1.e-3_r8 & + *(grc%area(g)*1.e6_r8*col%wtgcell(c)) + ! rsub_sat is not included in qdischarge, so add explicitly + qflx_rsub_sat_vol = qflx_rsub_sat(c)*1.e-3_r8 & + *(grc%area(g)*1.e6_r8*col%wtgcell(c)) + stream_water_volume(l) = stream_water_volume(l) & + + (qdischarge(c) + qflx_drain_perched_vol & + + qflx_rsub_sat_vol + qflx_surf_vol) * dtime + endif enddo stream_water_volume(l) = stream_water_volume(l) & - qstreamflow(l) * dtime + ! account for negative drainage (via searchforwater in soilhydrology) + if(stream_water_volume(l) < 0._r8) then + qstreamflow(l) = qstreamflow(l) + stream_water_volume(l)/dtime + stream_water_volume(l) = 0._r8 + endif + stream_water_depth(l) = stream_water_volume(l) & /lun%stream_channel_length(l) & /lun%stream_channel_width(l) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index e2fc6c1805..c22a50a5f1 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1551,6 +1551,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & associate( & dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) + zi => col%zi , & ! Input: [real(r8) (:,:) ] layer depth (m) t_soisno => temperature_inst%t_soisno_col , & ! Input: [real(r8) (:,:) ] soil temperature (Kelvin) h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) @@ -1569,34 +1570,35 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! define frost table as first frozen layer with unfrozen layer above it if(t_soisno(c,1) > tfrz) then - k_frz=nlevsoi + k_frz = nlevsoi else - k_frz=1 + k_frz = 1 endif - do k=2, nlevsoi + do k=2,nlevsoi if (t_soisno(c,k-1) > tfrz .and. t_soisno(c,k) <= tfrz) then - k_frz=k + k_frz = k exit endif enddo - frost_table(c)=z(c,k_frz) + ! frost table is top of frozen layer + frost_table(c)=z(c,k_frz-1) - ! initialize perched water table to frost table, and qflx_drain_perched(c) to zero - zwt_perched(c)=frost_table(c) + ! initialize perched water table to frost table + zwt_perched(c) = frost_table(c) !======= water table above frost table =================== ! if water table is above frost table, do nothing if (zwt(c) < frost_table(c) .and. t_soisno(c,k_frz) <= tfrz & .and. origflag == 0) then - else + else if (k_frz > 1) then !========== water table below frost table ============ ! locate perched water table from bottom up starting at ! frost table sat_lev is an arbitrary saturation level ! used to determine perched water table - sat_lev=0.9 + sat_lev = 0.9 k_perch=1 do k=k_frz,1,-1 @@ -1604,15 +1606,16 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & + h2osoi_ice(c,k)/(dz(c,k)*denice) if (h2osoi_vol(c,k)/watsat(c,k) <= sat_lev) then - k_perch=k + k_perch = k exit endif enddo - ! if frost_table = nlevsoi, only compute perched water table if frozen - if (t_soisno(c,k_frz) > tfrz) k_perch=k_frz + ! if frost_table = nlevsoi, check temperature of layer, + ! and only compute perched water table if frozen + if (t_soisno(c,k_frz) > tfrz) k_perch = k_frz - ! if perched water table exists + ! if perched water table exists above frost table, ! interpolate between k_perch and k_perch+1 to find ! perched water table height if (k_frz > k_perch) then @@ -1621,11 +1624,14 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & s2 = (h2osoi_liq(c,k_perch+1)/(dz(c,k_perch+1)*denh2o) & + h2osoi_ice(c,k_perch+1)/(dz(c,k_perch+1)*denice))/watsat(c,k_perch+1) - m=(z(c,k_perch+1)-z(c,k_perch))/(s2-s1) - b=z(c,k_perch+1)-m*s2 - zwt_perched(c)=max(0._r8,m*sat_lev+b) - - endif !k_frz > k_perch + if (s1 > s2) then + zwt_perched(c) = zi(c,k_perch-1) + else + m=(z(c,k_perch+1)-z(c,k_perch))/(s2-s1) + b=z(c,k_perch+1)-m*s2 + zwt_perched(c)=max(0._r8,m*sat_lev+b) + endif + endif endif end do @@ -1716,16 +1722,16 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & ! locate frost table and perched water table do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - k_frost(c)=nbedrock(c) - k_perch(c)=nbedrock(c) - do k=1, nbedrock(c) + k_frost(c) = nbedrock(c) + k_perch(c) = nbedrock(c) + do k=1,nbedrock(c) if (frost_table(c) >= zi(c,k-1) .and. frost_table(c) <= zi(c,k)) then k_frost(c)=k exit endif enddo - do k=1, nbedrock(c) + do k=1,nbedrock(c) if (zwt_perched(c) >= zi(c,k-1) .and. zwt_perched(c) <= zi(c,k)) then k_perch(c)=k exit @@ -1794,32 +1800,53 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & ! Calculate transmissivity of source column transmis = 0._r8 - if(c_src /= ispval) then - ! sum of layer transmissivities - if (transmissivity_method == 'layersum') then - do k = k_perch(c_src), k_frost(c_src) - if(k == k_perch(c_src)) then - transmis = transmis + 1.e-3_r8*hksat(c_src,k)*(zi(c_src,k) - zwt_perched(c_src)) - else - transmis = transmis + 1.e-3_r8*hksat(c_src,k)*dz(c_src,k) - endif - end do - ! adjust by 'anisotropy factor' - transmis = k_anisotropic*transmis - endif - ! constant conductivity based on shallowest saturated layer hk - if (transmissivity_method == 'constant') then - transmis = k_anisotropic*(1.e-3_r8*hksat(c_src,k_perch(c_src))) & - *(zi(c_src,k_frost(c_src)) - zwt_perched(c_src) ) - endif - ! power law profile based on shallowest saturated layer hk - if (transmissivity_method == 'power') then - endif - else + if(c_src == ispval) then + ! lowland, losing stream + ! transmissivity of losing stream (c_src == ispval) - transmis = k_anisotropic*(1.e-3_r8*hksat(c,k_perch(c_dst)))*stream_water_depth + transmis = (1.e-3_r8*hksat(c,k_perch(c_dst)))*stream_water_depth + else + ! if k_perch equals k_frost, no perched saturated zone exists + if(k_perch(c_src) < k_frost(c_src)) then + if (transmissivity_method == 'layersum') then + do k = k_perch(c_src), k_frost(c_src)-1 + if(k == k_perch(c_src)) then + transmis = transmis + 1.e-3_r8*hksat(c_src,k)*(zi(c_src,k) - zwt_perched(c_src)) + else + if(c_dst == ispval) then + ! lowland, gaining stream + ! only include layers above stream channel bottom + if ((col%hill_elev(c_src)-z(c_src,k)) > (-stream_channel_depth)) then + + transmis = transmis + 1.e-3_r8*hksat(c_src,k)*dz(c_src,k) + endif + else + ! uplands + ! only include layers above dst water table elevation + if ((col%hill_elev(c_src)-z(c_src,k)) > (col%hill_elev(c_dst) - zwt_perched(c_dst))) then + + transmis = transmis + 1.e-3_r8*hksat(c_src,k)*dz(c_src,k) + endif + endif + endif + enddo + endif + + + ! constant conductivity based on shallowest saturated layer hk + if (transmissivity_method == 'constant') then + transmis = (1.e-3_r8*hksat(c_src,k_perch(c_src))) & + *(zi(c_src,k_frost(c_src)) - zwt_perched(c_src) ) + endif + ! power law profile based on shallowest saturated layer hk + if (transmissivity_method == 'power') then + endif + endif endif + ! adjust by 'anisotropy factor' + transmis = k_anisotropic*transmis + qflx_drain_perched_vol(c) = transmis*col%hill_width(c)*dgrad qflx_drain_perched_out(c) = 1.e3_r8*(qflx_drain_perched_vol(c)/col%hill_area(c)) @@ -1831,7 +1858,8 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & wtsub = 0._r8 q_perch = 0._r8 - do k = k_perch(c), k_frost(c) +! this should be consistent with hillslope and k_perch=k_frost means no saturated zone; should probably change q_perch to tranmis and change units and q_perch_max + do k = k_perch(c), k_frost(c)-1 q_perch = q_perch + hksat(c,k)*dz(c,k) wtsub = wtsub + dz(c,k) end do @@ -1865,7 +1893,8 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & ! remove drainage from perched saturated layers drainage_tot = qflx_drain_perched(c) * dtime - do k = k_perch(c), k_frost(c) + ! ignore frozen layer (k_frost) + do k = k_perch(c), k_frost(c)-1 s_y = watsat(c,k) & * ( 1. - (1.+1.e3*zwt_perched(c)/sucsat(c,k))**(-1./bsw(c,k))) @@ -1949,7 +1978,7 @@ subroutine ThetaBasedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! locate water table from bottom up starting at bottom of soil column ! sat_lev is an arbitrary saturation level used to determine water table - sat_lev=0.9 + sat_lev = 0.9 k_zwt=nbedrock(c) sat_flag=1 !will remain unchanged if all layers at saturation @@ -2229,6 +2258,12 @@ subroutine SubsurfaceLateralFlow(bounds, & endif end if + + !scs: in cases of bad data, where hand differences in + ! adjacent bins are very large, cap maximum dgrad + ! should a warning be used instead? + dgrad = min(max(dgrad,-2._r8),2._r8) + ! Calculate transmissivity of source column if (dgrad >= 0._r8) then c_src = c @@ -2246,7 +2281,19 @@ subroutine SubsurfaceLateralFlow(bounds, & if(j == jwt(c_src)+1) then transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*(zi(c_src,j) - zwt(c_src)) else - transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*dz(c_src,j) + if(c_dst == ispval) then + ! lowland, gaining stream + ! only include layers above stream channel bottom + if ((col%hill_elev(c_src)-z(c_src,j)) > (-stream_channel_depth)) then + + transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*dz(c_src,j) + endif + else + ! uplands + if ((col%hill_elev(c_src)-z(c_src,j)) > (col%hill_elev(c_dst) - zwt(c_dst))) then + transmis = transmis + 1.e-3_r8*ice_imped(c_src,j)*hksat(c_src,j)*dz(c_src,j) + endif + endif endif end do endif @@ -2495,8 +2542,8 @@ subroutine SubsurfaceLateralFlow(bounds, & ! Instead of removing water from aquifer where it eventually ! shows up as excess drainage to the ocean, take it back out of ! drainage - qflx_rsub_sat(c) = qflx_rsub_sat(c) - xs(c)/dtime + qflx_rsub_sat(c) = qflx_rsub_sat(c) - xs(c)/dtime end do diff --git a/src/biogeophys/SurfaceAlbedoMod.F90 b/src/biogeophys/SurfaceAlbedoMod.F90 index 12b42d3688..4b25bf84b6 100644 --- a/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/src/biogeophys/SurfaceAlbedoMod.F90 @@ -262,7 +262,7 @@ subroutine SurfaceAlbedo(bounds,nc, & use clm_varctl , only : use_subgrid_fluxes, use_snicar_frc, use_fates use CLMFatesInterfaceMod, only : hlm_fates_interface_type use landunit_varcon , only : istsoil - use clm_varctl , only : use_hillslope,downscale_hillslope_meteorology + use clm_varctl , only : downscale_hillslope_meteorology ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds ! bounds @@ -420,12 +420,12 @@ subroutine SurfaceAlbedo(bounds,nc, & do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (use_hillslope .and. downscale_hillslope_meteorology .and. lun%itype(col%landunit(c)) == istsoil) then -! calculate local incidence angle based on column slope and aspect + if (col%is_hillslope_column(c) .and. downscale_hillslope_meteorology) then + ! calculate local incidence angle based on column slope and aspect zenith_angle = acos(coszen_grc(g)) azsun_grc(g) = shr_orb_azimuth(nextsw_cday, grc%lat(g), grc%lon(g), declinp1, zenith_angle) -! hill_slope is [m/m], convert to radians + ! hill_slope is [m/m], convert to radians coszen_col(c) = shr_orb_cosinc(zenith_angle,azsun_grc(g),atan(col%hill_slope(c)),col%hill_aspect(c)) if(coszen_grc(g) > 0._r8 .and. coszen_col(c) < 0._r8) coszen_col(c) = 0._r8 diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 15da342b1d..23ac29ce21 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -9,7 +9,7 @@ module lnd_import_export use NUOPC_Model , only : NUOPC_ModelGet use shr_kind_mod , only : r8 => shr_kind_r8, cx=>shr_kind_cx, cxx=>shr_kind_cxx, cs=>shr_kind_cs use shr_sys_mod , only : shr_sys_abort - use clm_varctl , only : iulog + use clm_varctl , only : iulog, use_hillslope_routing use clm_time_manager , only : get_nstep use decompmod , only : bounds_type, get_proc_bounds use lnd2atmType , only : lnd2atm_type @@ -864,6 +864,10 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & do g = begg, endg data1d(g) = waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(g) + & waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(g) + if(use_hillslope_routing) then + data1d(g) = data1d(g) + & + waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) + endif end do call state_setexport_1d(exportState, Flrl_rofsub, data1d(begg:), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/src/main/LandunitType.F90 b/src/main/LandunitType.F90 index e05b5da83b..3a5c68c4f3 100644 --- a/src/main/LandunitType.F90 +++ b/src/main/LandunitType.F90 @@ -58,6 +58,7 @@ module LandunitType real(r8), pointer :: stream_channel_width (:) ! stream channel bankfull width (m) real(r8), pointer :: stream_channel_length (:) ! stream channel length (m) real(r8), pointer :: stream_channel_slope (:) ! stream channel slope (m/m) + real(r8), pointer :: stream_channel_number (:) ! number of channels in landunit contains @@ -115,6 +116,7 @@ subroutine Init(this, begl, endl) allocate(this%stream_channel_width(begl:endl)); this%stream_channel_width (:) = nan allocate(this%stream_channel_length(begl:endl)); this%stream_channel_length (:) = nan allocate(this%stream_channel_slope(begl:endl)); this%stream_channel_slope (:) = nan + allocate(this%stream_channel_number(begl:endl)); this%stream_channel_number (:) = nan end subroutine Init @@ -153,6 +155,7 @@ subroutine Clean(this) deallocate(this%stream_channel_width) deallocate(this%stream_channel_length) deallocate(this%stream_channel_slope) + deallocate(this%stream_channel_number) end subroutine Clean end module LandunitType diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index 6e40b0ca08..25fe2c3ed2 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -15,7 +15,7 @@ module TopoMod use glcBehaviorMod , only : glc_behavior_type use landunit_varcon, only : istice, istsoil use filterColMod , only : filter_col_type, col_filter_from_logical_array_active_only - use clm_varctl , only : use_hillslope,downscale_hillslope_meteorology + use clm_varctl , only : use_hillslope, downscale_hillslope_meteorology ! ! !PUBLIC TYPES: implicit none @@ -140,7 +140,7 @@ subroutine InitCold(this, bounds) ! For other landunits, arbitrarily initialize topo_col to 0 m; for landunits ! where this matters, this will get overwritten in the run loop by values sent ! from CISM - if (lun%itype(l) == istsoil .and. use_hillslope .and. downscale_hillslope_meteorology) then + if (col%is_hillslope_column(c) .and. downscale_hillslope_meteorology) then this%topo_col(c) = col%hill_elev(c) this%needs_downscaling_col(c) = .true. else @@ -254,16 +254,16 @@ subroutine UpdateTopo(this, bounds, num_icec, filter_icec, & allocate(mean_hillslope_elevation(bounds%begl:bounds%endl)) mean_hillslope_elevation(:) = 0._r8 do l = bounds%begl, bounds%endl - if (lun%itype(l) == istsoil) then - mhe_norm = 0._r8 - do c = lun%coli(l), lun%colf(l) + mhe_norm = 0._r8 + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c)) then mean_hillslope_elevation(l) = mean_hillslope_elevation(l) & + col%hill_elev(c)*col%hill_area(c) mhe_norm = mhe_norm + col%hill_area(c) - enddo - if (mhe_norm > 0) then - mean_hillslope_elevation(l) = mean_hillslope_elevation(l)/mhe_norm endif + enddo + if (mhe_norm > 0) then + mean_hillslope_elevation(l) = mean_hillslope_elevation(l)/mhe_norm endif enddo endif @@ -279,7 +279,7 @@ subroutine UpdateTopo(this, bounds, num_icec, filter_icec, & if (.not. this%needs_downscaling_col(c)) then g = col%gridcell(c) l = col%landunit(c) - if (lun%itype(l) == istsoil .and. use_hillslope .and. downscale_hillslope_meteorology) then + if (col%is_hillslope_column(c) .and. downscale_hillslope_meteorology) then this%topo_col(c) = atm_topo(g) & + (col%hill_elev(c) - mean_hillslope_elevation(l)) this%needs_downscaling_col(c) = .true. diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 04e75fd8c0..26b0cebbbd 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -781,8 +781,7 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) do c = bounds%begc,bounds%endc g = col%gridcell(c) forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad) -! if (col%active(c)) then - if (lun%itype(col%landunit(c)) == istsoil) then + if (col%is_hillslope_column(c)) then if (coszen_grc(g) > 0._r8) then forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) endif @@ -791,10 +790,10 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) sum_wtlunit(g) = sum_wtlunit(g) + col%wtlunit(c) end if end do + ! Normalize column level solar do c = bounds%begc,bounds%endc -! if (col%active(c)) then - if (lun%itype(col%landunit(c)) == istsoil) then + if (col%is_hillslope_column(c)) then g = col%gridcell(c) do n = 1,numrad ! absorbed energy is solar flux x area landunit (sum_wtlunit) @@ -827,7 +826,6 @@ subroutine downscale_hillslope_precipitation(bounds, & ! ! !USES: use clm_varcon , only : rair, cpair, grav - use clm_varctl , only : use_hillslope ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -880,7 +878,7 @@ subroutine downscale_hillslope_precipitation(bounds, & do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (lun%itype(col%landunit(c)) == istsoil) then + if (col%is_hillslope_column(c)) then ! spatially uniform normalization, but separate rain/snow rain_scalar = 1.2e-3 @@ -904,7 +902,7 @@ subroutine downscale_hillslope_precipitation(bounds, & ! Calculate normalization (area-weighted average precipitation) do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (lun%itype(col%landunit(c)) == istsoil) then + if (col%is_hillslope_column(c)) then norm_rain(g) = norm_rain(g) + col%wtlunit(c)*forc_rain_c(c) norm_snow(g) = norm_snow(g) + col%wtlunit(c)*forc_snow_c(c) sum_wt(g) = sum_wt(g) + col%wtlunit(c) @@ -920,7 +918,7 @@ subroutine downscale_hillslope_precipitation(bounds, & ! Normalize column precipitation to conserve gridcell average do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (lun%itype(col%landunit(c)) == istsoil) then + if (col%is_hillslope_column(c)) then if (norm_rain(g) > 0._r8) then forc_rain_c(c) = forc_rain_c(c) * forc_rain_g(g) / norm_rain(g) endif @@ -938,7 +936,7 @@ subroutine downscale_hillslope_precipitation(bounds, & ! Calculate normalization (area-weighted average precipitation) do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (lun%itype(col%landunit(c)) == istsoil) then + if (col%is_hillslope_column(c)) then norm_rain(g) = norm_rain(g) + col%wtlunit(c)*forc_rain_c(c) norm_snow(g) = norm_snow(g) + col%wtlunit(c)*forc_snow_c(c) sum_wt(g) = sum_wt(g) + col%wtlunit(c) diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index c9bcd73036..deb191eb8b 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -180,7 +180,7 @@ subroutine lnd2atm(bounds, & real(r8) , intent(in) :: net_carbon_exchange_grc( bounds%begg: ) ! net carbon exchange between land and atmosphere, positive for source (gC/m2/s) ! ! !LOCAL VARIABLES: - integer :: c, g ! indices + integer :: c, l, g ! indices real(r8) :: eflx_sh_ice_to_liq_grc(bounds%begg:bounds%endg) ! sensible heat flux generated from the ice to liquid conversion, averaged to gridcell real(r8), parameter :: amC = 12.0_r8 ! Atomic mass number for Carbon real(r8), parameter :: amO = 16.0_r8 ! Atomic mass number for Oxygen @@ -337,15 +337,51 @@ subroutine lnd2atm(bounds, & ! lnd -> rof !---------------------------------------------------- - call c2g( bounds, & - water_inst%waterfluxbulk_inst%qflx_surf_col (bounds%begc:bounds%endc), & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc (bounds%begg:bounds%endg), & - c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + if(use_hillslope_routing) then + ! streamflow is volume/time, so sum over landunits (do not weight) + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) = 0._r8 + do l = bounds%begl, bounds%endl + g = lun%gridcell(l) + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & + + water_inst%waterfluxbulk_inst%qstreamflow_lun(l) & + *1e3_r8/(grc%area(g)*1.e6_r8) + enddo + + ! If hillslope routing is used, exclude inputs to stream channel from gridcell averages to avoid double counting + call c2g( bounds, & + water_inst%waterfluxbulk_inst%qflx_surf_col (bounds%begc:bounds%endc), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc (bounds%begg:bounds%endg), & + c2l_scale_type= 'urbanf', l2g_scale_type='unity',c2l_scale_type2= 'exclude_hillslope') + + call c2g( bounds, & + water_inst%waterfluxbulk_inst%qflx_drain_col (bounds%begc:bounds%endc), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & + c2l_scale_type= 'urbanf', l2g_scale_type='unity',c2l_scale_type2= 'exclude_hillslope') + + call c2g( bounds, & + water_inst%waterfluxbulk_inst%qflx_drain_perched_col (bounds%begc:bounds%endc), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(bounds%begg:bounds%endg), & + c2l_scale_type= 'urbanf', l2g_scale_type='unity',c2l_scale_type2= 'exclude_hillslope') + + else - call c2g( bounds, & - water_inst%waterfluxbulk_inst%qflx_drain_col (bounds%begc:bounds%endc), & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & - c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + call c2g( bounds, & + water_inst%waterfluxbulk_inst%qflx_surf_col (bounds%begc:bounds%endc), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc (bounds%begg:bounds%endg), & + c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + + call c2g( bounds, & + water_inst%waterfluxbulk_inst%qflx_drain_col (bounds%begc:bounds%endc), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & + c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + + call c2g( bounds, & + water_inst%waterfluxbulk_inst%qflx_drain_perched_col (bounds%begc:bounds%endc), & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(bounds%begg:bounds%endg), & + c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) + + endif do c = bounds%begc, bounds%endc if (col%active(c)) then @@ -383,34 +419,6 @@ subroutine lnd2atm(bounds, & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_grc(g) - & water_inst%waterfluxbulk_inst%qflx_liq_dynbal_grc(g) enddo - - call c2g( bounds, & - water_inst%waterfluxbulk_inst%qflx_drain_perched_col (bounds%begc:bounds%endc), & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(bounds%begg:bounds%endg), & - c2l_scale_type= 'urbanf', l2g_scale_type='unity' ) - - - if(use_hillslope_routing) then - - call l2g( bounds, & - water_inst%waterfluxbulk_inst%qstreamflow_lun (bounds%begl:bounds%endl), & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc (bounds%begg:bounds%endg), & - l2g_scale_type='unity' ) - - ! convert streamflow from m3/s to mm/s (discharge to flux) - do g = bounds%begg, bounds%endg - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & - * 1.e3_r8 / (1.e6_r8 * grc%area(g)) - enddo - - ! for now, set surface runoff and perched drainage to zero, and - ! set subsurface runoff to streamflow (which accounts for all three fluxes) - ! instead of modifying src/cpl/*/lnd_import_export.F90 - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(bounds%begg:bounds%endg) = 0._r8 - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(bounds%begg:bounds%endg) = 0._r8 - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(bounds%begg:bounds%endg) = water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) - endif call c2g( bounds, & water_inst%waterfluxbulk_inst%qflx_sfc_irrig_col (bounds%begc:bounds%endc), & diff --git a/src/main/subgridAveMod.F90 b/src/main/subgridAveMod.F90 index c5ce4a4a98..bbb26d8560 100644 --- a/src/main/subgridAveMod.F90 +++ b/src/main/subgridAveMod.F90 @@ -100,6 +100,104 @@ module subgridAveMod contains + !----------------------------------------------------------------------- + subroutine set_c2l_scale (bounds, c2l_scale_type, scale_c2l) + ! + ! !DESCRIPTION: + ! Set scale_c2l for different c2l_scale_type values + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) + real(r8), intent(out) :: scale_c2l(bounds%begc:bounds%endc) ! scale factor for column->landunit mapping + + ! + ! !LOCAL VARIABLES: + integer :: c,l ! indices + !------------------------------------------------------------------------ + + ! Enforce expected array sizes + SHR_ASSERT_ALL_FL((ubound(scale_c2l) == (/bounds%endc/)), sourcefile, __LINE__) + + if (c2l_scale_type == 'unity') then + do c = bounds%begc,bounds%endc + scale_c2l(c) = 1.0_r8 + end do + else if (c2l_scale_type == 'urbanf') then + do c = bounds%begc,bounds%endc + l = col%landunit(c) + if (lun%urbpoi(l)) then + if (col%itype(c) == icol_sunwall) then + scale_c2l(c) = 3.0 * lun%canyon_hwr(l) + else if (col%itype(c) == icol_shadewall) then + scale_c2l(c) = 3.0 * lun%canyon_hwr(l) + else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then + scale_c2l(c) = 3.0_r8 + else if (col%itype(c) == icol_roof) then + scale_c2l(c) = 1.0_r8 + end if + else + scale_c2l(c) = 1.0_r8 + end if + end do + else if (c2l_scale_type == 'urbans') then + do c = bounds%begc,bounds%endc + l = col%landunit(c) + if (lun%urbpoi(l)) then + if (col%itype(c) == icol_sunwall) then + scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) + else if (col%itype(c) == icol_shadewall) then + scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) + else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then + scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) + else if (col%itype(c) == icol_roof) then + scale_c2l(c) = 1.0_r8 + end if + else + scale_c2l(c) = 1.0_r8 + end if + end do + else + write(iulog,*)'set_c2l_scale: scale type ',c2l_scale_type,' not supported' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + end subroutine set_c2l_scale + + subroutine set_c2l_scale_hillslope (bounds, c2l_scale_type, scale_c2l) + ! + ! !DESCRIPTION: + ! Set scale_c2l for hillslope c2l_scale_type values + ! set_c2l_scale must be called before set_c2l_scale_hillslope + ! Only hillslope column values are changed + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) + real(r8), intent(inout) :: scale_c2l(bounds%begc:bounds%endc) ! scale factor for column->landunit mapping + + ! + ! !LOCAL VARIABLES: + integer :: c,l ! indices + !------------------------------------------------------------------------ + + ! Enforce expected array sizes + SHR_ASSERT_ALL_FL((ubound(scale_c2l) == (/bounds%endc/)), sourcefile, __LINE__) + + if (c2l_scale_type == 'exclude_hillslope') then + do c = bounds%begc,bounds%endc + ! Only modify values of hillslope columns + if (col%is_hillslope_column(c)) then + scale_c2l(c) = 0.0_r8 + endif + enddo + else + write(iulog,*)'set_c2l_scale: scale type ',c2l_scale_type,' not supported' + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + + end subroutine set_c2l_scale_hillslope + !----------------------------------------------------------------------- subroutine p2c_1d (bounds, parr, carr, p2c_scale_type) ! @@ -770,48 +868,7 @@ subroutine c2l_1d (bounds, carr, larr, c2l_scale_type, include_inactive) l_include_inactive = .false. end if - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'c2l_1d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) larr(bounds%begl : bounds%endl) = spval sumwt(bounds%begl : bounds%endl) = 0._r8 @@ -866,48 +923,7 @@ subroutine c2l_2d (bounds, num2d, carr, larr, c2l_scale_type) SHR_ASSERT_ALL_FL((ubound(carr) == (/bounds%endc, num2d/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(larr) == (/bounds%endl, num2d/)), sourcefile, __LINE__) - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'c2l_2d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) larr(bounds%begl : bounds%endl, :) = spval do j = 1,num2d @@ -940,7 +956,7 @@ subroutine c2l_2d (bounds, num2d, carr, larr, c2l_scale_type) end subroutine c2l_2d !----------------------------------------------------------------------- - subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type) + subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type, c2l_scale_type2) ! ! !DESCRIPTION: ! Perfrom subgrid-average from columns to gridcells. @@ -952,6 +968,7 @@ subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type) real(r8), intent(out) :: garr( bounds%begg: ) ! output gridcell array character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging + character(len=*), intent(in), optional :: c2l_scale_type2 ! second scale factor type ! ! !LOCAL VARIABLES: integer :: c,l,g,index ! indices @@ -968,49 +985,13 @@ subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type) call build_scale_l2g(bounds, l2g_scale_type, & scale_l2g(bounds%begl:bounds%endl)) - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'c2l_1d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) + ! Adjust scale_c2l for hillslope columns only + if (present(c2l_scale_type2)) then + call set_c2l_scale_hillslope (bounds, c2l_scale_type2, scale_c2l) + endif + garr(bounds%begg : bounds%endg) = spval sumwt(bounds%begg : bounds%endg) = 0._r8 do c = bounds%begc,bounds%endc @@ -1041,7 +1022,7 @@ subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type) end subroutine c2g_1d !----------------------------------------------------------------------- - subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type) + subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type, c2l_scale_type2) ! ! !DESCRIPTION: ! Perfrom subgrid-average from columns to gridcells. @@ -1054,6 +1035,7 @@ subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type) real(r8), intent(out) :: garr( bounds%begg: , 1: ) ! output gridcell array character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging + character(len=*), intent(in), optional :: c2l_scale_type2 ! second scale factor type ! ! !LOCAL VARIABLES: integer :: j,c,g,l,index ! indices @@ -1070,48 +1052,12 @@ subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type) call build_scale_l2g(bounds, l2g_scale_type, & scale_l2g(bounds%begl:bounds%endl)) - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'c2g_2d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) + + ! Adjust scale_c2l for hillslope columns only + if (present(c2l_scale_type2)) then + call set_c2l_scale_hillslope (bounds, c2l_scale_type2, scale_c2l) + endif garr(bounds%begg : bounds%endg,:) = spval do j = 1,num2d From edcf043768ac1eeea0ecad349b5af0ae26f55dcf Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 5 May 2022 11:03:46 -0600 Subject: [PATCH 061/153] correct frost table value --- src/biogeophys/SoilHydrologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index c22a50a5f1..74f528ce72 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1583,7 +1583,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & enddo ! frost table is top of frozen layer - frost_table(c)=z(c,k_frz-1) + frost_table(c) = zi(c,k_frz-1) ! initialize perched water table to frost table zwt_perched(c) = frost_table(c) From 7c20b41fa8386fadd7c0841c67408bacf88bee0b Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 6 May 2022 08:11:36 -0600 Subject: [PATCH 062/153] fix inequality in perchedlateralflow --- src/biogeophys/SoilHydrologyMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 74f528ce72..fc58484ed4 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1725,14 +1725,14 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & k_frost(c) = nbedrock(c) k_perch(c) = nbedrock(c) do k=1,nbedrock(c) - if (frost_table(c) >= zi(c,k-1) .and. frost_table(c) <= zi(c,k)) then + if (frost_table(c) >= zi(c,k-1) .and. frost_table(c) < zi(c,k)) then k_frost(c)=k exit endif enddo do k=1,nbedrock(c) - if (zwt_perched(c) >= zi(c,k-1) .and. zwt_perched(c) <= zi(c,k)) then + if (zwt_perched(c) >= zi(c,k-1) .and. zwt_perched(c) < zi(c,k)) then k_perch(c)=k exit endif From e1dc2efcdc31051cb41f7d37ebce677d3128005a Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Fri, 13 May 2022 15:08:48 -0600 Subject: [PATCH 063/153] Minor cleanup Remove unused variables, clean up indentation, fix / add some comments, remove some commented-out old lines of code. The one change that actually changes any code is moving the calculations of fsds_vis_d and fsds_nir_d a few lines down, back to where they used to be, to keep them next to the related variables. From a read of the surrounding code, this move looks safe. --- src/biogeophys/SoilHydrologyMod.F90 | 15 +++++++-------- src/biogeophys/SurfaceAlbedoMod.F90 | 13 +++++-------- src/biogeophys/SurfaceRadiationMod.F90 | 21 ++------------------- src/main/atm2lndMod.F90 | 4 ---- src/main/initGridCellsMod.F90 | 5 +++++ src/main/initVerticalMod.F90 | 2 +- src/main/subgridMod.F90 | 5 +---- src/main/surfrdMod.F90 | 5 +---- 8 files changed, 22 insertions(+), 48 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index fc58484ed4..19c37ec233 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -33,7 +33,6 @@ module SoilHydrologyMod use LandunitType , only : lun use ColumnType , only : column_type, col use PatchType , only : patch - use spmdMod , only : masterproc, iam ! ! !PUBLIC TYPES: implicit none @@ -1551,7 +1550,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & associate( & dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) - zi => col%zi , & ! Input: [real(r8) (:,:) ] layer depth (m) + zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) t_soisno => temperature_inst%t_soisno_col , & ! Input: [real(r8) (:,:) ] soil temperature (Kelvin) h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) @@ -1665,7 +1664,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & type(wateratm2lndbulk_type), intent(in) :: wateratm2lndbulk_inst ! ! !LOCAL VARIABLES: - character(len=32) :: subname = 'PerchedLateralFlowHillslope' ! subroutine name + character(len=32) :: subname = 'PerchedLateralFlow' ! subroutine name integer :: c,j,fc,i,l,g ! indices real(r8) :: dtime ! land model time step (sec) real(r8) :: drainage_tot @@ -1687,7 +1686,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & real(r8) :: transmis real(r8) :: dgrad real(r8), parameter :: k_anisotropic = 1._r8 - integer :: c0, c_src, c_dst, nstep, nbase + integer :: c0, c_src, c_dst, nbase real(r8) :: qflx_drain_perched_vol(bounds%begc:bounds%endc) ! volumetric lateral subsurface flow through active layer [m3/s] real(r8) :: qflx_drain_perched_out(bounds%begc:bounds%endc) ! lateral subsurface flow through active layer [mm/s] @@ -1858,7 +1857,9 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & wtsub = 0._r8 q_perch = 0._r8 -! this should be consistent with hillslope and k_perch=k_frost means no saturated zone; should probably change q_perch to tranmis and change units and q_perch_max + ! this should be consistent with hillslope and k_perch=k_frost means no + ! saturated zone; should probably change q_perch to tranmis and change + ! units and q_perch_max do k = k_perch(c), k_frost(c)-1 q_perch = q_perch + hksat(c,k)*dz(c,k) wtsub = wtsub + dz(c,k) @@ -2036,7 +2037,6 @@ subroutine SubsurfaceLateralFlow(bounds, & use abortutils , only : endrun use GridcellType , only : grc use landunit_varcon , only : istsoil, istcrop - use clm_time_manager , only : get_nstep ! ! !ARGUMENTS: @@ -2104,7 +2104,7 @@ subroutine SubsurfaceLateralFlow(bounds, & real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) real(r8) :: qflx_latflow_avg(bounds%begc:bounds%endc) real(r8) :: larea - integer :: c0, c_src, c_dst, nstep + integer :: c0, c_src, c_dst integer :: l !----------------------------------------------------------------------- @@ -2153,7 +2153,6 @@ subroutine SubsurfaceLateralFlow(bounds, & ! Get time step dtime = get_step_size_real() - nstep = get_nstep() ! Convert layer thicknesses from m to mm diff --git a/src/biogeophys/SurfaceAlbedoMod.F90 b/src/biogeophys/SurfaceAlbedoMod.F90 index c710e05ef6..9b4ac76b8a 100644 --- a/src/biogeophys/SurfaceAlbedoMod.F90 +++ b/src/biogeophys/SurfaceAlbedoMod.F90 @@ -308,7 +308,6 @@ subroutine SurfaceAlbedo(bounds,nc, & real(r8) :: ws (bounds%begp:bounds%endp) ! fraction of LAI+SAI that is SAI real(r8) :: blai(bounds%begp:bounds%endp) ! lai buried by snow: tlai - elai real(r8) :: bsai(bounds%begp:bounds%endp) ! sai buried by snow: tsai - esai - real(r8) :: coszen_gcell (bounds%begg:bounds%endg) ! cosine solar zenith angle for next time step (grc) real(r8) :: coszen_patch (bounds%begp:bounds%endp) ! cosine solar zenith angle for next time step (patch) real(r8) :: rho(bounds%begp:bounds%endp,numrad) ! leaf/stem refl weighted by fraction LAI and SAI real(r8) :: tau(bounds%begp:bounds%endp,numrad) ! leaf/stem tran weighted by fraction LAI and SAI @@ -429,18 +428,16 @@ subroutine SurfaceAlbedo(bounds,nc, & ! hill_slope is [m/m], convert to radians coszen_col(c) = shr_orb_cosinc(zenith_angle,azsun_grc(g),atan(col%hill_slope(c)),col%hill_aspect(c)) - if(coszen_grc(g) > 0._r8 .and. coszen_col(c) < 0._r8) coszen_col(c) = 0._r8 + if(coszen_grc(g) > 0._r8 .and. coszen_col(c) < 0._r8) coszen_col(c) = 0._r8 - - else - coszen_col(c) = coszen_grc(g) - endif + else + coszen_col(c) = coszen_grc(g) + endif end do do fp = 1,num_nourbanp p = filter_nourbanp(fp) - g = patch%gridcell(p) c = patch%column(p) - coszen_patch(p) = coszen_col(c) + coszen_patch(p) = coszen_col(c) end do ! Initialize output because solar radiation only done if coszen > 0 diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index f48e0e98e7..4168fb60a5 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -687,7 +687,6 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Absorbed by canopy -! cad(p,ib) = forc_solad(g,ib)*fabd(p,ib) cad(p,ib) = forc_solad_col(c,ib)*fabd(p,ib) cai(p,ib) = forc_solai(g,ib)*fabi(p,ib) sabv(p) = sabv(p) + cad(p,ib) + cai(p,ib) @@ -701,8 +700,6 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Transmitted = solar fluxes incident on ground -! trd(p,ib) = forc_solad(g,ib)*ftdd(p,ib) -! tri(p,ib) = forc_solad(g,ib)*ftid(p,ib) + forc_solai(g,ib)*ftii(p,ib) trd(p,ib) = forc_solad_col(c,ib)*ftdd(p,ib) tri(p,ib) = forc_solad_col(c,ib)*ftid(p,ib) + forc_solai(g,ib)*ftii(p,ib) ! Solar radiation absorbed by ground surface @@ -899,25 +896,19 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! NDVI and reflected solar radiation -! rvis = albd(p,1)*forc_solad(g,1) + albi(p,1)*forc_solai(g,1) -! rnir = albd(p,2)*forc_solad(g,2) + albi(p,2)*forc_solai(g,2) rvis = albd(p,1)*forc_solad_col(c,1) + albi(p,1)*forc_solai(g,1) rnir = albd(p,2)*forc_solad_col(c,2) + albi(p,2)*forc_solai(g,2) fsr(p) = rvis + rnir -! fsds_vis_d(p) = forc_solad(g,1) -! fsds_nir_d(p) = forc_solad(g,2) - fsds_vis_d(p) = forc_solad_col(c,1) - fsds_nir_d(p) = forc_solad_col(c,2) if (use_SSRE) then rvisSF = albdSF(p,1)*forc_solad(g,1) + albiSF(p,1)*forc_solai(g,1) rnirSF = albdSF(p,2)*forc_solad(g,2) + albiSF(p,2)*forc_solai(g,2) fsrSF(p) = rvisSF + rnirSF ssre_fsr(p) = fsr(p)-fsrSF(p) end if + fsds_vis_d(p) = forc_solad_col(c,1) + fsds_nir_d(p) = forc_solad_col(c,2) fsds_vis_i(p) = forc_solai(g,1) fsds_nir_i(p) = forc_solai(g,2) -! fsr_vis_d(p) = albd(p,1)*forc_solad(g,1) -! fsr_nir_d(p) = albd(p,2)*forc_solad(g,2) fsr_vis_d(p) = albd(p,1)*forc_solad_col(c,1) fsr_nir_d(p) = albd(p,2)*forc_solad_col(c,2) fsr_vis_i(p) = albi(p,1)*forc_solai(g,1) @@ -934,10 +925,6 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ssre_fsr_nir_i(p) = fsrSF_nir_i(p)-fsr_nir_i(p) end if if ( is_near_local_noon( grc%londeg(g), deltasec=nint(dtime)/2 ) )then -! fsds_vis_d_ln(p) = forc_solad(g,1) -! fsds_nir_d_ln(p) = forc_solad(g,2) -! fsr_vis_d_ln(p) = albd(p,1)*forc_solad(g,1) -! fsr_nir_d_ln(p) = albd(p,2)*forc_solad(g,2) fsds_vis_d_ln(p) = forc_solad_col(c,1) fsds_nir_d_ln(p) = forc_solad_col(c,2) fsr_vis_d_ln(p) = albd(p,1)*forc_solad_col(c,1) @@ -965,8 +952,6 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! (OPTIONAL) c = patch%column(p) if (snl(c) < 0) then -! fsds_sno_vd(p) = forc_solad(g,1) -! fsds_sno_nd(p) = forc_solad(g,2) fsds_sno_vd(p) = forc_solad_col(c,1) fsds_sno_nd(p) = forc_solad_col(c,2) fsds_sno_vi(p) = forc_solai(g,1) @@ -1022,8 +1007,6 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Solar reflected ! per unit ground area (roof, road) and per unit wall area (sunwall, shadewall) -! fsr_vis_d(p) = albd(p,1) * forc_solad(g,1) -! fsr_nir_d(p) = albd(p,2) * forc_solad(g,2) fsr_vis_d(p) = albd(p,1) * forc_solad_col(c,1) fsr_nir_d(p) = albd(p,2) * forc_solad_col(c,2) fsr_vis_i(p) = albi(p,1) * forc_solai(g,1) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 26b0cebbbd..933668a7e9 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -334,10 +334,6 @@ subroutine partition_precip(bounds, atm2lnd_inst, wateratm2lndbulk_inst, eflx_sh SHR_ASSERT_ALL_FL((ubound(eflx_sh_precip_conversion) == (/bounds%endc/)), sourcefile, __LINE__) associate(& - ! Gridcell-level non-downscaled fields: - forc_rain_g => wateratm2lndbulk_inst%forc_rain_not_downscaled_grc , & ! Input: [real(r8) (:)] rain rate [mm/s] - forc_snow_g => wateratm2lndbulk_inst%forc_snow_not_downscaled_grc , & ! Input: [real(r8) (:)] snow rate [mm/s] - ! Column-level downscaled fields: forc_t_c => atm2lnd_inst%forc_t_downscaled_col , & ! Input: [real(r8) (:)] atmospheric temperature (Kelvin) forc_rain_c => wateratm2lndbulk_inst%forc_rain_downscaled_col , & ! Output: [real(r8) (:)] rain rate [mm/s] diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index 983c9e76b5..f783a1efff 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -240,6 +240,11 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) if (nlunits > 0) then call add_landunit(li=li, gi=gi, ltype=ltype, wtgcell=wtlunit2gcell) nlunits_added = nlunits_added + 1 + ! Potentially create multiple columns (e.g., for hillslope hydrology), but each + ! with the same PFT breakdown. + ! + ! Set column weight arbitrarily for now. If we have multiple columns because we're + ! using hillslope hydrology, then col%wtlunit will be modified in InitHillslope. wtcol2lunit = 1.0_r8/real(ncols,r8) do ci2 = 1,ncols call add_column(ci=ci, li=li, ctype=1, wtlunit=wtcol2lunit) diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index 124bcc93f0..3ea6ef4fe3 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -91,7 +91,7 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) real(r8) , intent(in) :: thick_roof(bounds%begl:) ! ! LOCAL VARAIBLES: - integer :: c,l,g,i,j,lev,nh ! indices + integer :: c,l,g,i,j,lev ! indices type(file_desc_t) :: ncid ! netcdf id logical :: readvar integer :: dimid ! dimension id diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 2cfe60627d..2480bf2413 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -87,7 +87,6 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & call subgrid_get_info_natveg(gi, npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() - !scs jks HH-FATES ! call this after natveg call because we allocate space for ! FATES cohorts based on the number of naturally vegetated columns ! and nothing else @@ -115,9 +114,6 @@ subroutine subgrid_get_gcellinfo (gi, glc_behavior, & call subgrid_get_info_crop(gi, npatches_temp, ncols_temp, nlunits_temp) call accumulate_counters() - !move up for FATES -!scs jks !call subgrid_get_info_cohort(gi, ncols_temp, ncohorts) - contains subroutine accumulate_counters ! Accumulate running sums of patches, columns and landunits. @@ -171,6 +167,7 @@ subroutine subgrid_get_info_natveg(gi, npatches, ncols, nlunits) else ncols = 1 endif + ! Assume that each PFT present in the grid cell is present in every column npatches = ncols*npatches else diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 4cb23afe1f..91299b0ad9 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -774,13 +774,10 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) integer :: dimid,varid ! netCDF id's integer :: ier ! error status logical :: readvar ! is variable on dataset - integer,pointer :: arrayl(:) ! local array + integer,pointer :: arrayl(:) ! local array (needed because ncd_io expects a pointer) character(len=32) :: subname = 'surfrd_hillslope' ! subroutine name !----------------------------------------------------------------------- - ! This temporary array is needed because ncd_io expects a pointer, - !so we can't directly pass - ! number of hillslopes per landunit call ncd_inqdid(ncid,'nhillslope',dimid,readvar) if (.not. readvar) then From 84f14ff324905da8f6f7540b612a5d74b8b07939 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 24 May 2022 09:44:54 -0600 Subject: [PATCH 064/153] remove origflag and fracice --- bld/CLMBuildNamelist.pm | 7 -- .../namelist_definition_ctsm.xml | 6 -- src/biogeophys/SaturatedExcessRunoffMod.F90 | 35 +++------- src/biogeophys/SoilHydrologyMod.F90 | 64 +++++-------------- src/biogeophys/SoilHydrologyType.F90 | 10 +-- src/biogeophys/SoilWaterMovementMod.F90 | 59 +++++------------ 6 files changed, 42 insertions(+), 139 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 2233ec0626..fb8223c9df 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3024,12 +3024,8 @@ sub setup_logic_hydrology_switches { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_subgrid_fluxes'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_cover_fraction_method'); my $subgrid = $nl->get_value('use_subgrid_fluxes' ); - my $origflag = $nl->get_value('origflag' ); my $h2osfcflag = $nl->get_value('h2osfcflag' ); my $scf_method = $nl->get_value('snow_cover_fraction_method'); - if ( $origflag == 1 && &value_is_true($subgrid) ) { - $log->fatal_error("if origflag is ON, use_subgrid_fluxes can NOT also be on!"); - } if ( $h2osfcflag == 1 && ! &value_is_true($subgrid) ) { $log->fatal_error("if h2osfcflag is ON, use_subgrid_fluxes can NOT be off!"); } @@ -3053,9 +3049,6 @@ sub setup_logic_hydrology_switches { if ( defined($use_vic) && defined($lower) && (&value_is_true($use_vic)) && $lower != 3 && $lower != 4) { $log->fatal_error( "If use_vichydro is on -- lower_boundary_condition can only be table or aquifer" ); } - if ( defined($origflag) && defined($use_vic) && (&value_is_true($use_vic)) && $origflag == 1 ) { - $log->fatal_error( "If use_vichydro is on -- origflag can NOT be equal to 1" ); - } if ( defined($h2osfcflag) && defined($lower) && $h2osfcflag == 0 && $lower != 4 ) { $log->fatal_error( "If h2osfcflag is 0 lower_boundary_condition can only be aquifer" ); } diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index a61c0a2c72..82f4cb4bac 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -2392,12 +2392,6 @@ If surface water is active or not (deprecated -- will be removed) - -Use original CLM4 soil hydraulic properties -(deprecated -- will be removed) - - diff --git a/src/biogeophys/SaturatedExcessRunoffMod.F90 b/src/biogeophys/SaturatedExcessRunoffMod.F90 index 309d251460..5643a95394 100644 --- a/src/biogeophys/SaturatedExcessRunoffMod.F90 +++ b/src/biogeophys/SaturatedExcessRunoffMod.F90 @@ -233,10 +233,8 @@ subroutine SaturatedExcessRunoff (this, bounds, num_hydrologyc, filter_hydrology qflx_sat_excess_surf => waterfluxbulk_inst%qflx_sat_excess_surf_col, & ! Output: [real(r8) (:) ] surface runoff due to saturated surface (mm H2O /s) qflx_floodc => waterfluxbulk_inst%qflx_floodc_col , & ! Input: [real(r8) (:) ] column flux of flood water from RTM - qflx_rain_plus_snomelt => waterfluxbulk_inst%qflx_rain_plus_snomelt_col , & ! Input: [real(r8) (:) ] rain plus snow melt falling on the soil (mm/s) + qflx_rain_plus_snomelt => waterfluxbulk_inst%qflx_rain_plus_snomelt_col & ! Input: [real(r8) (:) ] rain plus snow melt falling on the soil (mm/s) - origflag => soilhydrology_inst%origflag , & ! Input: logical - fracice => soilhydrology_inst%fracice_col & ! Input: [real(r8) (:,:) ] fractional impermeability (-) ) ! ------------------------------------------------------------------------ @@ -275,29 +273,14 @@ subroutine SaturatedExcessRunoff (this, bounds, num_hydrologyc, filter_hydrology ! qflx_rain_plus_snomelt in control ! ------------------------------------------------------------------------ - if (origflag == 1) then - if (this%fsat_method == FSAT_METHOD_VIC) then - ! NOTE(wjs, 2017-07-12) I'm not sure if it's the VIC fsat method per se that - ! is incompatible with origflag, or some other aspect of VIC: The original - ! check was for origflag == 1 and use_vichydro, which also appears in error - ! checks elsewhere. - call endrun(msg="VICHYDRO is not available for origflag=1"//errmsg(sourcefile, __LINE__)) - end if - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - fcov(c) = (1._r8 - fracice(c,1)) * fsat(c) + fracice(c,1) - qflx_sat_excess_surf(c) = fcov(c) * qflx_rain_plus_snomelt(c) - end do - else - do fc = 1, num_hydrologyc - c = filter_hydrologyc(fc) - ! only send fast runoff directly to streams - qflx_sat_excess_surf(c) = fsat(c) * qflx_rain_plus_snomelt(c) - - ! Set fcov just to have it on the history file - fcov(c) = fsat(c) - end do - end if + do fc = 1, num_hydrologyc + c = filter_hydrologyc(fc) + ! only send fast runoff directly to streams + qflx_sat_excess_surf(c) = fsat(c) * qflx_rain_plus_snomelt(c) + + ! Set fcov just to have it on the history file + fcov(c) = fsat(c) + end do ! ------------------------------------------------------------------------ ! For urban columns, send flood water flux to runoff diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 22b3ae226d..bc72afbcaa 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -191,12 +191,10 @@ subroutine SetSoilWaterFractions(bounds, num_hydrologyc, filter_hydrologyc, & watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) eff_porosity => soilstate_inst%eff_porosity_col , & ! Output: [real(r8) (:,:) ] effective porosity = porosity - vol_ice - h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) - h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice water (kg/m2) + h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid water (kg/m2) + h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice water (kg/m2) - origflag => soilhydrology_inst%origflag , & ! Input: logical - icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] - fracice => soilhydrology_inst%fracice_col & ! Output: [real(r8) (:,:) ] fractional impermeability (-) + icefrac => soilhydrology_inst%icefrac_col & ! Output: [real(r8) (:,:) ] ) do j = 1,nlevsoi @@ -209,15 +207,6 @@ subroutine SetSoilWaterFractions(bounds, num_hydrologyc, filter_hydrologyc, & eff_porosity(c,j) = max(0.01_r8,watsat(c,j)-vol_ice(c,j)) icefrac(c,j) = min(1._r8,vol_ice(c,j)/watsat(c,j)) - ! fracice is only used in code with origflag == 1. For this calculation, we use - ! the version of icefrac that was used in this original hydrology code. - if (h2osoi_ice(c,j) == 0._r8) then - ! Avoid possible divide by zero (in case h2osoi_liq(c,j) is also 0) - icefrac_orig = 0._r8 - else - icefrac_orig = min(1._r8,h2osoi_ice(c,j)/(h2osoi_ice(c,j)+h2osoi_liq(c,j))) - end if - fracice(c,j) = max(0._r8,exp(-3._r8*(1._r8-icefrac_orig))- exp(-3._r8))/(1.0_r8-exp(-3._r8)) end do end do @@ -608,7 +597,6 @@ subroutine WaterTable(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) :: s_node ! soil wetness (-) real(r8) :: dzsum ! summation of dzmm of layers below water table (mm) real(r8) :: icefracsum ! summation of icefrac*dzmm of layers below water table (-) - real(r8) :: fracice_rsub(bounds%begc:bounds%endc) ! fractional impermeability of soil layers (-) real(r8) :: ka ! hydraulic conductivity of the aquifer (mm/s) real(r8) :: available_h2osoi_liq ! available soil liquid water in a layer real(r8) :: imped @@ -655,7 +643,6 @@ subroutine WaterTable(bounds, num_hydrologyc, filter_hydrologyc, & frost_table => soilhydrology_inst%frost_table_col , & ! Output: [real(r8) (:) ] frost table depth (m) wa => waterstatebulk_inst%wa_col , & ! Output: [real(r8) (:) ] water in the unconfined aquifer (mm) qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) - origflag => soilhydrology_inst%origflag , & ! Input: logical qflx_drain => waterfluxbulk_inst%qflx_drain_col , & ! Output: [real(r8) (:) ] sub-surface runoff (mm H2O /s) qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col , & ! Output: [real(r8) (:) ] perched wt sub-surface runoff (mm H2O /s) @@ -790,8 +777,7 @@ subroutine WaterTable(bounds, num_hydrologyc, filter_hydrologyc, & !=================== water table above frost table ============================= ! if water table is above frost table, do not use topmodel baseflow formulation - if (zwt(c) < frost_table(c) .and. t_soisno(c,k_frz) <= tfrz & - .and. origflag == 0) then + if (zwt(c) < frost_table(c) .and. t_soisno(c,k_frz) <= tfrz) then else !=================== water table below frost table ============================= !-- compute possible perched water table *and* groundwater table afterwards @@ -877,7 +863,6 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte real(r8) :: s_node ! soil wetness (-) real(r8) :: dzsum ! summation of dzmm of layers below water table (mm) real(r8) :: icefracsum ! summation of icefrac*dzmm of layers below water table (-) - real(r8) :: fracice_rsub(bounds%begc:bounds%endc) ! fractional impermeability of soil layers (-) real(r8) :: ka ! hydraulic conductivity of the aquifer (mm/s) real(r8) :: dza ! fff*(zwt-z(jwt)) (-) real(r8) :: available_h2osoi_liq ! available soil liquid water in a layer @@ -940,7 +925,6 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte wa => waterstatebulk_inst%wa_col , & ! Input: [real(r8) (:) ] water in the unconfined aquifer (mm) ice => soilhydrology_inst%ice_col , & ! Input: [real(r8) (:,:) ] soil layer moisture (mm) qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) - origflag => soilhydrology_inst%origflag , & ! Input: logical h2osfcflag => soilhydrology_inst%h2osfcflag , & ! Input: integer qflx_snwcp_liq => waterfluxbulk_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess liquid h2o due to snow capping (outgoing) (mm H2O /s) [+] @@ -980,8 +964,6 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte qflx_drain(c) = 0._r8 qflx_rsub_sat(c) = 0._r8 rsub_top(c) = 0._r8 - fracice_rsub(c) = 0._r8 - end do ! The layer index of the first unsaturated layer, i.e., the layer right above @@ -1035,8 +1017,7 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte !=================== water table above frost table ============================= ! if water table is above frost table, do not use topmodel baseflow formulation - if (zwt(c) < frost_table(c) .and. t_soisno(c,k_frz) <= tfrz & - .and. origflag == 0) then + if (zwt(c) < frost_table(c) .and. t_soisno(c,k_frz) <= tfrz) then ! compute drainage from perched saturated region wtsub = 0._r8 q_perch = 0._r8 @@ -1126,9 +1107,6 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte qflx_drain_perched(c) = q_perch_max * q_perch & *(frost_table(c) - zwt_perched(c)) - ! no perched water table drainage if using original formulation - if(origflag == 1) qflx_drain_perched(c) = 0._r8 - ! remove drainage from perched saturated layers rsub_top_tot = - qflx_drain_perched(c) * dtime do k = k_perch+1, k_frz @@ -1164,25 +1142,15 @@ subroutine Drainage(bounds, num_hydrologyc, filter_hydrologyc, num_urbanc, filte icefracsum = icefracsum + icefrac(c,j) * dzmm(c,j) end do ! add ice impedance factor to baseflow - if(origflag == 1) then - if (use_vichydro) then - call endrun(msg="VICHYDRO is not available for origflag=1"//errmsg(sourcefile, __LINE__)) - else - fracice_rsub(c) = max(0._r8,exp(-3._r8*(1._r8-(icefracsum/dzsum))) & - - exp(-3._r8))/(1.0_r8-exp(-3._r8)) - imped=(1._r8 - fracice_rsub(c)) - rsub_top_max = 5.5e-3_r8 - end if + if (use_vichydro) then + imped=10._r8**(-params_inst%e_ice*min(1.0_r8,ice(c,nlayer)/max_moist(c,nlayer))) + dsmax_tmp(c) = Dsmax(c) * dtime/ secspday !mm/day->mm/dtime + rsub_top_max = dsmax_tmp(c) else - if (use_vichydro) then - imped=10._r8**(-params_inst%e_ice*min(1.0_r8,ice(c,nlayer)/max_moist(c,nlayer))) - dsmax_tmp(c) = Dsmax(c) * dtime/ secspday !mm/day->mm/dtime - rsub_top_max = dsmax_tmp(c) - else - imped=10._r8**(-params_inst%e_ice*(icefracsum/dzsum)) - rsub_top_max = 10._r8 * sin((rpi/180.) * col%topo_slope(c)) - end if - endif + imped=10._r8**(-params_inst%e_ice*(icefracsum/dzsum)) + rsub_top_max = 10._r8 * sin((rpi/180.) * col%topo_slope(c)) + end if + if (use_vichydro) then ! ARNO model for the bottom soil layer (based on bottom soil layer ! moisture from previous time step @@ -1560,8 +1528,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) zwt => soilhydrology_inst%zwt_col , & ! Output: [real(r8) (:) ] water table depth (m) zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Output: [real(r8) (:) ] perched water table depth (m) - frost_table => soilhydrology_inst%frost_table_col , & ! Output: [real(r8) (:) ] frost table depth (m) - origflag => soilhydrology_inst%origflag & ! Input: logical + frost_table => soilhydrology_inst%frost_table_col & ! Output: [real(r8) (:) ] frost table depth (m) ) ! calculate perched water table location @@ -1590,8 +1557,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & !======= water table above frost table =================== ! if water table is above frost table, do nothing - if (zwt(c) < frost_table(c) .and. t_soisno(c,k_frz) <= tfrz & - .and. origflag == 0) then + if (zwt(c) < frost_table(c) .and. t_soisno(c,k_frz) <= tfrz) then else if (k_frz > 1) then !========== water table below frost table ============ ! locate perched water table from bottom up starting at diff --git a/src/biogeophys/SoilHydrologyType.F90 b/src/biogeophys/SoilHydrologyType.F90 index 4dfca06811..07ad2ca45b 100644 --- a/src/biogeophys/SoilHydrologyType.F90 +++ b/src/biogeophys/SoilHydrologyType.F90 @@ -19,8 +19,6 @@ Module SoilHydrologyType type, public :: soilhydrology_type integer :: h2osfcflag ! true => surface water is active (namelist) - integer :: origflag ! used to control soil hydrology properties (namelist) - real(r8), pointer :: num_substeps_col (:) ! col adaptive timestep counter ! NON-VIC real(r8), pointer :: frost_table_col (:) ! col frost table depth @@ -28,7 +26,6 @@ Module SoilHydrologyType real(r8), pointer :: zwts_col (:) ! col water table depth, the shallower of the two water depths real(r8), pointer :: zwt_perched_col (:) ! col perched water table depth real(r8), pointer :: qcharge_col (:) ! col aquifer recharge rate (mm/s) - real(r8), pointer :: fracice_col (:,:) ! col fractional impermeability (-) real(r8), pointer :: icefrac_col (:,:) ! col fraction of ice real(r8), pointer :: h2osfc_thresh_col (:) ! col level at which h2osfc "percolates" (time constant) real(r8), pointer :: xs_urban_col (:) ! col excess soil water above urban ponding limit @@ -121,7 +118,6 @@ subroutine InitAllocate(this, bounds) allocate(this%zwts_col (begc:endc)) ; this%zwts_col (:) = nan allocate(this%qcharge_col (begc:endc)) ; this%qcharge_col (:) = nan - allocate(this%fracice_col (begc:endc,nlevgrnd)) ; this%fracice_col (:,:) = nan allocate(this%icefrac_col (begc:endc,nlevgrnd)) ; this%icefrac_col (:,:) = nan allocate(this%h2osfc_thresh_col (begc:endc)) ; this%h2osfc_thresh_col (:) = nan allocate(this%xs_urban_col (begc:endc)) ; this%xs_urban_col (:) = nan @@ -340,16 +336,14 @@ subroutine ReadNL( this, NLFilename ) ! !LOCAL VARIABLES: integer :: ierr ! error code integer :: unitn ! unit for namelist file - integer :: origflag=0 !use to control soil hydraulic properties integer :: h2osfcflag=1 !If surface water is active or not character(len=32) :: subname = 'SoilHydrology_readnl' ! subroutine name !----------------------------------------------------------------------- - namelist / clm_soilhydrology_inparm / h2osfcflag, origflag + namelist / clm_soilhydrology_inparm / h2osfcflag ! preset values - origflag = 0 h2osfcflag = 1 if ( masterproc )then @@ -371,10 +365,8 @@ subroutine ReadNL( this, NLFilename ) end if call shr_mpi_bcast(h2osfcflag, mpicom) - call shr_mpi_bcast(origflag, mpicom) this%h2osfcflag = h2osfcflag - this%origflag = origflag end subroutine ReadNL diff --git a/src/biogeophys/SoilWaterMovementMod.F90 b/src/biogeophys/SoilWaterMovementMod.F90 index 70da14a713..1d990b7f5c 100644 --- a/src/biogeophys/SoilWaterMovementMod.F90 +++ b/src/biogeophys/SoilWaterMovementMod.F90 @@ -575,10 +575,8 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) dz => col%dz , & ! Input: [real(r8) (:,:) ] layer thickness (m) - origflag => soilhydrology_inst%origflag , & ! Input: constant qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) - fracice => soilhydrology_inst%fracice_col , & ! Input: [real(r8) (:,:) ] fractional impermeability (-) icefrac => soilhydrology_inst%icefrac_col , & ! Input: [real(r8) (:,:) ] fraction of ice hkdepth => soilhydrology_inst%hkdepth_col , & ! Input: [real(r8) (:) ] decay factor (m) @@ -720,22 +718,13 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & c = filter_hydrologyc(fc) ! compute hydraulic conductivity based on liquid water content only - if (origflag == 1) then - s1 = 0.5_r8*(h2osoi_vol(c,j) + h2osoi_vol(c,min(nlevsoi, j+1))) / & - (0.5_r8*(watsat(c,j)+watsat(c,min(nlevsoi, j+1)))) - else - s1 = 0.5_r8*(vwc_liq(c,j) + vwc_liq(c,min(nlevsoi, j+1))) / & - (0.5_r8*(watsat(c,j)+watsat(c,min(nlevsoi, j+1)))) - endif + s1 = 0.5_r8*(vwc_liq(c,j) + vwc_liq(c,min(nlevsoi, j+1))) / & + (0.5_r8*(watsat(c,j)+watsat(c,min(nlevsoi, j+1)))) s1 = min(1._r8, s1) s2 = hksat(c,j)*s1**(2._r8*bsw(c,j)+2._r8) - ! replace fracice with impedance factor, as in zhao 97,99 - if (origflag == 1) then - imped(c,j)=(1._r8-0.5_r8*(fracice(c,j)+fracice(c,min(nlevsoi, j+1)))) - else - imped(c,j)=10._r8**(-params_inst%e_ice*(0.5_r8*(icefrac(c,j)+icefrac(c,min(nlevsoi, j+1))))) - endif + imped(c,j)=10._r8**(-params_inst%e_ice*(0.5_r8*(icefrac(c,j)+icefrac(c,min(nlevsoi, j+1))))) + hk(c,j) = imped(c,j)*s1*s2 dhkdw(c,j) = imped(c,j)*(2._r8*bsw(c,j)+3._r8)*s2* & (1._r8/(watsat(c,j)+watsat(c,min(nlevsoi, j+1)))) @@ -751,11 +740,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & ! compute matric potential and derivative based on liquid water content only - if (origflag == 1) then - s_node = max(h2osoi_vol(c,j)/watsat(c,j), 0.01_r8) - else - s_node = max(vwc_liq(c,j)/watsat(c,j), 0.01_r8) - endif + s_node = max(vwc_liq(c,j)/watsat(c,j), 0.01_r8) s_node = min(1.0_r8, s_node) !call soil_water_retention_curve%soil_suction(sucsat(c,j), s_node, bsw(c,j), smp(c,j), dsmpds) @@ -765,11 +750,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & !do not turn on the line below, which will cause bit to bit error, jyt, 2014 Mar 6 !dsmpdw(c,j) = dsmpds/watsat(c,j) - if (origflag == 1) then - dsmpdw(c,j) = -bsw(c,j)*smp(c,j)/(s_node*watsat(c,j)) - else - dsmpdw(c,j) = -bsw(c,j)*smp(c,j)/vwc_liq(c,j) - endif + dsmpdw(c,j) = -bsw(c,j)*smp(c,j)/vwc_liq(c,j) smp_l(c,j) = smp(c,j) hk_l(c,j) = hk(c,j) @@ -861,11 +842,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & else ! water table is below soil column ! compute aquifer soil moisture as average of layer 10 and saturation - if(origflag == 1) then - s_node = max(0.5*(1.0_r8+h2osoi_vol(c,j)/watsat(c,j)), 0.01_r8) - else - s_node = max(0.5*((vwc_zwt(c)+vwc_liq(c,j))/watsat(c,j)), 0.01_r8) - endif + s_node = max(0.5*((vwc_zwt(c)+vwc_liq(c,j))/watsat(c,j)), 0.01_r8) s_node = min(1.0_r8, s_node) ! compute smp for aquifer layer @@ -940,7 +917,7 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & s_node = max(h2osoi_vol(c,jwt(c)+1)/watsat(c,jwt(c)+1), 0.01_r8) s1 = min(1._r8, s_node) - !scs: this is the expression for unsaturated hk + !this is the expression for unsaturated hk ka = imped(c,jwt(c)+1)*hksat(c,jwt(c)+1) & *s1**(2._r8*bsw(c,jwt(c)+1)+3._r8) @@ -953,12 +930,12 @@ subroutine soilwater_zengdecker2009(bounds, num_hydrologyc, filter_hydrologyc, & smp1 = max(smpmin(c), smp(c,max(1,jwt(c)))) wh = smp1 - zq(c,max(1,jwt(c))) - !scs: original formulation + !original formulation if(jwt(c) == 0) then qcharge(c) = -ka * (wh_zwt-wh) /((zwt(c)+1.e-3)*1000._r8) else ! qcharge(c) = -ka * (wh_zwt-wh)/((zwt(c)-z(c,jwt(c)))*1000._r8) - !scs: 1/2, assuming flux is at zwt interface, saturation deeper than zwt + !1/2, assuming flux is at zwt interface, saturation deeper than zwt qcharge(c) = -ka * (wh_zwt-wh)/((zwt(c)-z(c,jwt(c)))*1000._r8*2.0) endif @@ -1494,7 +1471,7 @@ subroutine compute_hydraulic_properties(c, nlayers, & character(len=32) :: subname = 'calculate_hydraulic_properties' ! subroutine name !----------------------------------------------------------------------- -!scs: originally, associate statements selected sections rather than +! originally, associate statements selected sections rather than ! entire arrays, but due to pgi bug, removed array section selections ! using array sections allowed consistent 1d indexing throughout associate(& @@ -1621,7 +1598,7 @@ subroutine compute_moisture_fluxes_and_derivs(c, nlayers, & real(r8) :: num, den ! used in calculating qin, qout real(r8) :: dhkds1, dhkds2 !temporary variable real(r8),parameter :: m_to_mm = 1.e3_r8 !convert meters to mm -!scs: temporarily use local variables for the following + ! temporarily use local variables for the following real(r8) :: vwc_liq_ub ! liquid volumetric water content at upper boundary real(r8) :: vwc_liq_lb ! liquid volumetric water content at lower boundary character(len=32) :: subname = 'calculate_moisture_fluxes_and_derivs' ! subroutine name @@ -1704,12 +1681,11 @@ subroutine compute_moisture_fluxes_and_derivs(c, nlayers, & dhkds1 = 0.5_r8 * dhkdw(j) / watsat(c,j) ! derivative w.r.t. volumetric liquid water in the upper layer dhkds2 = 0.5_r8 * dhkdw(j) / watsat(c,j+1) ! derivative w.r.t. volumetric liquid water in the lower layer -!scs: this is how zd is done + ! this is how zd is done if (zdflag == 1) then dhkds1 = dhkdw(j)/(watsat(c,j)+watsat(c,min(nlevsoi, j+1))) dhkds2 = dhkds1 endif -!scs ! compute flux at the bottom of the j-th layer ! NOTE: hk(j) is hydraulic conductivity at the bottom of the j-th @@ -1739,12 +1715,11 @@ subroutine compute_moisture_fluxes_and_derivs(c, nlayers, & ! layer interface w.r.t relative saturation at the interface dhkds1 = 0.5_r8 * dhkdw(j) / watsat(c,j) ! derivative w.r.t. volumetric liquid water in the upper layer dhkds2 = 0.5_r8 * dhkdw(j) / watsat(c,j+1) ! derivative w.r.t. volumetric liquid water in the lower layer -!scs: this is how zd is done + ! this is how zd is done if (zdflag == 1) then dhkds1 = dhkdw(j)/(watsat(c,j)+watsat(c,min(nlevsoi, j+1))) dhkds2 = dhkds1 endif -!scs ! compute flux at the bottom of the j-th layer ! NOTE: hk(j) is hydraulic conductivity at the bottom of the j-th layer @@ -1801,12 +1776,12 @@ subroutine compute_moisture_fluxes_and_derivs(c, nlayers, & ! condition when the water table is a long way below the soil column dhkds1 = dhkdw(j) / watsat(c,j) -!scs: this is how zd is done + ! this is how zd is done if (zdflag == 1) then dhkds1 = dhkdw(j)/(watsat(c,j)+watsat(c,min(nlevsoi, j+1))) dhkds2 = dhkds1 endif -!scs + ! compute flux num = -smp(j) ! NOTE: assume saturation at water table depth (smp=0) den = m_to_mm * (zwt(c) - z(c,j)) @@ -1824,7 +1799,7 @@ subroutine compute_moisture_fluxes_and_derivs(c, nlayers, & ! compute the relative saturation at the lower boundary s1 = vwc_liq_lb / watsat(c,j) -!scs: mc's original expression s1 = (vwc_liq_lb - watres(c,j)) / (watsat(c,j) - watres(c,j)) + ! mc's original expression s1 = (vwc_liq_lb - watres(c,j)) / (watsat(c,j) - watres(c,j)) s1 = min(s1, 1._r8) s1 = max(0.01_r8, s1) From 602eda03787b552ca0e65c9e3d9bc695e398b754 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 24 May 2022 10:40:17 -0600 Subject: [PATCH 065/153] clean up SoilHydrologyMod --- src/biogeophys/SoilHydrologyMod.F90 | 168 +++++++++++----------------- 1 file changed, 67 insertions(+), 101 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index bc72afbcaa..3dc90245f1 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1489,7 +1489,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! Calculate watertable, considering aquifer recharge but no drainage. ! ! !USES: - use clm_varcon , only : pondmx, tfrz, watmin,denice,denh2o + use clm_varcon , only : tfrz, denice, denh2o use column_varcon , only : icol_roof, icol_road_imperv ! ! !ARGUMENTS: @@ -1501,19 +1501,15 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & type(soilhydrology_type) , intent(inout) :: soilhydrology_inst type(soilstate_type) , intent(in) :: soilstate_inst type(temperature_type) , intent(in) :: temperature_inst - type(waterstatebulk_type) , intent(inout) :: waterstatebulk_inst - type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst + type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst + type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst ! ! !LOCAL VARIABLES: - integer :: c,j,fc,i ! indices - real(r8) :: s_y - integer :: k,k_frz,k_perch,k_zwt - real(r8) :: sat_lev - real(r8) :: s1 - real(r8) :: s2 - real(r8) :: m - real(r8) :: b - integer :: sat_flag + integer :: c,j,fc,i ! indices + integer :: k,k_frz,k_perch,k_zwt ! indices + real(r8) :: s1, s2 ! temporary moisture values + real(r8) :: m, b ! slope and intercept + real(r8), parameter :: sat_lev = 0.9 ! saturation value used to identify saturated layers !----------------------------------------------------------------------- associate( & @@ -1564,8 +1560,6 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! frost table sat_lev is an arbitrary saturation level ! used to determine perched water table - sat_lev = 0.9 - k_perch=1 do k=k_frz,1,-1 h2osoi_vol(c,k) = h2osoi_liq(c,k)/(dz(c,k)*denh2o) & @@ -1870,7 +1864,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & s_y = watsat(c,k) & * ( 1. - (1.+1.e3*zwt_perched(c)/sucsat(c,k))**(-1./bsw(c,k))) s_y=max(s_y,params_inst%aq_sp_yield_min) - if (k== k_perch(c)) then + if (k==k_perch(c)) then drainage_layer=min(drainage_tot,(s_y*(zi(c,k) - zwt_perched(c))*1.e3)) else drainage_layer=min(drainage_tot,(s_y*(dz(c,k))*1.e3)) @@ -2001,12 +1995,11 @@ subroutine SubsurfaceLateralFlow(bounds, & ! !USES: use clm_time_manager , only : get_step_size use clm_varpar , only : nlevsoi, nlevgrnd, nlayer, nlayert - use clm_varcon , only : pondmx, watmin,rpi, secspday, nlvic - use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv + use clm_varcon , only : pondmx, watmin,rpi, secspday + use column_varcon , only : icol_road_perv use abortutils , only : endrun use GridcellType , only : grc use landunit_varcon , only : istsoil, istcrop - use clm_time_manager , only : get_nstep use clm_varctl , only : use_hillslope_routing use HillslopeHydrologyMod, only : head_gradient_method, transmissivity_method use HillslopeHydrologyMod, only : kinematic,darcy,uniform_transmissivity,layersum @@ -2027,54 +2020,36 @@ subroutine SubsurfaceLateralFlow(bounds, & ! ! !LOCAL VARIABLES: character(len=32) :: subname = 'SubsurfaceLateralFlow' ! subroutine name - integer :: c,j,fc,i ! indices + integer :: c,j,fc,i,l,g ! indices real(r8) :: dtime ! land model time step (sec) real(r8) :: xs(bounds%begc:bounds%endc) ! water needed to bring soil moisture to watmin (mm) real(r8) :: dzmm(bounds%begc:bounds%endc,1:nlevsoi) ! layer thickness (mm) integer :: jwt(bounds%begc:bounds%endc) ! index of the soil layer right above the water table (-) - real(r8) :: rsub_top(bounds%begc:bounds%endc) ! subsurface runoff - topographic control (mm/s) + real(r8) :: drainage(bounds%begc:bounds%endc) ! subsurface drainage (mm/s) real(r8) :: xsi(bounds%begc:bounds%endc) ! excess soil water above saturation at layer i (mm) - real(r8) :: xsia(bounds%begc:bounds%endc) ! available pore space at layer i (mm) real(r8) :: xs1(bounds%begc:bounds%endc) ! excess soil water above saturation at layer 1 (mm) - real(r8) :: smpfz(1:nlevsoi) ! matric potential of layer right above water table (mm) - real(r8) :: wtsub ! summation of hk*dzmm for layers below water table (mm**2/s) real(r8) :: dzsum ! summation of dzmm of layers below water table (mm) real(r8) :: icefracsum ! summation of icefrac*dzmm of layers below water table (-) real(r8) :: ice_imped_col(bounds%begc:bounds%endc) ! column average hydraulic conductivity reduction due to presence of soil ice (-) - real(r8) :: ice_imped(bounds%begc:bounds%endc,1:nlevsoi) ! hydraulic conductivity reduction due to presence of soil ice (-) + real(r8) :: ice_imped(bounds%begc:bounds%endc,1:nlevsoi) ! hydraulic conductivity reduction due to presence of soil ice (-) real(r8) :: available_h2osoi_liq ! available soil liquid water in a layer - real(r8) :: h2osoi_vol - real(r8) :: rsub_top_tot - real(r8) :: rsub_top_layer - real(r8) :: theta_unsat - real(r8) :: f_unsat - real(r8) :: s_y - integer :: k - real(r8) :: s1 - real(r8) :: s2 - real(r8) :: m - real(r8) :: b - real(r8) :: vol_ice - real(r8) :: dsmax_tmp(bounds%begc:bounds%endc) ! temporary variable for ARNO subsurface runoff calculation - real(r8) :: rsub_tmp ! temporary variable for ARNO subsurface runoff calculation - real(r8) :: frac ! temporary variable for ARNO subsurface runoff calculation - real(r8) :: rel_moist ! relative moisture, temporary variable - real(r8) :: wtsub_vic ! summation of hk*dzmm for layers in the third VIC layer - integer :: g - - logical :: no_lateral_flow = .false. - real(r8) :: transmis ! transmissivity - real(r8) :: dgrad ! hydraulic head gradient - real(r8) :: stream_water_depth ! depth of water in stream channel - real(r8) :: stream_channel_depth ! depth of stream channel + real(r8) :: h2osoi_vol ! volumetric water content (mm3/mm3) + real(r8) :: drainage_tot ! total drainage to be removed from column (mm) + real(r8) :: drainage_layer ! drainage to be removed from current layer (mm) + real(r8) :: s_y ! specific yield (unitless) + real(r8) :: vol_ice ! volumetric ice content (mm3/mm3) + logical :: no_lateral_flow = .false. ! flag for testing + real(r8) :: transmis ! transmissivity (m2/s) + real(r8) :: head_gradient ! hydraulic head gradient (m/m) + real(r8) :: stream_water_depth ! depth of water in stream channel (m) + real(r8) :: stream_channel_depth ! depth of stream channel (m) real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 1._r8 ! anisotropy scalar - real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) - real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) - real(r8) :: qflx_latflow_avg(bounds%begc:bounds%endc) - real(r8) :: larea - integer :: c0, c_src, c_dst, nstep - integer :: l + real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) ! volumetric lateral flow (m3/s) + real(r8) :: qflx_net_latflow(bounds%begc:bounds%endc) ! net lateral flow in column (mm/s) + real(r8) :: qflx_latflow_avg(bounds%begc:bounds%endc) ! average lateral flow (mm/s) + real(r8) :: larea ! area of hillslope in landunit + integer :: c0, c_src, c_dst ! indices !----------------------------------------------------------------------- @@ -2099,14 +2074,7 @@ subroutine SubsurfaceLateralFlow(bounds, & tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth - c_param => soilhydrology_inst%c_param_col , & ! Input: [real(r8) (:) ] baseflow exponent (Qb) - Dsmax => soilhydrology_inst%dsmax_col , & ! Input: [real(r8) (:) ] max. velocity of baseflow (mm/day) - max_moist => soilhydrology_inst%max_moist_col , & ! Input: [real(r8) (:,:) ] maximum soil moisture (ice + liq) - moist => soilhydrology_inst%moist_col , & ! Input: [real(r8) (:,:) ] soil layer moisture (mm) - Ds => soilhydrology_inst%ds_col , & ! Input: [real(r8) (:) ] fracton of Dsmax where non-linear baseflow begins - Wsvic => soilhydrology_inst%Wsvic_col , & ! Input: [real(r8) (:) ] fraction of maximum soil moisutre where non-liear base flow occurs icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] fraction of ice in layer - frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) @@ -2122,7 +2090,6 @@ subroutine SubsurfaceLateralFlow(bounds, & ! Get time step dtime = get_step_size_real() - nstep = get_nstep() ! Convert layer thicknesses from m to mm @@ -2143,7 +2110,7 @@ subroutine SubsurfaceLateralFlow(bounds, & c = filter_hydrologyc(fc) qflx_drain(c) = 0._r8 qflx_rsub_sat(c) = 0._r8 - rsub_top(c) = 0._r8 + drainage(c) = 0._r8 qflx_latflow_in(c) = 0._r8 qflx_latflow_out(c) = 0._r8 qflx_net_latflow(c) = 0._r8 @@ -2187,15 +2154,15 @@ subroutine SubsurfaceLateralFlow(bounds, & ! kinematic wave approximation if (head_gradient_method == kinematic) then - dgrad = col%hill_slope(c) + head_gradient = col%hill_slope(c) endif ! darcy's law if (head_gradient_method == darcy) then if (col%cold(c) /= ispval) then - dgrad = (col%hill_elev(c)-zwt(c)) & + head_gradient = (col%hill_elev(c)-zwt(c)) & - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) - dgrad = dgrad / (col%hill_distance(c) - col%hill_distance(col%cold(c))) + head_gradient = head_gradient / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else if(use_hillslope_routing) then stream_water_depth = stream_water_volume(l) & @@ -2208,33 +2175,32 @@ subroutine SubsurfaceLateralFlow(bounds, & ! flow between channel and lowest column ! bankfull height is defined to be zero - dgrad = (col%hill_elev(c)-zwt(c)) & + head_gradient = (col%hill_elev(c)-zwt(c)) & ! ignore overbankfull storage - min((stream_water_depth - stream_channel_depth),0._r8) - dgrad = dgrad / (col%hill_distance(c)) - ! dgrad cannot be negative when channel is empty + head_gradient = head_gradient / (col%hill_distance(c)) + ! head_gradient cannot be negative when channel is empty if (stream_water_depth <= 0._r8) then - dgrad = max(dgrad, 0._r8) + head_gradient = max(head_gradient, 0._r8) endif ! add vertical drainage for losing streams ! (this could be a separate term from lateral flow...) - if (dgrad < 0._r8) then - ! dgrad = dgrad - 1._r8 + if (head_gradient < 0._r8) then + ! head_gradient = head_gradient - 1._r8 ! adjust lateral gradient w/ k_anisotropic - dgrad = dgrad - 1._r8/k_anisotropic + head_gradient = head_gradient - 1._r8/k_anisotropic endif endif end if - !scs: in cases of bad data, where hand differences in - ! adjacent bins are very large, cap maximum dgrad + ! adjacent bins are very large, cap maximum head_gradient ! should a warning be used instead? - dgrad = min(max(dgrad,-2._r8),2._r8) + head_gradient = min(max(head_gradient,-2._r8),2._r8) ! Calculate transmissivity of source column - if (dgrad >= 0._r8) then + if (head_gradient >= 0._r8) then c_src = c else c_src = col%cold(c) @@ -2283,9 +2249,9 @@ subroutine SubsurfaceLateralFlow(bounds, & ! transmissivity to determine whether saturated flow ! conditions exist, b/c gradients will be nonzero ! even when no saturated layers are present - ! qflx_latflow_out_vol(c) = ice_imped(c)*transmis*col%hill_width(c)*dgrad + ! qflx_latflow_out_vol(c) = ice_imped(c)*transmis*col%hill_width(c)*head_gradient ! include ice impedance in transmissivity - qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*dgrad + qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*head_gradient ! qdischarge from lowest column is qflx_latflow_out_vol ! scaled by total area of column in gridcell divided by column area @@ -2361,30 +2327,30 @@ subroutine SubsurfaceLateralFlow(bounds, & ! baseflow if(zwt(c) <= zi(c,nbedrock(c))) then ! apply net lateral flow here - rsub_top(c) = qflx_net_latflow(c) + drainage(c) = qflx_net_latflow(c) else - rsub_top(c) = 0._r8 + drainage(c) = 0._r8 endif - !-- Now remove water via rsub_top - rsub_top_tot = - rsub_top(c) * dtime + !-- Now remove water via drainage + drainage_tot = - drainage(c) * dtime - if(rsub_top_tot > 0.) then !rising water table + if(drainage_tot > 0.) then !rising water table do j = jwt(c)+1,1,-1 ! analytical expression for specific yield s_y = watsat(c,j) & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) s_y=max(s_y,params_inst%aq_sp_yield_min) - rsub_top_layer=min(rsub_top_tot,(s_y*dz(c,j)*1.e3)) + drainage_layer=min(drainage_tot,(s_y*dz(c,j)*1.e3)) - rsub_top_layer=max(rsub_top_layer,0._r8) - h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer + drainage_layer=max(drainage_layer,0._r8) + h2osoi_liq(c,j) = h2osoi_liq(c,j) + drainage_layer - rsub_top_tot = rsub_top_tot - rsub_top_layer + drainage_tot = drainage_tot - drainage_layer - if (rsub_top_tot <= 0.) then - zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 + if (drainage_tot <= 0.) then + zwt(c) = zwt(c) - drainage_layer/s_y/1000._r8 exit else zwt(c) = zi(c,j-1) @@ -2392,8 +2358,8 @@ subroutine SubsurfaceLateralFlow(bounds, & enddo - !-- remove residual rsub_top -------------------------------- - h2osfc(c) = h2osfc(c) + rsub_top_tot + !-- remove residual drainage -------------------------------- + h2osfc(c) = h2osfc(c) + drainage_tot else ! deepening water table do j = jwt(c)+1, nbedrock(c) @@ -2402,23 +2368,23 @@ subroutine SubsurfaceLateralFlow(bounds, & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) s_y=max(s_y,params_inst%aq_sp_yield_min) - rsub_top_layer=max(rsub_top_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) - rsub_top_layer=min(rsub_top_layer,0._r8) - h2osoi_liq(c,j) = h2osoi_liq(c,j) + rsub_top_layer + drainage_layer=max(drainage_tot,-(s_y*(zi(c,j) - zwt(c))*1.e3)) + drainage_layer=min(drainage_layer,0._r8) + h2osoi_liq(c,j) = h2osoi_liq(c,j) + drainage_layer - rsub_top_tot = rsub_top_tot - rsub_top_layer + drainage_tot = drainage_tot - drainage_layer - if (rsub_top_tot >= 0.) then - zwt(c) = zwt(c) - rsub_top_layer/s_y/1000._r8 + if (drainage_tot >= 0.) then + zwt(c) = zwt(c) - drainage_layer/s_y/1000._r8 exit else zwt(c) = zi(c,j) endif enddo - !-- remove residual rsub_top ----------------------- + !-- remove residual drainage ----------------------- ! make sure no extra water removed from soil column - rsub_top(c) = rsub_top(c) + rsub_top_tot/dtime + drainage(c) = drainage(c) + drainage_tot/dtime endif zwt(c) = max(0.0_r8,zwt(c)) @@ -2515,7 +2481,7 @@ subroutine SubsurfaceLateralFlow(bounds, & c = filter_hydrologyc(fc) ! Sub-surface runoff and drainage - qflx_drain(c) = qflx_rsub_sat(c) + rsub_top(c) + qflx_drain(c) = qflx_rsub_sat(c) + drainage(c) ! Set imbalance for snow capping From 4095d6c00707004ae3c3eaa05ef626ef84605c2f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 24 May 2022 11:18:29 -0600 Subject: [PATCH 066/153] remove hill_pftndx from column type --- src/biogeophys/HillslopeHydrologyMod.F90 | 23 ++++++++++++++++------- src/main/ColumnType.F90 | 5 +---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index bac73ca214..9f03b01d66 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -167,6 +167,7 @@ subroutine InitHillslope(bounds,fsurdat) integer, allocatable :: col_ndx(:,:) ! column index integer, allocatable :: col_dndx(:,:) ! downhill column index integer, allocatable :: hill_pftndx(:,:) ! hillslope pft index [] + integer, allocatable :: col_pftndx(:) ! hillslope column pft index [] real(r8), pointer :: fhillslope_in(:,:) ! read in - float real(r8), allocatable :: pct_hillslope(:,:) ! percent of landunit occupied by hillslope real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] @@ -212,6 +213,7 @@ subroutine InitHillslope(bounds,fsurdat) hill_length (bounds%begl:bounds%endl,max_columns_hillslope), & hill_width (bounds%begl:bounds%endl,max_columns_hillslope), & hill_height (bounds%begl:bounds%endl,max_columns_hillslope), & + col_pftndx (bounds%begc:bounds%endc), & stat=ierr) allocate(ncolumns_hillslope_in(bounds%begg:bounds%endg)) @@ -496,8 +498,9 @@ subroutine InitHillslope(bounds,fsurdat) end if endif - if ( allocated(hill_pftndx) ) & - col%hill_pftndx(c) = hill_pftndx(l,ci) + if ( allocated(hill_pftndx) ) then + col_pftndx(c) = hill_pftndx(l,ci) + endif enddo @@ -577,7 +580,7 @@ subroutine InitHillslope(bounds,fsurdat) col%wtlunit(c) = (col%hill_area(c)/hillslope_area(nh)) & * (pct_hillslope(l,nh)*0.01_r8) else - ! do not reweight if no input hillslope data + ! do not reweight if column is not a hillslope column !col%wtlunit(c) = 0._r8 endif check_weight = check_weight + col%wtlunit(c) @@ -587,6 +590,9 @@ subroutine InitHillslope(bounds,fsurdat) write(iulog,*) 'weights: ', col%wtlunit(lun%coli(l):lun%colf(l)) write(iulog,*) 'location: ',grc%londeg(g),grc%latdeg(g) write(iulog,*) ' ' + if (masterproc) then + call endrun( 'ERROR:: column weights do not sum to 1.'//errmsg(sourcefile, __LINE__) ) + end if endif endif enddo @@ -606,8 +612,10 @@ subroutine InitHillslope(bounds,fsurdat) endif if ( allocated(hill_pftndx) ) then deallocate(hill_pftndx) - call HillslopePftFromFile(bounds) + + call HillslopePftFromFile(bounds,col_pftndx) + deallocate(col_pftndx) else ! Modify pft distributions ! this may require modifying subgridMod/natveg_patch_exists @@ -943,7 +951,7 @@ subroutine HillslopeDominantLowlandPft(bounds) end subroutine HillslopeDominantLowlandPft !------------------------------------------------------------------------ - subroutine HillslopePftFromFile(bounds) + subroutine HillslopePftFromFile(bounds,col_pftndx) ! ! !DESCRIPTION: ! Reassign patch weights using indices from surface data file @@ -960,6 +968,7 @@ subroutine HillslopePftFromFile(bounds) ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds + integer, intent(in) :: col_pftndx(:) ! ! !LOCAL VARIABLES: integer :: nc,p,pc,l,c ! indices @@ -977,7 +986,7 @@ subroutine HillslopePftFromFile(bounds) ! find patch index of specified vegetation type pc = ispval do p = col%patchi(c), col%patchf(c) - if(patch%itype(p) == col%hill_pftndx(c)) pc = p + if(patch%itype(p) == col_pftndx(c)) pc = p enddo ! only reweight if pft exist within column @@ -995,7 +1004,7 @@ subroutine HillslopePftFromFile(bounds) patch%wtgcell(pc) = sum_wtgrc else - write(iulog,*) 'no pft in column ',c, col%hill_pftndx(c) + write(iulog,*) 'no pft in column ',c, col_pftndx(c) write(iulog,*) 'pfts ',c,patch%itype(col%patchi(c):col%patchf(c)) write(iulog,*) 'weights ',c,patch%wtcol(col%patchi(c):col%patchf(c)) write(iulog,*) 'location ',c,grc%londeg(col%gridcell(c)),grc%latdeg(col%gridcell(c)) diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 819d0fe79f..2295f9c091 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -73,7 +73,6 @@ module ColumnType integer, pointer :: colu (:) ! column index of uphill column (hillslope hydrology) integer, pointer :: cold (:) ! column index of downhill column (hillslope hydrology) integer, pointer :: hillslope_ndx (:) ! hillslope identifier - integer, pointer :: hill_pftndx (:) ! specified (single) pft index of column real(r8), pointer :: hill_elev (:) ! mean elevation of column relative to mean gridcell elevation (m) real(r8), pointer :: hill_slope (:) ! mean along-hill slope (m/m) real(r8), pointer :: hill_area (:) ! mean surface area (m2) @@ -147,7 +146,6 @@ subroutine Init(this, begc, endc) allocate(this%colu (begc:endc)) ; this%colu (:) = ispval allocate(this%cold (begc:endc)) ; this%cold (:) = ispval allocate(this%hillslope_ndx(begc:endc)) ; this%hillslope_ndx (:) = ispval - allocate(this%hill_pftndx(begc:endc)) ; this%hill_pftndx (:) = ispval allocate(this%hill_elev(begc:endc)) ; this%hill_elev (:) = spval allocate(this%hill_slope(begc:endc)) ; this%hill_slope (:) = spval allocate(this%hill_area(begc:endc)) ; this%hill_area (:) = spval @@ -203,14 +201,13 @@ subroutine Clean(this) deallocate(this%colu ) deallocate(this%cold ) deallocate(this%hillslope_ndx) - deallocate(this%hill_pftndx ) deallocate(this%hill_elev ) deallocate(this%hill_slope ) deallocate(this%hill_area ) deallocate(this%hill_width ) deallocate(this%hill_distance) deallocate(this%hill_aspect ) - deallocate(this%urbpoi ) + deallocate(this%urbpoi ) end subroutine Clean !----------------------------------------------------------------------- From 286edbe824459d6f96912a1a8d679a6b20fe9295 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 24 May 2022 11:30:32 -0600 Subject: [PATCH 067/153] add endrun for streamflow_method --- src/biogeophys/HillslopeHydrologyMod.F90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 9f03b01d66..77fb6e0ef0 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -1067,7 +1067,7 @@ subroutine HillslopeStreamOutflow(bounds, & do l = bounds%begl,bounds%endl qstreamflow(l) = 0._r8 - if(lun%itype(l) == istsoil) then + if(lun%itype(l) == istsoil .and. lun%active(l)) then ! Streamflow calculated from Manning equation if(streamflow_method == streamflow_manning) then cross_sectional_area = stream_water_volume(l) & @@ -1106,6 +1106,10 @@ subroutine HillslopeStreamOutflow(bounds, & qstreamflow(l) = max(0._r8,min(qstreamflow(l),stream_water_volume(l)/dtime)) endif + else + if (masterproc) then + call endrun( 'ERROR:: invalid streamflow_method'//errmsg(sourcefile, __LINE__) ) + end if endif endif ! end of istsoil enddo ! end of loop over landunits From 71083f4092eed31a209cb1bde93e4df906c5fd37 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 25 May 2022 07:36:44 -0600 Subject: [PATCH 068/153] add downscaling identifiers to variables --- src/biogeochem/DryDepVelocity.F90 | 4 +- src/biogeochem/VOCEmissionMod.F90 | 4 +- src/biogeophys/BalanceCheckMod.F90 | 6 +- src/biogeophys/SurfaceRadiationMod.F90 | 8 +-- src/biogeophys/UrbanRadiationMod.F90 | 4 +- src/cpl/lilac/lnd_import_export.F90 | 4 +- src/cpl/mct/lnd_import_export.F90 | 4 +- src/cpl/nuopc/lnd_import_export.F90 | 4 +- src/cpl/utils/lnd_import_export_utils.F90 | 11 ++-- src/main/atm2lndMod.F90 | 27 +++++---- src/main/atm2lndType.F90 | 73 ++++++++++------------- src/utils/clmfates_interfaceMod.F90 | 2 +- 12 files changed, 73 insertions(+), 78 deletions(-) diff --git a/src/biogeochem/DryDepVelocity.F90 b/src/biogeochem/DryDepVelocity.F90 index 7646699ffa..f18ae31b2a 100644 --- a/src/biogeochem/DryDepVelocity.F90 +++ b/src/biogeochem/DryDepVelocity.F90 @@ -282,7 +282,7 @@ subroutine depvel_compute( bounds, & associate( & forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) - forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) + forc_solad => atm2lnd_inst%forc_solad_downscaled_col, & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) forc_t => atm2lnd_inst%forc_t_downscaled_col , & ! Input: [real(r8) (:) ] downscaled atmospheric temperature (Kelvin) forc_q => wateratm2lndbulk_inst%forc_q_downscaled_col , & ! Input: [real(r8) (:) ] downscaled atmospheric specific humidity (kg/kg) forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] downscaled surface pressure (Pa) @@ -321,7 +321,7 @@ subroutine depvel_compute( bounds, & spec_hum = forc_q(c) rain = forc_rain(c) sfc_temp = forc_t(c) - solar_flux = forc_solad(g,1) + solar_flux = forc_solad(c,1) lat = grc%latdeg(g) lon = grc%londeg(g) clmveg = patch%itype(pi) diff --git a/src/biogeochem/VOCEmissionMod.F90 b/src/biogeochem/VOCEmissionMod.F90 index 88ae7c08cc..44aff57280 100644 --- a/src/biogeochem/VOCEmissionMod.F90 +++ b/src/biogeochem/VOCEmissionMod.F90 @@ -480,7 +480,7 @@ subroutine VOCEmission (bounds, num_soilp, filter_soilp, & !h2osoi_vol => waterstate_inst%h2osoi_vol_col , & ! Input: [real(r8) (:,:) ] volumetric soil water (m3/m3) !h2osoi_ice => waterstate_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice soil content (kg/m3) - forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) + forc_solad => atm2lnd_inst%forc_solad_downscaled_col, & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (visible only) forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] downscaled atmospheric pressure (Pa) forc_pco2 => atm2lnd_inst%forc_pco2_grc , & ! Input: [real(r8) (:) ] partial pressure co2 (Pa) @@ -552,7 +552,7 @@ subroutine VOCEmission (bounds, num_soilp, filter_soilp, & ! Calculate PAR: multiply w/m2 by 4.6 to get umol/m2/s for par (added 8/14/02) !------------------------ ! SUN: - par_sun = (forc_solad(g,1) + fsun(p) * forc_solai(g,1)) * 4.6_r8 + par_sun = (forc_solad(c,1) + fsun(p) * forc_solai(g,1)) * 4.6_r8 par24_sun = (forc_solad24(p) + fsun24(p) * forc_solai24(p)) * 4.6_r8 par240_sun = (forc_solad240(p) + fsun240(p) * forc_solai240(p)) * 4.6_r8 diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 7f1cf7d6d1..cdf97d198a 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -514,9 +514,9 @@ subroutine BalanceCheck( bounds, & !----------------------------------------------------------------------- associate( & - forc_solad_col => atm2lnd_inst%forc_solad_col , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) - forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) - forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (vis=forc_solsd, nir=forc_solld) + forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) + forc_solad => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) + forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (vis=forc_solsd, nir=forc_solld) forc_rain => wateratm2lnd_inst%forc_rain_downscaled_col , & ! Input: [real(r8) (:) ] column level rain rate [mm/s] forc_rain_grc => wateratm2lnd_inst%forc_rain_not_downscaled_grc, & ! Input: [real(r8) (:) ] grid cell-level rain rate [mm/s] forc_snow => wateratm2lnd_inst%forc_snow_downscaled_col , & ! Input: [real(r8) (:) ] column level snow rate [mm/s] diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index 4168fb60a5..9dfc59858c 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -391,8 +391,8 @@ subroutine CanopySunShadeFracs(filter_nourbanp, num_nourbanp, & associate( tlai_z => surfalb_inst%tlai_z_patch, & ! tlai increment for canopy layer fsun_z => surfalb_inst%fsun_z_patch, & ! sunlit fraction of canopy layer elai => canopystate_inst%elai_patch, & ! one-sided leaf area index - forc_solad => atm2lnd_inst%forc_solad_grc, & ! direct beam radiation (W/m**2) - forc_solad_col => atm2lnd_inst%forc_solad_col, & ! direct beam radiation (W/m**2) + forc_solad => atm2lnd_inst%forc_solad_not_downscaled_grc, & ! direct beam radiation, gridcell (W/m**2) + forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col, & ! direct beam radiation, column (W/m**2) forc_solai => atm2lnd_inst%forc_solai_grc, & ! diffuse radiation (W/m**2) fabd_sun_z => surfalb_inst%fabd_sun_z_patch, & ! absorbed sunlit leaf direct PAR fabd_sha_z => surfalb_inst%fabd_sha_z_patch, & ! absorbed shaded leaf direct PAR @@ -537,8 +537,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & associate( & snl => col%snl , & ! Input: [integer (:) ] negative number of snow layers [nbr] - forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (W/m**2) - forc_solad_col => atm2lnd_inst%forc_solad_col , & ! Input: [real(r8) (:,:) ] direct beam radiation (W/m**2) + forc_solad => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation, gridcell (W/m**2) + forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col , & ! Input: [real(r8) (:,:) ] direct beam radiation, column (W/m**2) forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (W/m**2) snow_depth => waterdiagnosticbulk_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m) diff --git a/src/biogeophys/UrbanRadiationMod.F90 b/src/biogeophys/UrbanRadiationMod.F90 index 0b6412f2d2..ccb3f196b7 100644 --- a/src/biogeophys/UrbanRadiationMod.F90 +++ b/src/biogeophys/UrbanRadiationMod.F90 @@ -117,9 +117,9 @@ subroutine UrbanRadiation (bounds , & canyon_hwr => lun%canyon_hwr , & ! Input: [real(r8) (:) ] ratio of building height to street width wtroad_perv => lun%wtroad_perv , & ! Input: [real(r8) (:) ] weight of pervious road wrt total road - forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) (W/m**2) + forc_solad => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (vis=forc_sols , nir=forc_soll ) (W/m**2) forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse beam radiation (vis=forc_sols , nir=forc_soll ) (W/m**2) - forc_solar => atm2lnd_inst%forc_solar_grc , & ! Input: [real(r8) (:) ] incident solar radiation (W/m**2) + forc_solar => atm2lnd_inst%forc_solar_not_downscaled_grc , & ! Input: [real(r8) (:) ] incident solar radiation (W/m**2) forc_lwrad => atm2lnd_inst%forc_lwrad_not_downscaled_grc , & ! Input: [real(r8) (:) ] downward infrared (longwave) radiation (W/m**2) frac_sno => waterdiagnosticbulk_inst%frac_sno_col , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1) diff --git a/src/cpl/lilac/lnd_import_export.F90 b/src/cpl/lilac/lnd_import_export.F90 index 32d1bace46..27331a56c2 100644 --- a/src/cpl/lilac/lnd_import_export.F90 +++ b/src/cpl/lilac/lnd_import_export.F90 @@ -153,11 +153,11 @@ subroutine import_fields( importState, bounds, first_call, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getimport(importState, 'c2l_fb_atm', 'Faxa_swvdr', bounds, & - output=atm2lnd_inst%forc_solad_grc(:,1), rc=rc) + output=atm2lnd_inst%forc_solad_not_downscaled_grc(:,1), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getimport(importState, 'c2l_fb_atm', 'Faxa_swndr', bounds, & - output=atm2lnd_inst%forc_solad_grc(:,2), rc=rc) + output=atm2lnd_inst%forc_solad_not_downscaled_grc(:,2), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getimport(importState, 'c2l_fb_atm', 'Faxa_swvdf', bounds, & diff --git a/src/cpl/mct/lnd_import_export.F90 b/src/cpl/mct/lnd_import_export.F90 index d491ca6a8d..f58f7ad0c8 100644 --- a/src/cpl/mct/lnd_import_export.F90 +++ b/src/cpl/mct/lnd_import_export.F90 @@ -97,8 +97,8 @@ subroutine lnd_import( bounds, x2l, glc_present, atm2lnd_inst, glc2lnd_inst, wat atm2lnd_inst%forc_topo_grc(g) = x2l(index_x2l_Sa_topo,i) ! Atm surface height (m) atm2lnd_inst%forc_u_grc(g) = x2l(index_x2l_Sa_u,i) ! forc_uxy Atm state m/s atm2lnd_inst%forc_v_grc(g) = x2l(index_x2l_Sa_v,i) ! forc_vxy Atm state m/s - atm2lnd_inst%forc_solad_grc(g,2) = x2l(index_x2l_Faxa_swndr,i) ! forc_sollxy Atm flux W/m^2 - atm2lnd_inst%forc_solad_grc(g,1) = x2l(index_x2l_Faxa_swvdr,i) ! forc_solsxy Atm flux W/m^2 + atm2lnd_inst%forc_solad_not_downscaled_grc(g,2) = x2l(index_x2l_Faxa_swndr,i) ! forc_sollxy Atm flux W/m^2 + atm2lnd_inst%forc_solad_not_downscaled_grc(g,1) = x2l(index_x2l_Faxa_swvdr,i) ! forc_solsxy Atm flux W/m^2 atm2lnd_inst%forc_solai_grc(g,2) = x2l(index_x2l_Faxa_swndf,i) ! forc_solldxy Atm flux W/m^2 atm2lnd_inst%forc_solai_grc(g,1) = x2l(index_x2l_Faxa_swvdf,i) ! forc_solsdxy Atm flux W/m^2 diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index f1d5df0f7e..92ebfd87b4 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -548,9 +548,9 @@ subroutine import_fields( gcomp, bounds, glc_present, rof_prognostic, & if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getimport_1d(importState, Faxa_lwdn , atm2lnd_inst%forc_lwrad_not_downscaled_grc(begg:), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call state_getimport_1d(importState, Faxa_swvdr, atm2lnd_inst%forc_solad_grc(begg:,1), rc=rc) + call state_getimport_1d(importState, Faxa_swvdr, atm2lnd_inst%forc_solad_not_downscaled_grc(begg:,1), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call state_getimport_1d(importState, Faxa_swndr, atm2lnd_inst%forc_solad_grc(begg:,2), rc=rc) + call state_getimport_1d(importState, Faxa_swndr, atm2lnd_inst%forc_solad_not_downscaled_grc(begg:,2), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getimport_1d(importState, Faxa_swvdf, atm2lnd_inst%forc_solai_grc(begg:,1), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/src/cpl/utils/lnd_import_export_utils.F90 b/src/cpl/utils/lnd_import_export_utils.F90 index 032cb19b6f..5a459d1ddd 100644 --- a/src/cpl/utils/lnd_import_export_utils.F90 +++ b/src/cpl/utils/lnd_import_export_utils.F90 @@ -76,8 +76,11 @@ subroutine derive_quantities( bounds, atm2lnd_inst, wateratm2lndbulk_inst, & atm2lnd_inst%forc_wind_grc(g) = sqrt(atm2lnd_inst%forc_u_grc(g)**2 + atm2lnd_inst%forc_v_grc(g)**2) - atm2lnd_inst%forc_solar_grc(g) = atm2lnd_inst%forc_solad_grc(g,1) + atm2lnd_inst%forc_solai_grc(g,1) + & - atm2lnd_inst%forc_solad_grc(g,2) + atm2lnd_inst%forc_solai_grc(g,2) + atm2lnd_inst%forc_solar_not_downscaled_grc(g) = & + atm2lnd_inst%forc_solad_not_downscaled_grc(g,1) & + + atm2lnd_inst%forc_solai_grc(g,1) & + + atm2lnd_inst%forc_solad_not_downscaled_grc(g,2) & + + atm2lnd_inst%forc_solai_grc(g,2) wateratm2lndbulk_inst%forc_rain_not_downscaled_grc(g) = forc_rainc(g) + forc_rainl(g) wateratm2lndbulk_inst%forc_snow_not_downscaled_grc(g) = forc_snowc(g) + forc_snowl(g) @@ -118,8 +121,8 @@ subroutine check_for_errors( bounds, atm2lnd_inst, wateratm2lndbulk_inst ) call shr_sys_abort( subname//& ' ERROR: Longwave down sent from the atmosphere model is negative or zero' ) end if - if ( (atm2lnd_inst%forc_solad_grc(g,1) < 0.0_r8) .or. & - (atm2lnd_inst%forc_solad_grc(g,2) < 0.0_r8) .or. & + if ( (atm2lnd_inst%forc_solad_not_downscaled_grc(g,1) < 0.0_r8) .or. & + (atm2lnd_inst%forc_solad_not_downscaled_grc(g,2) < 0.0_r8) .or. & (atm2lnd_inst%forc_solai_grc(g,1) < 0.0_r8) .or. & (atm2lnd_inst%forc_solai_grc(g,2) < 0.0_r8) ) then call shr_sys_abort( subname//& diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 933668a7e9..487e342230 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -162,7 +162,8 @@ subroutine downscale_forcings(bounds, & forc_q_g => wateratm2lndbulk_inst%forc_q_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric specific humidity (kg/kg) forc_pbot_g => atm2lnd_inst%forc_pbot_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric pressure (Pa) forc_rho_g => atm2lnd_inst%forc_rho_not_downscaled_grc , & ! Input: [real(r8) (:)] atmospheric density (kg/m**3) - forc_solad_g => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation + forc_solad_g => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation + forc_solar_g => atm2lnd_inst%forc_solar_not_downscaled_grc, & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation ! Column-level downscaled fields: forc_rain_c => wateratm2lndbulk_inst%forc_rain_downscaled_col , & ! Output: [real(r8) (:)] rain rate [mm/s] @@ -172,7 +173,8 @@ subroutine downscale_forcings(bounds, & forc_th_c => atm2lnd_inst%forc_th_downscaled_col , & ! Output: [real(r8) (:)] atmospheric potential temperature (Kelvin) forc_pbot_c => atm2lnd_inst%forc_pbot_downscaled_col , & ! Output: [real(r8) (:)] atmospheric pressure (Pa) forc_rho_c => atm2lnd_inst%forc_rho_downscaled_col , & ! Output: [real(r8) (:)] atmospheric density (kg/m**3) - forc_solad_c => atm2lnd_inst%forc_solad_col & ! Output: [real(r8) (:)] column direct incoming solar radiation + forc_solad_c => atm2lnd_inst%forc_solad_downscaled_col , & ! Output: [real(r8) (:)] column direct incoming solar radiation + forc_solar_c => atm2lnd_inst%forc_solar_downscaled_col & ! Output: [real(r8) (:)] column total incoming solar radiation ) ! Initialize column forcing (needs to be done for ALL active columns) @@ -187,6 +189,7 @@ subroutine downscale_forcings(bounds, & forc_q_c(c) = forc_q_g(g) forc_pbot_c(c) = forc_pbot_g(g) forc_rho_c(c) = forc_rho_g(g) + forc_solar_c(c) = forc_solar_g(g) forc_solad_c(c,1:numrad) = forc_solad_g(g,1:numrad) end if end do @@ -762,13 +765,13 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) associate(& ! Gridcell-level fields: forc_solai_grc => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:)] gridcell indirect incoming solar radiation - forc_solad_grc => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation + forc_solad_not_downscaled_grc => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation coszen_grc => surfalb_inst%coszen_grc , & ! Input: [real(r8) (:)] cosine of solar zenith angle ! Column-level fields: - forc_solar_col => atm2lnd_inst%forc_solar_col , & ! Output: [real(r8) (:)] column total incoming solar radiation - forc_solad_col => atm2lnd_inst%forc_solad_col , & ! Output: [real(r8) (:)] column direct incoming solar radiation - coszen_col => surfalb_inst%coszen_col & ! Input: [real(r8) (:)] cosine of solar zenith angle + coszen_col => surfalb_inst%coszen_col , & ! Input: [real(r8) (:)] cosine of solar zenith angle + forc_solar_downscaled_col => atm2lnd_inst%forc_solar_downscaled_col , & ! Output: [real(r8) (:)] column total incoming solar radiation + forc_solad_downscaled_col => atm2lnd_inst%forc_solad_downscaled_col & ! Output: [real(r8) (:)] column direct incoming solar radiation ) ! Initialize column forcing @@ -776,13 +779,13 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) sum_wtlunit(bounds%begg:bounds%endg) = 0._r8 do c = bounds%begc,bounds%endc g = col%gridcell(c) - forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad) + forc_solad_downscaled_col(c,1:numrad) = forc_solad_not_downscaled_grc(g,1:numrad) if (col%is_hillslope_column(c)) then if (coszen_grc(g) > 0._r8) then - forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) + forc_solad_downscaled_col(c,1:numrad) = forc_solad_not_downscaled_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) endif - sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtlunit(c)*forc_solad_col(c,1:numrad) + sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtlunit(c)*forc_solad_downscaled_col(c,1:numrad) sum_wtlunit(g) = sum_wtlunit(g) + col%wtlunit(c) end if end do @@ -794,14 +797,14 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) do n = 1,numrad ! absorbed energy is solar flux x area landunit (sum_wtlunit) if(sum_solar(g,n) > 0._r8) then - norm(n) = sum_wtlunit(g)*forc_solad_grc(g,n)/sum_solar(g,n) + norm(n) = sum_wtlunit(g)*forc_solad_not_downscaled_grc(g,n)/sum_solar(g,n) else norm(n) = 0._r8 endif - forc_solad_col(c,n) = forc_solad_col(c,n)*norm(n) + forc_solad_downscaled_col(c,n) = forc_solad_downscaled_col(c,n)*norm(n) enddo end if - forc_solar_col(c) = sum(forc_solad_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) + forc_solar_downscaled_col(c) = sum(forc_solad_downscaled_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) end do diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index b21242a9b2..f0f538d572 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -80,10 +80,10 @@ module atm2lndType real(r8), pointer :: forc_vp_grc (:) => null() ! atmospheric vapor pressure (Pa) real(r8), pointer :: forc_pco2_grc (:) => null() ! CO2 partial pressure (Pa) real(r8), pointer :: forc_pco2_240_patch (:) => null() ! 10-day mean CO2 partial pressure (Pa) - real(r8), pointer :: forc_solad_grc (:,:) => null() ! direct beam radiation (numrad) (vis=forc_sols , nir=forc_soll ) + real(r8), pointer :: forc_solad_not_downscaled_grc (:,:) => null() ! direct beam radiation (numrad) (vis=forc_sols , nir=forc_soll ) real(r8), pointer :: forc_solai_grc (:,:) => null() ! diffuse radiation (numrad) (vis=forc_solsd, nir=forc_solld) - real(r8), pointer :: forc_solar_grc (:) => null() ! incident solar radiation - real(r8), pointer :: forc_solar_col (:) => null() ! incident solar radiation + real(r8), pointer :: forc_solar_not_downscaled_grc (:) => null() ! incident solar radiation + real(r8), pointer :: forc_solar_downscaled_col (:) => null() ! incident solar radiation real(r8), pointer :: forc_ndep_grc (:) => null() ! nitrogen deposition rate (gN/m2/s) real(r8), pointer :: forc_pc13o2_grc (:) => null() ! C13O2 partial pressure (Pa) real(r8), pointer :: forc_po2_grc (:) => null() ! O2 partial pressure (Pa) @@ -104,7 +104,7 @@ module atm2lndType real(r8), pointer :: forc_pbot_downscaled_col (:) => null() ! downscaled atm pressure (Pa) real(r8), pointer :: forc_rho_downscaled_col (:) => null() ! downscaled atm density (kg/m**3) real(r8), pointer :: forc_lwrad_downscaled_col (:) => null() ! downscaled atm downwrd IR longwave radiation (W/m**2) - real(r8), pointer :: forc_solad_col (:,:) => null() ! direct beam radiation (numrad) (vis=forc_sols , nir=forc_soll ) + real(r8), pointer :: forc_solad_downscaled_col (:,:) => null() ! direct beam radiation (numrad) (vis=forc_sols , nir=forc_soll ) ! time averaged quantities real(r8) , pointer :: fsd24_patch (:) => null() ! patch 24hr average of direct beam radiation @@ -475,9 +475,9 @@ subroutine InitAllocate(this, bounds) allocate(this%forc_hgt_q_grc (begg:endg)) ; this%forc_hgt_q_grc (:) = ival allocate(this%forc_vp_grc (begg:endg)) ; this%forc_vp_grc (:) = ival allocate(this%forc_pco2_grc (begg:endg)) ; this%forc_pco2_grc (:) = ival - allocate(this%forc_solad_grc (begg:endg,numrad)) ; this%forc_solad_grc (:,:) = ival + allocate(this%forc_solad_not_downscaled_grc (begg:endg,numrad)) ; this%forc_solad_not_downscaled_grc (:,:) = ival allocate(this%forc_solai_grc (begg:endg,numrad)) ; this%forc_solai_grc (:,:) = ival - allocate(this%forc_solar_grc (begg:endg)) ; this%forc_solar_grc (:) = ival + allocate(this%forc_solar_not_downscaled_grc (begg:endg)) ; this%forc_solar_not_downscaled_grc (:) = ival allocate(this%forc_ndep_grc (begg:endg)) ; this%forc_ndep_grc (:) = ival allocate(this%forc_pc13o2_grc (begg:endg)) ; this%forc_pc13o2_grc (:) = ival allocate(this%forc_po2_grc (begg:endg)) ; this%forc_po2_grc (:) = ival @@ -502,8 +502,8 @@ subroutine InitAllocate(this, bounds) allocate(this%forc_th_downscaled_col (begc:endc)) ; this%forc_th_downscaled_col (:) = ival allocate(this%forc_rho_downscaled_col (begc:endc)) ; this%forc_rho_downscaled_col (:) = ival allocate(this%forc_lwrad_downscaled_col (begc:endc)) ; this%forc_lwrad_downscaled_col (:) = ival - allocate(this%forc_solad_col (begc:endc,numrad)) ; this%forc_solad_col (:,:) = ival - allocate(this%forc_solar_col (begc:endc)) ; this%forc_solar_col (:) = ival + allocate(this%forc_solad_downscaled_col (begc:endc,numrad)) ; this%forc_solad_downscaled_col (:,:) = ival + allocate(this%forc_solar_downscaled_col (begc:endc)) ; this%forc_solar_downscaled_col (:) = ival allocate(this%fsd24_patch (begp:endp)) ; this%fsd24_patch (:) = nan allocate(this%fsd240_patch (begp:endp)) ; this%fsd240_patch (:) = nan @@ -556,20 +556,20 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='atmospheric surface height', & ptr_lnd=this%forc_topo_grc) - this%forc_solar_grc(begg:endg) = spval - call hist_addfld1d (fname='FSDS', units='W/m^2', & - avgflag='A', long_name='atmospheric incident solar radiation', & - ptr_lnd=this%forc_solar_grc) + this%forc_solar_not_downscaled_grc(begg:endg) = spval + call hist_addfld1d (fname='FSDS_from_atm', units='W/m^2', & + avgflag='A', long_name='atmospheric incident solar radiation received from atmosphere (pre-downscaling)', & + ptr_lnd=this%forc_solar_not_downscaled_grc) this%forc_pco2_grc(begg:endg) = spval call hist_addfld1d (fname='PCO2', units='Pa', & avgflag='A', long_name='atmospheric partial pressure of CO2', & ptr_lnd=this%forc_pco2_grc) - this%forc_solar_grc(begg:endg) = spval + this%forc_solar_not_downscaled_grc(begg:endg) = spval call hist_addfld1d (fname='SWdown', units='W/m^2', & avgflag='A', long_name='atmospheric incident solar radiation', & - ptr_gcell=this%forc_solar_grc, default='inactive') + ptr_gcell=this%forc_solar_not_downscaled_grc, default='inactive') if (use_lch4) then this%forc_pch4_grc(begg:endg) = spval @@ -583,57 +583,46 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='atmospheric air temperature received from atmosphere (pre-downscaling)', & ptr_gcell=this%forc_t_not_downscaled_grc, default='inactive') -!scs - this%forc_solar_col(begc:endc) = spval - call hist_addfld1d (fname='FSDS_COL', units='W/m^2', & - avgflag='A', long_name='column atmospheric incident solar radiation', & - ptr_col=this%forc_solar_col, default='inactive') + this%forc_solar_downscaled_col(begc:endc) = spval + call hist_addfld1d (fname='FSDS', units='W/m^2', & + avgflag='A', long_name='atmospheric incident solar radiation (downscaled for glacier and hillslope columns)', & + ptr_col=this%forc_solar_downscaled_col) this%forc_t_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='TBOT', units='K', & - avgflag='A', long_name='atmospheric air temperature (downscaled to columns in glacier regions)', & + avgflag='A', long_name='atmospheric air temperature (downscaled for glacier and hillslope columns)', & ptr_col=this%forc_t_downscaled_col) call hist_addfld1d (fname='Tair', units='K', & - avgflag='A', long_name='atmospheric air temperature (downscaled to columns in glacier regions)', & + avgflag='A', long_name='atmospheric air temperature (downscaled for glacier and hillslope columns)', & ptr_col=this%forc_t_downscaled_col, default='inactive') this%forc_pbot_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='PBOT', units='Pa', & - avgflag='A', long_name='atmospheric pressure at surface (downscaled to columns in glacier regions)', & + avgflag='A', long_name='atmospheric pressure at surface (downscaled for glacier and hillslope columns)', & ptr_col=this%forc_pbot_downscaled_col) call hist_addfld1d (fname='PSurf', units='Pa', & - avgflag='A', long_name='atmospheric pressure at surface (downscaled to columns in glacier regions)', & + avgflag='A', long_name='atmospheric pressure at surface (downscaled for glacier and hillslope columns)', & ptr_col=this%forc_pbot_downscaled_col, default='inactive') this%forc_lwrad_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='FLDS', units='W/m^2', & - avgflag='A', long_name='atmospheric longwave radiation (downscaled to columns in glacier regions)', & + avgflag='A', long_name='atmospheric longwave radiation (downscaled for glacier and hillslope columns)', & ptr_col=this%forc_lwrad_downscaled_col) call hist_addfld1d (fname='LWdown', units='W/m^2', & - avgflag='A', long_name='atmospheric longwave radiation (downscaled to columns in glacier regions)', & + avgflag='A', long_name='atmospheric longwave radiation (downscaled for glacier and hillslope columns)', & ptr_col=this%forc_lwrad_downscaled_col, default='inactive') call hist_addfld1d (fname='FLDS_ICE', units='W/m^2', & avgflag='A', & - long_name='atmospheric longwave radiation (downscaled to columns in glacier regions) (ice landunits only)', & + long_name='atmospheric longwave radiation (downscaled for glacier and hillslope columns) (ice landunits only)', & ptr_col=this%forc_lwrad_downscaled_col, l2g_scale_type='ice', & default='inactive') this%forc_th_downscaled_col(begc:endc) = spval call hist_addfld1d (fname='THBOT', units='K', & - avgflag='A', long_name='atmospheric air potential temperature (downscaled to columns in glacier regions)', & + avgflag='A', long_name='atmospheric air potential temperature (downscaled for glacier and hillslope columns)', & ptr_col=this%forc_th_downscaled_col) -!scs -!!$ this%forc_solad_col(begc:endc,:) = spval -!!$ call hist_addfld1d (fname='SW_VIS_COL', units='W/m^2', & -!!$ avgflag='A', long_name='column direct solar radiation', & -!!$ ptr_col=this%forc_solad_col(:,1), default='inactive') -!!$ call hist_addfld1d (fname='SW_NIR_COL', units='W/m^2', & -!!$ avgflag='A', long_name='column direct solar radiation', & -!!$ ptr_col=this%forc_solad_col(:,2), default='inactive') -!scs - ! Time averaged quantities this%fsi24_patch(begp:endp) = spval call hist_addfld1d (fname='FSI24', units='K', & @@ -870,7 +859,7 @@ subroutine UpdateAccVars (this, bounds) ! Accumulate and extract forc_solad24 & forc_solad240 do p = begp,endp g = patch%gridcell(p) - rbufslp(p) = this%forc_solad_grc(g,1) + rbufslp(p) = this%forc_solad_not_downscaled_grc(g,1) end do call update_accum_field ('FSD240', rbufslp , nstep) call extract_accum_field ('FSD240', this%fsd240_patch , nstep) @@ -1009,9 +998,9 @@ subroutine Clean(this) deallocate(this%forc_hgt_q_grc) deallocate(this%forc_vp_grc) deallocate(this%forc_pco2_grc) - deallocate(this%forc_solad_grc) + deallocate(this%forc_solad_not_downscaled_grc) deallocate(this%forc_solai_grc) - deallocate(this%forc_solar_grc) + deallocate(this%forc_solar_not_downscaled_grc) deallocate(this%forc_ndep_grc) deallocate(this%forc_pc13o2_grc) deallocate(this%forc_po2_grc) @@ -1031,8 +1020,8 @@ subroutine Clean(this) deallocate(this%forc_th_downscaled_col) deallocate(this%forc_rho_downscaled_col) deallocate(this%forc_lwrad_downscaled_col) - deallocate(this%forc_solad_col) - deallocate(this%forc_solar_col) + deallocate(this%forc_solad_downscaled_col) + deallocate(this%forc_solar_downscaled_col) deallocate(this%fsd24_patch) deallocate(this%fsd240_patch) diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index f4a6bd8c6c..e954e399b9 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -1831,7 +1831,7 @@ subroutine wrap_sunfrac(this,nc,atm2lnd_inst,canopystate_inst) call t_startf('fates_wrapsunfrac') - associate( forc_solad => atm2lnd_inst%forc_solad_grc, & + associate( forc_solad => atm2lnd_inst%forc_solad_not_downscaled_grc, & forc_solai => atm2lnd_inst%forc_solai_grc, & fsun => canopystate_inst%fsun_patch, & laisun => canopystate_inst%laisun_patch, & From 14ffa235cb645babed215c0fb7193ac06fd1e87f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 25 May 2022 07:52:00 -0600 Subject: [PATCH 069/153] reorder topo_col calculation --- src/main/ColumnType.F90 | 2 +- src/main/TopoMod.F90 | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 2295f9c091..7461032cad 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -73,7 +73,7 @@ module ColumnType integer, pointer :: colu (:) ! column index of uphill column (hillslope hydrology) integer, pointer :: cold (:) ! column index of downhill column (hillslope hydrology) integer, pointer :: hillslope_ndx (:) ! hillslope identifier - real(r8), pointer :: hill_elev (:) ! mean elevation of column relative to mean gridcell elevation (m) + real(r8), pointer :: hill_elev (:) ! mean elevation of column relative to stream channel (m) real(r8), pointer :: hill_slope (:) ! mean along-hill slope (m/m) real(r8), pointer :: hill_area (:) ! mean surface area (m2) real(r8), pointer :: hill_width (:) ! across-hill width of bottom boundary of column (m) diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index 25fe2c3ed2..5e054ef00c 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -279,12 +279,13 @@ subroutine UpdateTopo(this, bounds, num_icec, filter_icec, & if (.not. this%needs_downscaling_col(c)) then g = col%gridcell(c) l = col%landunit(c) + + this%topo_col(c) = atm_topo(g) + if (col%is_hillslope_column(c) .and. downscale_hillslope_meteorology) then - this%topo_col(c) = atm_topo(g) & + this%topo_col(c) = this%topo_col(c) & + (col%hill_elev(c) - mean_hillslope_elevation(l)) this%needs_downscaling_col(c) = .true. - else - this%topo_col(c) = atm_topo(g) endif end if end do From 84b709359be9f778fd5f847a8a6cc999e9e08eb0 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 25 May 2022 08:48:41 -0600 Subject: [PATCH 070/153] change downscaling normalization weights --- src/cpl/mct/clm_cpl_indices.F90 | 4 -- src/main/atm2lndMod.F90 | 105 ++++++++++++++++++-------------- src/main/clm_varctl.F90 | 3 - 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/cpl/mct/clm_cpl_indices.F90 b/src/cpl/mct/clm_cpl_indices.F90 index 78586a48ea..dfd3dcade8 100644 --- a/src/cpl/mct/clm_cpl_indices.F90 +++ b/src/cpl/mct/clm_cpl_indices.F90 @@ -110,8 +110,6 @@ module clm_cpl_indices integer, public ::index_x2l_Flrr_flood ! rtm->lnd rof flood flux integer, public ::index_x2l_Flrr_volr ! rtm->lnd rof volr total volume integer, public ::index_x2l_Flrr_volrmch ! rtm->lnd rof volr main channel volume - integer, public ::index_x2l_Sr_tdepth ! rtm->lnd tributary water depth - integer, public ::index_x2l_Sr_tdepth_max ! rtm->lnd tributary bankfull water depth ! In the following, index 0 is bare land, other indices are glc elevation classes integer, allocatable, public ::index_x2l_Sg_ice_covered(:) ! Fraction of glacier from glc model @@ -249,8 +247,6 @@ subroutine clm_cpl_indices_set( ) index_x2l_Flrr_volr = mct_avect_indexra(x2l,'Flrr_volr') index_x2l_Flrr_volrmch = mct_avect_indexra(x2l,'Flrr_volrmch') - index_x2l_Sr_tdepth = mct_avect_indexra(x2l,'Sr_tdepth') - index_x2l_Sr_tdepth_max = mct_avect_indexra(x2l,'Sr_tdepth_max') index_x2l_Faxa_lwdn = mct_avect_indexra(x2l,'Faxa_lwdn') index_x2l_Faxa_rainc = mct_avect_indexra(x2l,'Faxa_rainc') diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 487e342230..098f15fb76 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -22,7 +22,7 @@ module atm2lndMod use filterColMod , only : filter_col_type use LandunitType , only : lun use ColumnType , only : col - use landunit_varcon, only : istice, istsoil + use landunit_varcon, only : istice use WaterType , only : water_type use Wateratm2lndBulkType, only : wateratm2lndbulk_type @@ -757,7 +757,8 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) integer :: c,l,g,n ! indices real(r8) :: norm(numrad) real(r8) :: sum_solar(bounds%begg:bounds%endg,numrad) - real(r8) :: sum_wtlunit(bounds%begg:bounds%endg) + real(r8) :: sum_wtgcell(bounds%begg:bounds%endg) + logical :: checkConservation = .true. character(len=*), parameter :: subname = 'downscale_hillslope_solar' !----------------------------------------------------------------------- @@ -765,49 +766,75 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) associate(& ! Gridcell-level fields: forc_solai_grc => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:)] gridcell indirect incoming solar radiation - forc_solad_not_downscaled_grc => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation + forc_solad_grc => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation coszen_grc => surfalb_inst%coszen_grc , & ! Input: [real(r8) (:)] cosine of solar zenith angle ! Column-level fields: coszen_col => surfalb_inst%coszen_col , & ! Input: [real(r8) (:)] cosine of solar zenith angle - forc_solar_downscaled_col => atm2lnd_inst%forc_solar_downscaled_col , & ! Output: [real(r8) (:)] column total incoming solar radiation - forc_solad_downscaled_col => atm2lnd_inst%forc_solad_downscaled_col & ! Output: [real(r8) (:)] column direct incoming solar radiation + forc_solar_col => atm2lnd_inst%forc_solar_downscaled_col , & ! Output: [real(r8) (:)] column total incoming solar radiation + forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col & ! Output: [real(r8) (:)] column direct incoming solar radiation ) ! Initialize column forcing sum_solar(bounds%begg:bounds%endg,1:numrad) = 0._r8 - sum_wtlunit(bounds%begg:bounds%endg) = 0._r8 + sum_wtgcell(bounds%begg:bounds%endg) = 0._r8 do c = bounds%begc,bounds%endc g = col%gridcell(c) - forc_solad_downscaled_col(c,1:numrad) = forc_solad_not_downscaled_grc(g,1:numrad) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then if (coszen_grc(g) > 0._r8) then - forc_solad_downscaled_col(c,1:numrad) = forc_solad_not_downscaled_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) + forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) endif - sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtlunit(c)*forc_solad_downscaled_col(c,1:numrad) - sum_wtlunit(g) = sum_wtlunit(g) + col%wtlunit(c) + sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtgcell(c)*forc_solad_col(c,1:numrad) + sum_wtgcell(g) = sum_wtgcell(g) + col%wtgcell(c) end if end do ! Normalize column level solar do c = bounds%begc,bounds%endc - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then g = col%gridcell(c) do n = 1,numrad - ! absorbed energy is solar flux x area landunit (sum_wtlunit) + ! absorbed energy is solar flux x area landunit (sum_wtgcell) if(sum_solar(g,n) > 0._r8) then - norm(n) = sum_wtlunit(g)*forc_solad_not_downscaled_grc(g,n)/sum_solar(g,n) + norm(n) = sum_wtgcell(g)*forc_solad_grc(g,n)/sum_solar(g,n) + forc_solad_col(c,n) = forc_solad_col(c,n)*norm(n) else - norm(n) = 0._r8 + forc_solad_col(c,n) = forc_solad_grc(g,n) endif - forc_solad_downscaled_col(c,n) = forc_solad_downscaled_col(c,n)*norm(n) enddo end if - forc_solar_downscaled_col(c) = sum(forc_solad_downscaled_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) + forc_solar_col(c) = sum(forc_solad_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) end do + ! check conservation + if(checkConservation) then + sum_solar(bounds%begg:bounds%endg,1:numrad) = 0._r8 + sum_wtgcell(bounds%begg:bounds%endg) = 0._r8 + ! Calculate normalization (area-weighted solar flux) + do c = bounds%begc,bounds%endc + if (col%is_hillslope_column(c) .and. col%active(c)) then + g = col%gridcell(c) + do n = 1,numrad + sum_solar(g,n) = sum_solar(g,n) + col%wtgcell(c)*forc_solad_col(c,n) + enddo + sum_wtgcell(g) = sum_wtgcell(g) + col%wtgcell(c) + end if + end do + do g = bounds%begg,bounds%endg + do n = 1,numrad + if(abs(sum_solar(g,n) - sum_wtgcell(g)*forc_solad_grc(g,n)) > 1.e-6) then + write(iulog,*) 'downscaled solar not conserved', g, n, sum_solar(g,n), sum_wtgcell(g)*forc_solad_grc(g,n) + call endrun(subgrid_index=g, subgrid_level=subgrid_level_gridcell, & + msg=' ERROR: Energy conservation error downscaling solar'//& + errMsg(sourcefile, __LINE__)) + endif + enddo + enddo + endif + + end associate end subroutine downscale_hillslope_solar @@ -840,9 +867,8 @@ subroutine downscale_hillslope_precipitation(bounds, & real(r8) :: norm_rain(bounds%begg:bounds%endg) real(r8) :: norm_snow(bounds%begg:bounds%endg) real(r8) :: sum_wt(bounds%begg:bounds%endg) - real(r8) :: max_topo(bounds%begg:bounds%endg) - real(r8) :: min_topo(bounds%begg:bounds%endg) - real(r8) :: rain_scalar, snow_scalar + real(r8), parameter :: rain_scalar = 1.5e-3_r8 ! (1/m) + real(r8), parameter :: snow_scalar = 1.5e-3_r8 ! (1/m) logical :: checkConservation = .true. character(len=*), parameter :: subname = 'downscale_hillslope_precipitation' !----------------------------------------------------------------------- @@ -860,33 +886,18 @@ subroutine downscale_hillslope_precipitation(bounds, & forc_snow_c => wateratm2lndbulk_inst%forc_snow_downscaled_col & ! Output: [real(r8) (:)] snow rate [mm/s] ) - ! Extract maximum column-level topographic elevation - - min_topo(bounds%begg:bounds%endg) = 0._r8 - max_topo(bounds%begg:bounds%endg) = 0._r8 - do l = bounds%begl, bounds%endl - if (lun%itype(l) == istsoil) then - g = lun%gridcell(l) - min_topo(g) = minval(topo_c(lun%coli(l):lun%colf(l))) - max_topo(g) = maxval(topo_c(lun%coli(l):lun%colf(l))) - endif - enddo - ! Redistribute precipitation based on departure ! of column elevation from mean elevation do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then ! spatially uniform normalization, but separate rain/snow - rain_scalar = 1.2e-3 - rain_scalar = 1.5e-3 topo_anom = max(-1._r8,(topo_c(c) - forc_topo_g(g))*rain_scalar) ! rain precip_anom = forc_rain_g(g) * topo_anom forc_rain_c(c) = forc_rain_c(c) + precip_anom - snow_scalar = rain_scalar topo_anom = max(-1._r8,(topo_c(c) - forc_topo_g(g))*snow_scalar) ! snow precip_anom = forc_snow_g(g) * topo_anom forc_snow_c(c) = forc_snow_c(c) + precip_anom @@ -901,10 +912,10 @@ subroutine downscale_hillslope_precipitation(bounds, & ! Calculate normalization (area-weighted average precipitation) do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (col%is_hillslope_column(c)) then - norm_rain(g) = norm_rain(g) + col%wtlunit(c)*forc_rain_c(c) - norm_snow(g) = norm_snow(g) + col%wtlunit(c)*forc_snow_c(c) - sum_wt(g) = sum_wt(g) + col%wtlunit(c) + if (col%is_hillslope_column(c) .and. col%active(c)) then + norm_rain(g) = norm_rain(g) + col%wtgcell(c)*forc_rain_c(c) + norm_snow(g) = norm_snow(g) + col%wtgcell(c)*forc_snow_c(c) + sum_wt(g) = sum_wt(g) + col%wtgcell(c) end if end do do g = bounds%begg,bounds%endg @@ -917,12 +928,16 @@ subroutine downscale_hillslope_precipitation(bounds, & ! Normalize column precipitation to conserve gridcell average do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then if (norm_rain(g) > 0._r8) then forc_rain_c(c) = forc_rain_c(c) * forc_rain_g(g) / norm_rain(g) + else + forc_rain_c(c) = forc_rain_g(g) endif if (norm_snow(g) > 0._r8) then forc_snow_c(c) = forc_snow_c(c) * forc_snow_g(g) / norm_snow(g) + else + forc_snow_c(c) = forc_snow_g(g) endif end if end do @@ -935,10 +950,10 @@ subroutine downscale_hillslope_precipitation(bounds, & ! Calculate normalization (area-weighted average precipitation) do c = bounds%begc,bounds%endc g = col%gridcell(c) - if (col%is_hillslope_column(c)) then - norm_rain(g) = norm_rain(g) + col%wtlunit(c)*forc_rain_c(c) - norm_snow(g) = norm_snow(g) + col%wtlunit(c)*forc_snow_c(c) - sum_wt(g) = sum_wt(g) + col%wtlunit(c) + if (col%is_hillslope_column(c) .and. col%active(c)) then + norm_rain(g) = norm_rain(g) + col%wtgcell(c)*forc_rain_c(c) + norm_snow(g) = norm_snow(g) + col%wtgcell(c)*forc_snow_c(c) + sum_wt(g) = sum_wt(g) + col%wtgcell(c) end if end do do g = bounds%begg,bounds%endg diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index c93f218156..784bc385d7 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -350,9 +350,6 @@ module clm_varctl ! true => CLM glacier area & topography changes dynamically logical , public :: glc_do_dynglacier = .false. - ! true => downscale longwave radiation - logical , public :: glcmec_downscale_longwave = .true. - ! number of days before one considers the perennially snow-covered point 'land ice' integer , public :: glc_snow_persistence_max_days = 7300 From 90bbebda3ee06a1643de998c7996acdfa4c34531 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 26 May 2022 08:39:07 -0600 Subject: [PATCH 071/153] add set_c2l_scale call to subgridAveMod routines --- src/biogeophys/BalanceCheckMod.F90 | 2 +- src/biogeophys/HillslopeHydrologyMod.F90 | 81 ++++++----- src/biogeophys/SoilHydrologyMod.F90 | 12 +- src/biogeophys/WaterStateType.F90 | 18 +-- src/main/subgridAveMod.F90 | 172 +---------------------- src/main/surfrdMod.F90 | 10 +- 6 files changed, 67 insertions(+), 228 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index cdf97d198a..2c214a8e0a 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -275,7 +275,7 @@ subroutine WaterGridcellBalanceSingle(bounds, & if (use_hillslope_routing) then do l = begl, endl g = lun%gridcell(l) - wb_grc(g) = wb_grc(g) + waterstate_inst%stream_water_lun(l) & + wb_grc(g) = wb_grc(g) + waterstate_inst%stream_water_volume_lun(l) & *1e3_r8/(grc%area(g)*1.e6_r8) enddo endif diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 77fb6e0ef0..ccbd108233 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -692,7 +692,7 @@ subroutine HillslopeSoilThicknessProfile(bounds,& ! Specify lowland/upland soil thicknesses separately if(soil_profile_method == soil_profile_set_lowland_upland) then do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then if(col%cold(c) /= ispval) then do j = 1,nlevsoi if(zisoi(j-1) > zmin_bedrock) then @@ -724,7 +724,7 @@ subroutine HillslopeSoilThicknessProfile(bounds,& b = soil_depth_upland do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then soil_depth_col = m*(max_hill_dist - col%hill_distance(c)) + b do j = 1,nlevsoi @@ -769,7 +769,7 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) do l = bounds%begl, bounds%endl do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) @@ -831,7 +831,7 @@ subroutine HillslopeDominantPft(bounds) do l = bounds%begl, bounds%endl do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) pdom = pdom + (col%patchi(c) - 1) @@ -883,7 +883,7 @@ subroutine HillslopeDominantLowlandPft(bounds) do l = bounds%begl, bounds%endl do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) ! create mask to exclude pdom allocate(mask(col%npatches(c))) @@ -978,7 +978,7 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) do l = bounds%begl, bounds%endl do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then ! this may require modifying ! subgridMod/natveg_patch_exists to ensure that ! a patch exists on each column @@ -1045,20 +1045,20 @@ subroutine HillslopeStreamOutflow(bounds, & integer :: c, l, g, i, j integer :: nstep real(r8) :: dtime ! land model time step (sec) - real(r8) :: cross_sectional_area - real(r8) :: stream_depth - real(r8) :: hydraulic_radius - real(r8) :: flow_velocity - real(r8) :: overbank_area -! real(r8), parameter :: manning_roughness = 0.05 - real(r8), parameter :: manning_roughness = 0.03 - real(r8), parameter :: manning_exponent = 0.667 - + real(r8) :: cross_sectional_area ! cross sectional area of stream water (m2) + real(r8) :: stream_depth ! depth of stream water (m) + real(r8) :: hydraulic_radius ! cross sectional area divided by wetted perimeter (m) + real(r8) :: flow_velocity ! flow velocity (m/s) + real(r8) :: overbank_area ! area of water above bankfull (m2) + real(r8), parameter :: manning_roughness = 0.03 ! manning roughness + real(r8), parameter :: manning_exponent = 0.667 ! manning exponent + + integer, parameter :: overbank_method = 1 ! method to treat overbank stream storage; 1 = increase dynamic slope, 2 = increase flow area cross section, 3 = remove instantaneously character(len=*), parameter :: subname = 'HillslopeStreamOutflow' !----------------------------------------------------------------------- associate( & - stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) + stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) qstreamflow => waterfluxbulk_inst%qstreamflow_lun & ! Input: [real(r8) (:) ] stream water discharge (m3/s) ) @@ -1085,18 +1085,25 @@ subroutine HillslopeStreamOutflow(bounds, & / manning_roughness ! overbank flow if (stream_depth > lun%stream_channel_depth(l)) then - ! try increasing flow area cross section -! overbank_area = (stream_depth -lun%stream_channel_depth(l)) * 30._r8 * lun%stream_channel_width(l) - ! qstreamflow(l) = (cross_sectional_area + overbank_area) * flow_velocity - - ! try increasing dynamic slope - qstreamflow(l) = cross_sectional_area * flow_velocity & - *(stream_depth/lun%stream_channel_depth(l)) - - ! try removing all overbank flow instantly -!!$ qstreamflow(l) = cross_sectional_area * flow_velocity & -!!$ + (stream_depth-lun%stream_channel_depth(l)) & -!!$ *lun%stream_channel_width(l)*lun%stream_channel_length(l)/dtime + if (overbank_method == 1) then + ! try increasing dynamic slope + qstreamflow(l) = cross_sectional_area * flow_velocity & + *(stream_depth/lun%stream_channel_depth(l)) + else if (overbank_method == 2) then + ! try increasing flow area cross section + overbank_area = (stream_depth -lun%stream_channel_depth(l)) * 30._r8 * lun%stream_channel_width(l) + qstreamflow(l) = (cross_sectional_area + overbank_area) * flow_velocity + else if (overbank_method == 3) then + ! try removing all overbank flow instantly + qstreamflow(l) = cross_sectional_area * flow_velocity & + + (stream_depth-lun%stream_channel_depth(l)) & + *lun%stream_channel_width(l)*lun%stream_channel_length(l)/dtime + else + if (masterproc) then + call endrun( 'ERROR:: invalid overbank_method.'//errmsg(sourcefile, __LINE__) ) + end if + endif + else qstreamflow(l) = cross_sectional_area * flow_velocity endif @@ -1153,14 +1160,14 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & character(len=*), parameter :: subname = 'HillslopeUpdateStreamWater' !----------------------------------------------------------------------- - associate( & - stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input/Output: [real(r8) (:) ] stream water volume (m3) - qstreamflow => waterfluxbulk_inst%qstreamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) - qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Input: [real(r8) (:) ] discharge from columns (m3/s) - qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, &! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) - qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Input: [real(r8) (:) ] column level correction runoff (mm H2O /s) - qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) - stream_water_depth => waterstatebulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) + associate( & + stream_water_volume => waterstatebulk_inst%stream_water_volume_lun, & ! Input/Output: [real(r8) (:) ] stream water volume (m3) + qstreamflow => waterfluxbulk_inst%qstreamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) + qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Input: [real(r8) (:) ] discharge from columns (m3/s) + qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, &! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) + qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Input: [real(r8) (:) ] column level correction runoff (mm H2O /s) + qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) + stream_water_depth => waterstatebulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) ) ! Get time step @@ -1171,7 +1178,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & g = lun%gridcell(l) do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then qflx_surf_vol = qflx_surf(c)*1.e-3_r8 & *(grc%area(g)*1.e6_r8*col%wtgcell(c)) qflx_drain_perched_vol = qflx_drain_perched(c)*1.e-3_r8 & diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 0be3a0126c..77429563cf 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1663,7 +1663,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Input: [real(r8) (:) ] perched water table depth (m) tdepth => wateratm2lndbulk_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) - stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) + stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col , & ! Output: [real(r8) (:) ] perched wt sub-surface runoff (mm H2O /s) @@ -1707,7 +1707,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & if (frost_table(c) > zwt_perched(c)) then ! Hillslope columns - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then ! calculate head gradient @@ -1843,7 +1843,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & c = filter_hydrologyc(fc) ! drainage-out qflx_drain_perched(c) = qflx_drain_perched(c) + qflx_drain_perched_out(c) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then ! drainage-in if (col%cold(c) /= ispval) then qflx_drain_perched(col%cold(c)) = & @@ -2077,7 +2077,7 @@ subroutine SubsurfaceLateralFlow(bounds, & depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] fraction of ice in layer zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) - stream_water_volume => waterstatebulk_inst%stream_water_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) + stream_water_volume => waterstatebulk_inst%stream_water_volume_lun, & ! Input: [real(r8) (:) ] stream water volume (m3) qflx_snwcp_liq => waterfluxbulk_inst%qflx_snwcp_liq_col , & ! Output: [real(r8) (:) ] excess rainfall due to snow capping (mm H2O /s) [+] qflx_ice_runoff_xs => waterfluxbulk_inst%qflx_ice_runoff_xs_col , & ! Output: [real(r8) (:) ] solid runoff from excess ice in soil (mm H2O /s) [+] @@ -2151,7 +2151,7 @@ subroutine SubsurfaceLateralFlow(bounds, & l = col%landunit(c) g = col%gridcell(c) ! Hillslope columns - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then ! kinematic wave approximation if (head_gradient_method == kinematic) then @@ -2296,7 +2296,7 @@ subroutine SubsurfaceLateralFlow(bounds, & endif do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) - if (col%is_hillslope_column(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then l = col%landunit(c) !need to sum all columns w/ same hillslope id for each column qflx_latflow_avg(c) = 0._r8 diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 1dc361acd1..44a89b7cff 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -52,8 +52,8 @@ module WaterStateType real(r8) :: aquifer_water_baseline ! baseline value for water in the unconfined aquifer (wa_col) for this bulk / tracer (mm) ! Hillslope stream variables - real(r8), pointer :: stream_water_lun (:) ! landunit volume of water in the streams (m3) - real(r8), pointer :: stream_water_depth_lun (:) ! landunit depth of water in the streams (m3) + real(r8), pointer :: stream_water_volume_lun(:) ! landunit volume of water in the streams (m3) + real(r8), pointer :: stream_water_depth_lun (:) ! landunit depth of water in the streams (m) contains @@ -154,7 +154,7 @@ subroutine InitAllocate(this, bounds, tracer_vars) call AllocateVar1d(var = this%dynbal_baseline_ice_col, name = 'dynbal_baseline_ice_col', & container = tracer_vars, & bounds = bounds, subgrid_level = subgrid_level_column) - call AllocateVar1d(var = this%stream_water_lun, name = 'stream_water_lun', & + call AllocateVar1d(var = this%stream_water_volume_lun, name = 'stream_water_volume_lun', & container = tracer_vars, & bounds = bounds, subgrid_level = subgrid_level_landunit) call AllocateVar1d(var = this%stream_water_depth_lun, name = 'stream_water_depth_lun', & @@ -283,17 +283,17 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) end if if (use_hillslope) then - this%stream_water_lun(begl:endl) = spval + this%stream_water_volume_lun(begl:endl) = spval call hist_addfld1d (fname=this%info%fname('STREAM_WATER_VOLUME'), units='m3', & avgflag='A', & long_name=this%info%lname('volume of water in stream channel (hillslope hydrology only)'), & - ptr_lunit=this%stream_water_lun, l2g_scale_type='veg', default='inactive') + ptr_lunit=this%stream_water_volume_lun, l2g_scale_type='natveg', default='inactive') this%stream_water_depth_lun(begl:endl) = spval call hist_addfld1d (fname=this%info%fname('STREAM_WATER_DEPTH'), units='m', & avgflag='A', & long_name=this%info%lname('depth of water in stream channel (hillslope hydrology only)'), & - ptr_lunit=this%stream_water_depth_lun, l2g_scale_type='veg', default='inactive') + ptr_lunit=this%stream_water_depth_lun, l2g_scale_type='natveg', default='inactive') end if @@ -347,7 +347,7 @@ subroutine InitCold(this, bounds, & this%h2osfc_col(bounds%begc:bounds%endc) = 0._r8 this%snocan_patch(bounds%begp:bounds%endp) = 0._r8 this%liqcan_patch(bounds%begp:bounds%endp) = 0._r8 - this%stream_water_lun(bounds%begl:bounds%endl) = 0._r8 + this%stream_water_volume_lun(bounds%begl:bounds%endl) = 0._r8 !-------------------------------------------- ! Set soil water @@ -665,10 +665,10 @@ subroutine Restart(this, bounds, ncid, flag, & dim1name='landunit', & long_name=this%info%lname('water in stream channel'), & units='m3', & - interpinic_flag='interp', readvar=readvar, data=this%stream_water_lun) + interpinic_flag='interp', readvar=readvar, data=this%stream_water_volume_lun) if (flag == 'read' .and. .not. is_restart()) then - this%stream_water_lun(bounds%begl:bounds%endl) = 0._r8 + this%stream_water_volume_lun(bounds%begl:bounds%endl) = 0._r8 end if ! Determine volumetric soil water (for read only) diff --git a/src/main/subgridAveMod.F90 b/src/main/subgridAveMod.F90 index bbb26d8560..8194d7e884 100644 --- a/src/main/subgridAveMod.F90 +++ b/src/main/subgridAveMod.F90 @@ -408,48 +408,7 @@ subroutine p2l_1d (bounds, parr, larr, p2c_scale_type, c2l_scale_type) SHR_ASSERT_ALL_FL((ubound(parr) == (/bounds%endp/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(larr) == (/bounds%endl/)), sourcefile, __LINE__) - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'p2l_1d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) if (p2c_scale_type == 'unity') then do p = bounds%begp,bounds%endp @@ -516,48 +475,7 @@ subroutine p2l_2d(bounds, num2d, parr, larr, p2c_scale_type, c2l_scale_type) SHR_ASSERT_ALL_FL((ubound(parr) == (/bounds%endp, num2d/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(larr) == (/bounds%endl, num2d/)), sourcefile, __LINE__) - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'p2l_2d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) if (p2c_scale_type == 'unity') then do p = bounds%begp,bounds%endp @@ -630,48 +548,7 @@ subroutine p2g_1d(bounds, parr, garr, p2c_scale_type, c2l_scale_type, l2g_scale_ call build_scale_l2g(bounds, l2g_scale_type, & scale_l2g(bounds%begl:bounds%endl)) - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'p2g_1d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) if (p2c_scale_type == 'unity') then do p = bounds%begp,bounds%endp @@ -746,48 +623,7 @@ subroutine p2g_2d(bounds, num2d, parr, garr, p2c_scale_type, c2l_scale_type, l2g call build_scale_l2g(bounds, l2g_scale_type, & scale_l2g(bounds%begl:bounds%endl)) - if (c2l_scale_type == 'unity') then - do c = bounds%begc,bounds%endc - scale_c2l(c) = 1.0_r8 - end do - else if (c2l_scale_type == 'urbanf') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = 3.0 * lun%canyon_hwr(l) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0_r8 - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else if (c2l_scale_type == 'urbans') then - do c = bounds%begc,bounds%endc - l = col%landunit(c) - if (lun%urbpoi(l)) then - if (col%itype(c) == icol_sunwall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_shadewall) then - scale_c2l(c) = (3.0 * lun%canyon_hwr(l)) / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_road_perv .or. col%itype(c) == icol_road_imperv) then - scale_c2l(c) = 3.0 / (2.*lun%canyon_hwr(l) + 1.) - else if (col%itype(c) == icol_roof) then - scale_c2l(c) = 1.0_r8 - end if - else - scale_c2l(c) = 1.0_r8 - end if - end do - else - write(iulog,*)'p2g_2d error: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if + call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) if (p2c_scale_type == 'unity') then do p = bounds%begp,bounds%endp diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 91299b0ad9..f794ac5e09 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -781,8 +781,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! number of hillslopes per landunit call ncd_inqdid(ncid,'nhillslope',dimid,readvar) if (.not. readvar) then - write(iulog,*)'surfrd error: nhillslope not on surface data file' - nhillslope = 1 + call endrun( msg=' ERROR: nhillslope not on surface data file'//errMsg(sourcefile, __LINE__)) else call ncd_inqdlen(ncid,dimid,nh) nhillslope = nh @@ -790,8 +789,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! maximum number of columns per landunit call ncd_inqdid(ncid,'nmaxhillcol',dimid,readvar) if (.not. readvar) then - write(iulog,*)'surfrd error: nmaxhillcol not on surface data file' - max_columns_hillslope = 1 + call endrun( msg=' ERROR: nmaxhillcol not on surface data file'//errMsg(sourcefile, __LINE__)) else call ncd_inqdlen(ncid,dimid,nh) max_columns_hillslope = nh @@ -801,9 +799,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) call ncd_io(ncid=ncid, varname='nhillcolumns', flag='read', data=arrayl, & dim1name=grlnd, readvar=readvar) if (.not. readvar) then - write(iulog,*)'surfrd error: nhillcolumns not on surface data file' - ncolumns_hillslope(begg:endg) = 1 - write(iulog,*)'setting ncolumns_hillslope[:] = 1' + call endrun( msg=' ERROR: nhillcolumns not on surface data file'//errMsg(sourcefile, __LINE__)) else ncolumns_hillslope(begg:endg) = arrayl(begg:endg) endif From 0017cc57a1c8ea063d9dc2fba89d8ad602bfabd7 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 26 May 2022 10:49:30 -0600 Subject: [PATCH 072/153] add check to CLMBuildNamelist.pm --- bld/CLMBuildNamelist.pm | 6 +- src/biogeophys/HillslopeHydrologyMod.F90 | 371 +++++++++++------------ src/biogeophys/SoilHydrologyMod.F90 | 16 +- src/biogeophys/SurfaceRadiationMod.F90 | 1 - src/biogeophys/WaterFluxType.F90 | 8 +- src/biogeophys/WaterStateType.F90 | 6 +- 6 files changed, 204 insertions(+), 204 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index fcb3a5af36..9ecff7ea1b 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3251,7 +3251,11 @@ sub setup_logic_hillslope { my $use_hillslope = $nl->get_value('use_hillslope'); my $use_hillslope_routing = $nl->get_value('use_hillslope_routing'); if ( (! &value_is_true($use_hillslope)) && &value_is_true($use_hillslope_routing) ) { - $log->fatal_error("Cannot turn use_hillslope_routing on when use_hillslope is off\n" ); + $log->fatal_error("Cannot turn on use_hillslope_routing when use_hillslope is off\n" ); + } + my $downscale_hillslope_meteorology = $nl->get_value('use_hillslope_routing'); + if ( (! &value_is_true($use_hillslope)) && &value_is_true($downscale_hillslope_meteorology) ) { + $log->fatal_error("Cannot turn on downscale_hillslope_meteorology when use_hillslope is off\n" ); } } diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index ccbd108233..8a14cfa24f 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -360,11 +360,11 @@ subroutine InitHillslope(bounds,fsurdat) if (masterproc) then write(iulog,*) 'h_bedrock found on surface data set' end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + hill_bedrock(l,:) = fhillslope_in(g,:) + enddo end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_bedrock(l,:) = fhillslope_in(g,:) - enddo deallocate(fhillslope_in) @@ -579,13 +579,11 @@ subroutine InitHillslope(bounds,fsurdat) if (col%is_hillslope_column(c)) then col%wtlunit(c) = (col%hill_area(c)/hillslope_area(nh)) & * (pct_hillslope(l,nh)*0.01_r8) - else - ! do not reweight if column is not a hillslope column - !col%wtlunit(c) = 0._r8 endif check_weight = check_weight + col%wtlunit(c) enddo if (abs(1._r8 - check_weight) > 1.e-6_r8) then + write(iulog,*) 'HillslopeHydrologyMod column reweighting' write(iulog,*) 'col%wtlunit does not sum to 1: ', check_weight write(iulog,*) 'weights: ', col%wtlunit(lun%coli(l):lun%colf(l)) write(iulog,*) 'location: ',grc%londeg(g),grc%latdeg(g) @@ -622,14 +620,14 @@ subroutine InitHillslope(bounds,fsurdat) ! to ensure patch exists in every gridcell ! Specify single dominant pft per gridcell - call HillslopeDominantPft(bounds) + !call HillslopeDominantPft(bounds) ! Specify different pfts for uplands / lowlands - !call HillslopeDominantLowlandPft(bounds) + call HillslopeDominantLowlandPft(bounds) !upland_ivt = 13 ! c3 non-arctic grass !lowland_ivt = 7 ! broadleaf deciduous tree - !call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) + call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) endif call ncd_pio_closefile(ncid) @@ -688,35 +686,32 @@ subroutine HillslopeSoilThicknessProfile(bounds,& soil_depth_upland = soil_depth_upland_default endif - do l = bounds%begl,bounds%endl - ! Specify lowland/upland soil thicknesses separately - if(soil_profile_method == soil_profile_set_lowland_upland) then - do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c) .and. col%active(c)) then - if(col%cold(c) /= ispval) then - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < soil_depth_upland .and. zisoi(j) >= soil_depth_upland) then - col%nbedrock(c) = j - end if + ! Specify lowland/upland soil thicknesses separately + if(soil_profile_method == soil_profile_set_lowland_upland) then + do c = bounds%begc,bounds%endc + if (col%is_hillslope_column(c) .and. col%active(c)) then + if(col%cold(c) /= ispval) then + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < soil_depth_upland .and. zisoi(j) >= soil_depth_upland) then + col%nbedrock(c) = j end if - enddo - else - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < soil_depth_lowland .and. zisoi(j) >= soil_depth_lowland) then - col%nbedrock(c) = j - end if + end if + enddo + else + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < soil_depth_lowland .and. zisoi(j) >= soil_depth_lowland) then + col%nbedrock(c) = j end if - enddo - endif + end if + enddo endif - end do - endif - - ! Linear soil thickness profile - if(soil_profile_method == soil_profile_linear) then - + endif + end do + ! Linear soil thickness profile + else if(soil_profile_method == soil_profile_linear) then + do l = bounds%begl,bounds%endl min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) m = (soil_depth_lowland - soil_depth_upland)/ & @@ -734,8 +729,12 @@ subroutine HillslopeSoilThicknessProfile(bounds,& enddo endif enddo - endif - enddo ! end of loop over landunits + enddo + else + if (masterproc) then + call endrun( 'ERROR:: invalid soil_profile_method.'//errmsg(sourcefile, __LINE__) ) + end if + endif end subroutine HillslopeSoilThicknessProfile @@ -767,39 +766,37 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) !------------------------------------------------------------------------ - do l = bounds%begl, bounds%endl - do c = lun%coli(l), lun%colf(l) + do c = bounds%begc,bounds%endc if (col%is_hillslope_column(c) .and. col%active(c)) then - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - pl = ispval - pu = ispval - do p = col%patchi(c), col%patchf(c) - if(patch%itype(p) == lowland_ivt) pl = p - if(patch%itype(p) == upland_ivt) pu = p - enddo + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + pl = ispval + pu = ispval + do p = col%patchi(c), col%patchf(c) + if(patch%itype(p) == lowland_ivt) pl = p + if(patch%itype(p) == upland_ivt) pu = p + enddo - ! only reweight if pfts exist within column - if (pl /= ispval .and. pu /= ispval) then - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + ! only reweight if pfts exist within column + if (pl /= ispval .and. pu /= ispval) then + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - ! hillbottom - if(col%cold(c) == ispval) then - patch%wtcol(pl) = sum_wtcol - patch%wtlunit(pl) = sum_wtlun - patch%wtgcell(pl) = sum_wtgrc - else - patch%wtcol(pu) = sum_wtcol - patch%wtlunit(pu) = sum_wtlun - patch%wtgcell(pu) = sum_wtgrc - endif + ! hillbottom + if(col%cold(c) == ispval) then + patch%wtcol(pl) = sum_wtcol + patch%wtlunit(pl) = sum_wtlun + patch%wtgcell(pl) = sum_wtgrc + else + patch%wtcol(pu) = sum_wtcol + patch%wtlunit(pu) = sum_wtlun + patch%wtgcell(pu) = sum_wtgrc endif endif - enddo ! end loop c - enddo ! end loop l + endif + enddo ! end loop c end subroutine HillslopeSetLowlandUplandPfts @@ -829,26 +826,24 @@ subroutine HillslopeDominantPft(bounds) !------------------------------------------------------------------------ - do l = bounds%begl, bounds%endl - do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c) .and. col%active(c)) then - pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) - pdom = pdom + (col%patchi(c) - 1) + do c = bounds%begc,bounds%endc + if (col%is_hillslope_column(c) .and. col%active(c)) then + pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) + pdom = pdom + (col%patchi(c) - 1) - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtcol(pdom(1)) = sum_wtcol - patch%wtlunit(pdom(1)) = sum_wtlun - patch%wtgcell(pdom(1)) = sum_wtgrc - endif - enddo ! end loop c - enddo ! end loop l + patch%wtcol(pdom(1)) = sum_wtcol + patch%wtlunit(pdom(1)) = sum_wtlun + patch%wtgcell(pdom(1)) = sum_wtgrc + endif + enddo ! end loop c end subroutine HillslopeDominantPft @@ -868,6 +863,7 @@ subroutine HillslopeDominantLowlandPft(bounds) use clm_varcon , only : ispval use landunit_varcon , only : istsoil use PatchType , only : patch + use pftconMod , only : pftcon, ndllf_evr_tmp_tree, nc3_nonarctic_grass, nc4_grass ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -881,72 +877,70 @@ subroutine HillslopeDominantLowlandPft(bounds) !------------------------------------------------------------------------ - do l = bounds%begl, bounds%endl - do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c) .and. col%active(c)) then - pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) - ! create mask to exclude pdom - allocate(mask(col%npatches(c))) - mask(:) = 1. - mask(pdom(1)) = 0. - - pdom = pdom + (col%patchi(c) - 1) - - psubdom = maxloc(mask*patch%wtcol(col%patchi(c):col%patchf(c))) - psubdom = psubdom + (col%patchi(c) - 1) - deallocate(mask) - - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - - ! assumes trees are 1-8, shrubs 9-11, and grasses 12-14 - ! and puts the lowest ivt on the lowland column - if ((patch%itype(pdom(1)) > patch%itype(psubdom(1)) & - .and. patch%itype(psubdom(1)) > 0) .or. & - (patch%itype(pdom(1)) == 0)) then - plow = psubdom(1) - phigh = pdom(1) - else - plow = pdom(1) - phigh = psubdom(1) - endif + do c = bounds%begc,bounds%endc + if (col%is_hillslope_column(c) .and. col%active(c)) then + pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) + ! create mask to exclude pdom + allocate(mask(col%npatches(c))) + mask(:) = 1. + mask(pdom(1)) = 0. + + pdom = pdom + (col%patchi(c) - 1) + + psubdom = maxloc(mask*patch%wtcol(col%patchi(c):col%patchf(c))) + psubdom = psubdom + (col%patchi(c) - 1) + deallocate(mask) + + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + + ! assumes trees are 1-8, shrubs 9-11, and grasses 12-14 + ! and puts the lowest ivt on the lowland column + if ((patch%itype(pdom(1)) > patch%itype(psubdom(1)) & + .and. patch%itype(psubdom(1)) > 0) .or. & + (patch%itype(pdom(1)) == 0)) then + plow = psubdom(1) + phigh = pdom(1) + else + plow = pdom(1) + phigh = psubdom(1) + endif - ! Special cases (subjective) + ! Special cases (subjective) - ! if NET/BDT assign BDT to lowland - if ((patch%itype(pdom(1)) == 1) .and. (patch%itype(psubdom(1)) < 9)) then - plow = psubdom(1) - phigh = pdom(1) - endif - ! if C3/C4 assign C4 to lowland - if ((patch%itype(pdom(1)) == 14) .and. (patch%itype(psubdom(1)) == 13)) then - plow = pdom(1) - phigh = psubdom(1) - endif - if ((patch%itype(pdom(1)) == 13) .and. (patch%itype(psubdom(1)) == 14)) then - plow = psubdom(1) - phigh = pdom(1) - endif + ! if NET/BDT assign BDT to lowland + if ((patch%itype(pdom(1)) == ndllf_evr_tmp_tree) .and. pftcon%is_tree(patch%itype(psubdom(1)))) then + plow = psubdom(1) + phigh = pdom(1) + endif + ! if C3/C4 assign C4 to lowland + if ((patch%itype(pdom(1)) == nc4_grass) .and. (patch%itype(psubdom(1)) == nc3_nonarctic_grass)) then + plow = pdom(1) + phigh = psubdom(1) + endif + if ((patch%itype(pdom(1)) == nc3_nonarctic_grass) .and. (patch%itype(psubdom(1)) == nc4_grass)) then + plow = psubdom(1) + phigh = pdom(1) + endif - if(col%cold(c) == ispval) then - ! lowland column - patch%wtcol(plow) = sum_wtcol - patch%wtlunit(plow) = sum_wtlun - patch%wtgcell(plow) = sum_wtgrc - else - ! upland columns - patch%wtcol(phigh) = sum_wtcol - patch%wtlunit(phigh) = sum_wtlun - patch%wtgcell(phigh) = sum_wtgrc - endif + if(col%cold(c) == ispval) then + ! lowland column + patch%wtcol(plow) = sum_wtcol + patch%wtlunit(plow) = sum_wtlun + patch%wtgcell(plow) = sum_wtgrc + else + ! upland columns + patch%wtcol(phigh) = sum_wtcol + patch%wtlunit(phigh) = sum_wtlun + patch%wtgcell(phigh) = sum_wtgrc endif - enddo ! end loop c - enddo ! end loop l + endif + enddo ! end loop c end subroutine HillslopeDominantLowlandPft @@ -976,43 +970,44 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) !------------------------------------------------------------------------ - do l = bounds%begl, bounds%endl - do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c) .and. col%active(c)) then - ! this may require modifying - ! subgridMod/natveg_patch_exists to ensure that - ! a patch exists on each column - - ! find patch index of specified vegetation type - pc = ispval - do p = col%patchi(c), col%patchf(c) - if(patch%itype(p) == col_pftndx(c)) pc = p - enddo + do c = bounds%begc, bounds%endc + if (col%is_hillslope_column(c) .and. col%active(c)) then + ! this may require modifying + ! subgridMod/natveg_patch_exists to ensure that + ! a patch exists on each column + + ! find patch index of specified vegetation type + pc = ispval + do p = col%patchi(c), col%patchf(c) + if(patch%itype(p) == col_pftndx(c)) then + pc = p + exit + endif + enddo - ! only reweight if pft exist within column - if (pc /= ispval) then - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) + ! only reweight if pft exist within column + if (pc /= ispval) then + sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) + sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) + sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtcol(pc) = sum_wtcol - patch%wtlunit(pc) = sum_wtlun - patch%wtgcell(pc) = sum_wtgrc + patch%wtcol(pc) = sum_wtcol + patch%wtlunit(pc) = sum_wtlun + patch%wtgcell(pc) = sum_wtgrc - else - write(iulog,*) 'no pft in column ',c, col_pftndx(c) - write(iulog,*) 'pfts ',c,patch%itype(col%patchi(c):col%patchf(c)) - write(iulog,*) 'weights ',c,patch%wtcol(col%patchi(c):col%patchf(c)) - write(iulog,*) 'location ',c,grc%londeg(col%gridcell(c)),grc%latdeg(col%gridcell(c)) + else + write(iulog,*) 'no pft in column ',c, col_pftndx(c) + write(iulog,*) 'pfts ',c,patch%itype(col%patchi(c):col%patchf(c)) + write(iulog,*) 'weights ',c,patch%wtcol(col%patchi(c):col%patchf(c)) + write(iulog,*) 'location ',c,grc%londeg(col%gridcell(c)),grc%latdeg(col%gridcell(c)) - endif endif - enddo ! end loop c - enddo ! end loop l + endif + enddo ! end loop c end subroutine HillslopePftFromFile @@ -1044,16 +1039,16 @@ subroutine HillslopeStreamOutflow(bounds, & integer :: c, l, g, i, j integer :: nstep - real(r8) :: dtime ! land model time step (sec) - real(r8) :: cross_sectional_area ! cross sectional area of stream water (m2) - real(r8) :: stream_depth ! depth of stream water (m) - real(r8) :: hydraulic_radius ! cross sectional area divided by wetted perimeter (m) - real(r8) :: flow_velocity ! flow velocity (m/s) - real(r8) :: overbank_area ! area of water above bankfull (m2) - real(r8), parameter :: manning_roughness = 0.03 ! manning roughness - real(r8), parameter :: manning_exponent = 0.667 ! manning exponent - - integer, parameter :: overbank_method = 1 ! method to treat overbank stream storage; 1 = increase dynamic slope, 2 = increase flow area cross section, 3 = remove instantaneously + real(r8) :: dtime ! land model time step (sec) + real(r8) :: cross_sectional_area ! cross sectional area of stream water (m2) + real(r8) :: stream_depth ! depth of stream water (m) + real(r8) :: hydraulic_radius ! cross sectional area divided by wetted perimeter (m) + real(r8) :: flow_velocity ! flow velocity (m/s) + real(r8) :: overbank_area ! area of water above bankfull (m2) + real(r8), parameter :: manning_roughness = 0.03_r8 ! manning roughness + real(r8), parameter :: manning_exponent = 0.667_r8 ! manning exponent + + integer, parameter :: overbank_method = 1 ! method to treat overbank stream storage; 1 = increase dynamic slope, 2 = increase flow area cross section, 3 = remove instantaneously character(len=*), parameter :: subname = 'HillslopeStreamOutflow' !----------------------------------------------------------------------- @@ -1108,8 +1103,8 @@ subroutine HillslopeStreamOutflow(bounds, & qstreamflow(l) = cross_sectional_area * flow_velocity endif - ! scale streamflow by number of channel 'branches' - qstreamflow(l) = qstreamflow(l) * lun%stream_channel_number(l) * 1e3 + ! scale streamflow by number of channel reaches + qstreamflow(l) = qstreamflow(l) * lun%stream_channel_number(l) qstreamflow(l) = max(0._r8,min(qstreamflow(l),stream_water_volume(l)/dtime)) endif diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 77429563cf..3e31eb94ae 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2039,7 +2039,7 @@ subroutine SubsurfaceLateralFlow(bounds, & real(r8) :: drainage_layer ! drainage to be removed from current layer (mm) real(r8) :: s_y ! specific yield (unitless) real(r8) :: vol_ice ! volumetric ice content (mm3/mm3) - logical :: no_lateral_flow = .false. ! flag for testing + logical, parameter :: no_lateral_flow = .false. ! flag for testing real(r8) :: transmis ! transmissivity (m2/s) real(r8) :: head_gradient ! hydraulic head gradient (m/m) real(r8) :: stream_water_depth ! depth of water in stream channel (m) @@ -2153,13 +2153,10 @@ subroutine SubsurfaceLateralFlow(bounds, & ! Hillslope columns if (col%is_hillslope_column(c) .and. col%active(c)) then - ! kinematic wave approximation + ! method for calculating head gradient if (head_gradient_method == kinematic) then head_gradient = col%hill_slope(c) - endif - - ! darcy's law - if (head_gradient_method == darcy) then + else if (head_gradient_method == darcy) then if (col%cold(c) /= ispval) then head_gradient = (col%hill_elev(c)-zwt(c)) & - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) @@ -2193,6 +2190,8 @@ subroutine SubsurfaceLateralFlow(bounds, & head_gradient = head_gradient - 1._r8/k_anisotropic endif endif + else + call endrun(msg="head_gradient_method must be kinematic or darcy"//errmsg(sourcefile, __LINE__)) end if !scs: in cases of bad data, where hand differences in @@ -2232,11 +2231,12 @@ subroutine SubsurfaceLateralFlow(bounds, & endif endif end do - endif ! constant conductivity based on shallowest saturated layer hk - if (transmissivity_method == uniform_transmissivity) then + else if (transmissivity_method == uniform_transmissivity) then transmis = (1.e-3_r8*ice_imped(c_src,jwt(c_src)+1)*hksat(c_src,jwt(c_src)+1)) & *(zi(c_src,nbedrock(c_src)) - zwt(c_src) ) + else + call endrun(msg="transmissivity_method must be LayerSum or Uniform"//errmsg(sourcefile, __LINE__)) endif endif else diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index 9dfc59858c..a34ac3c951 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -391,7 +391,6 @@ subroutine CanopySunShadeFracs(filter_nourbanp, num_nourbanp, & associate( tlai_z => surfalb_inst%tlai_z_patch, & ! tlai increment for canopy layer fsun_z => surfalb_inst%fsun_z_patch, & ! sunlit fraction of canopy layer elai => canopystate_inst%elai_patch, & ! one-sided leaf area index - forc_solad => atm2lnd_inst%forc_solad_not_downscaled_grc, & ! direct beam radiation, gridcell (W/m**2) forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col, & ! direct beam radiation, column (W/m**2) forc_solai => atm2lnd_inst%forc_solai_grc, & ! diffuse radiation (W/m**2) fabd_sun_z => surfalb_inst%fabd_sun_z_patch, & ! absorbed sunlit leaf direct PAR diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index b3376ed124..2ab92fead2 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -509,7 +509,8 @@ subroutine InitHistory(this, bounds) units='mm/s', & avgflag='A', & long_name=this%info%lname('hillcol lateral outflow'), & - ptr_col=this%qflx_latflow_out_col, c2l_scale_type='urbanf') + l2g_scale_type='natveg', c2l_scale_type='urbanf', & + ptr_col=this%qflx_latflow_out_col) this%qdischarge_col(begc:endc) = spval call hist_addfld1d ( & @@ -517,7 +518,8 @@ subroutine InitHistory(this, bounds) units='m3/s', & avgflag='A', & long_name=this%info%lname('hillslope discharge from column'), & - ptr_col=this%qdischarge_col, c2l_scale_type='urbanf') + l2g_scale_type='natveg', c2l_scale_type='urbanf', & + ptr_col=this%qdischarge_col) if (use_hillslope_routing) then this%qstreamflow_lun(begl:endl) = spval @@ -526,7 +528,7 @@ subroutine InitHistory(this, bounds) units='m3/s', & avgflag='A', & long_name=this%info%lname('streamflow discharge'), & - l2g_scale_type='veg', & + l2g_scale_type='natveg', & ptr_lunit=this%qstreamflow_lun) endif endif diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 44a89b7cff..4a8b7c4355 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -667,9 +667,9 @@ subroutine Restart(this, bounds, ncid, flag, & units='m3', & interpinic_flag='interp', readvar=readvar, data=this%stream_water_volume_lun) - if (flag == 'read' .and. .not. is_restart()) then - this%stream_water_volume_lun(bounds%begl:bounds%endl) = 0._r8 - end if +!!$ if (flag == 'read' .and. .not. is_restart()) then +!!$ this%stream_water_volume_lun(bounds%begl:bounds%endl) = 0._r8 +!!$ end if ! Determine volumetric soil water (for read only) if (flag == 'read' ) then From 66e6fbcc883dad8cc157d8723cce84fad3b25cd0 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 26 May 2022 13:46:07 -0600 Subject: [PATCH 073/153] add namelist variables for pft distribution --- bld/CLMBuildNamelist.pm | 1 + bld/namelist_files/namelist_defaults_ctsm.xml | 1 + .../namelist_definition_ctsm.xml | 5 ++ src/biogeophys/HillslopeHydrologyMod.F90 | 73 +++++++++++++------ src/biogeophys/WaterStateType.F90 | 4 - 5 files changed, 59 insertions(+), 25 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 9ecff7ea1b..e520b09403 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3247,6 +3247,7 @@ sub setup_logic_hillslope { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'downscale_hillslope_meteorology' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_head_gradient_method' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_transmissivity_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_pft_distribution_method' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope_routing', 'use_hillslope'=>$nl_flags->{'use_hillslope'} ); my $use_hillslope = $nl->get_value('use_hillslope'); my $use_hillslope_routing = $nl->get_value('use_hillslope_routing'); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index e9aca8700f..f4b635869d 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -602,6 +602,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. Darcy LayerSum +Standard .true. diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 82f4cb4bac..8a4dc34a0c 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -754,6 +754,11 @@ Method for calculating hillslope saturated head gradient Method for calculating transmissivity of hillslope columns + +Method for distributing pfts across hillslope columns + + Toggle to turn on the plant hydraulic stress model diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 8a14cfa24f..6b4579e498 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -34,6 +34,7 @@ module HillslopeHydrologyMod integer, public :: head_gradient_method ! Method for calculating hillslope saturated head gradient integer, public :: transmissivity_method ! Method for calculating transmissivity of hillslope columns + integer, public :: pft_distribution_method ! Method for distributing pfts across hillslope columns ! Head gradient methods integer, public, parameter :: kinematic = 0 @@ -42,7 +43,13 @@ module HillslopeHydrologyMod integer, public, parameter :: uniform_transmissivity = 0 integer, public, parameter :: layersum = 1 ! Streamflow methods - integer, public, parameter :: streamflow_manning = 0 + integer, public, parameter :: streamflow_manning = 0 + ! Pft distribution methods + integer, public, parameter :: pft_standard = 0 + integer, public, parameter :: pft_from_file = 1 + integer, public, parameter :: pft_uniform_dominant_pft = 2 + integer, public, parameter :: pft_lowland_dominant_pft = 3 + integer, public, parameter :: pft_lowland_upland = 4 ! PRIVATE character(len=*), parameter, private :: sourcefile = & @@ -76,19 +83,22 @@ subroutine read_hillslope_hydrology_namelist() integer :: nml_error ! namelist i/o error flag character(len=*), parameter :: nmlname = 'hillslope_hydrology_inparm' character(*), parameter :: subName = "('read_hillslope_hydrology_namelist')" - character(len=50) :: hillslope_head_gradient_method = 'Darcy' ! head gradient method string + character(len=50) :: hillslope_head_gradient_method = 'Darcy' ! head gradient method string character(len=50) :: hillslope_transmissivity_method = 'LayerSum' ! transmissivity method string + character(len=50) :: hillslope_pft_distribution_method = 'Standard' ! pft distribution method string !----------------------------------------------------------------------- ! MUST agree with name in namelist and read statement namelist /hillslope_hydrology_inparm/ & hillslope_head_gradient_method, & - hillslope_transmissivity_method - + hillslope_transmissivity_method, & + hillslope_pft_distribution_method + ! Default values for namelist - head_gradient_method = darcy - transmissivity_method = layersum - + head_gradient_method = darcy + transmissivity_method = layersum + pft_distribution_method = pft_standard + ! Read hillslope hydrology namelist if (masterproc) then nu_nml = getavu() @@ -116,15 +126,31 @@ subroutine read_hillslope_hydrology_namelist() if ( trim(hillslope_transmissivity_method) == 'Uniform' ) then transmissivity_method = uniform_transmissivity - else if ( trim(hillslope_transmissivity_method) == 'LayerSum' ) then + else if ( trim(hillslope_transmissivity_method) == 'LayerSum') then transmissivity_method = layersum else call endrun(msg="ERROR bad value for hillslope_transmissivity_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) end if + + if ( trim(hillslope_pft_distribution_method) == 'Standard' ) then + pft_distribution_method = pft_standard + else if ( trim(hillslope_pft_distribution_method) == 'FromFile' ) then + pft_distribution_method = pft_from_file + else if ( trim(hillslope_pft_distribution_method) == 'DominantPftUniform') then + pft_distribution_method = pft_uniform_dominant_pft + else if ( trim(hillslope_pft_distribution_method) == 'DominantPftLowland') then + pft_distribution_method = pft_lowland_dominant_pft + else if ( trim(hillslope_pft_distribution_method) == 'PftLowlandUpland') then + pft_distribution_method = pft_lowland_upland + else + call endrun(msg="ERROR bad value for hillslope_transmissivity_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + endif call shr_mpi_bcast(head_gradient_method, mpicom) call shr_mpi_bcast(transmissivity_method, mpicom) + call shr_mpi_bcast(pft_distribution_method, mpicom) if (masterproc) then @@ -132,6 +158,7 @@ subroutine read_hillslope_hydrology_namelist() write(iulog,*) 'hillslope_hydrology settings:' write(iulog,*) ' hillslope_head_gradient_method = ',hillslope_head_gradient_method write(iulog,*) ' hillslope_transmissivity_method = ',hillslope_transmissivity_method + write(iulog,*) ' hillslope_pft_distribution_method = ',hillslope_pft_distribution_method endif @@ -608,27 +635,31 @@ subroutine InitHillslope(bounds,fsurdat) soil_depth_lowland_in=8.0_r8,soil_depth_upland_in=8.0_r8) endif - if ( allocated(hill_pftndx) ) then - deallocate(hill_pftndx) - - call HillslopePftFromFile(bounds,col_pftndx) - - deallocate(col_pftndx) - else - ! Modify pft distributions - ! this may require modifying subgridMod/natveg_patch_exists - ! to ensure patch exists in every gridcell + ! Modify pft distributions + ! this may require modifying subgridMod/natveg_patch_exists + ! to ensure patch exists in every gridcell + if (pft_distribution_method == pft_from_file) then + call HillslopePftFromFile(bounds,col_pftndx) + endif + if (pft_distribution_method == pft_uniform_dominant_pft) then ! Specify single dominant pft per gridcell - !call HillslopeDominantPft(bounds) - + call HillslopeDominantPft(bounds) + endif + if (pft_distribution_method == pft_lowland_dominant_pft) then ! Specify different pfts for uplands / lowlands call HillslopeDominantLowlandPft(bounds) - + endif + if (pft_distribution_method == pft_lowland_upland) then !upland_ivt = 13 ! c3 non-arctic grass !lowland_ivt = 7 ! broadleaf deciduous tree call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) endif + + if ( allocated(hill_pftndx) ) then + deallocate(hill_pftndx) + deallocate(col_pftndx) + endif call ncd_pio_closefile(ncid) diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 4a8b7c4355..3c51865b1c 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -667,10 +667,6 @@ subroutine Restart(this, bounds, ncid, flag, & units='m3', & interpinic_flag='interp', readvar=readvar, data=this%stream_water_volume_lun) -!!$ if (flag == 'read' .and. .not. is_restart()) then -!!$ this%stream_water_volume_lun(bounds%begl:bounds%endl) = 0._r8 -!!$ end if - ! Determine volumetric soil water (for read only) if (flag == 'read' ) then do c = bounds%begc, bounds%endc From cb50d27f5b376a0667b8802a4290bbc7559a8e50 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 26 May 2022 16:26:12 -0600 Subject: [PATCH 074/153] create setSoilLayerClass subroutine --- src/biogeophys/HillslopeHydrologyMod.F90 | 20 ++--- src/main/initVerticalMod.F90 | 99 +++++++++++++++++------- 2 files changed, 77 insertions(+), 42 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 6b4579e498..fe6d6bceea 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -183,7 +183,8 @@ subroutine InitHillslope(bounds,fsurdat) use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil use ncdio_pio - + use initVerticalMod , only : setSoilLayerClass + ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -513,17 +514,6 @@ subroutine InitHillslope(bounds,fsurdat) end if endif enddo - ! from initVertical: - ! integer, parameter :: LEVGRND_CLASS_STANDARD = 1 - ! integer, parameter :: LEVGRND_CLASS_DEEP_BEDROCK = 2 - ! integer, parameter :: LEVGRND_CLASS_SHALLOW_BEDROCK = 3 - - ! just hardcoding for now... - col%levgrnd_class(c, 1:col%nbedrock(c)) = 1 - if (col%nbedrock(c) < nlevsoi) then - col%levgrnd_class(c, (col%nbedrock(c) + 1) : nlevsoi) = 3 - end if - endif if ( allocated(hill_pftndx) ) then col_pftndx(c) = hill_pftndx(l,ci) @@ -620,7 +610,7 @@ subroutine InitHillslope(bounds,fsurdat) end if endif endif - enddo + enddo ! end of landunit loop deallocate(pct_hillslope,hill_ndx,col_ndx,col_dndx, & hill_slope,hill_area,hill_length, & @@ -636,6 +626,10 @@ subroutine InitHillslope(bounds,fsurdat) endif + ! Update layer classes if nbedrock has been modified + call setSoilLayerClass(bounds) + + ! Modify pft distributions ! this may require modifying subgridMod/natveg_patch_exists ! to ensure patch exists in every gridcell diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index 3ea6ef4fe3..efe857a1ca 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -40,7 +40,8 @@ module initVerticalMod public :: initVertical public :: find_soil_layer_containing_depth public :: readParams - + public :: setSoilLayerClass + ! !PRIVATE MEMBER FUNCTIONS: private :: hasBedrock ! true if the given column type includes bedrock layers type, private :: params_type @@ -80,6 +81,71 @@ subroutine readParams( ncid ) end subroutine readParams + !------------------------------------------------------------------------ + subroutine setSoilLayerClass(bounds) + + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + ! + ! LOCAL VARAIBLES: + integer :: c,l,j ! indices + + ! Possible values for levgrnd_class. The important thing is that, for a given column, + ! layers that are fundamentally different (e.g., soil vs bedrock) have different + ! values. This information is used in the vertical interpolation in init_interp. + ! + ! IMPORTANT: These values should not be changed lightly. e.g., try to avoid changing + ! the values assigned to LEVGRND_CLASS_STANDARD, LEVGRND_CLASS_DEEP_BEDROCK, etc. The + ! problem with changing these is that init_interp expects that layers with a value of + ! (e.g.) 1 on the source file correspond to layers with a value of 1 on the + ! destination file. So if you change the values of these constants, you either need to + ! adequately inform users of this change, or build in some translation mechanism in + ! init_interp (such as via adding more metadata to the restart file on the meaning of + ! these different values). + ! + ! The distinction between "shallow" and "deep" bedrock is not made explicitly + ! elsewhere. But, since these classes have somewhat different behavior, they are + ! distinguished explicitly here. + integer, parameter :: LEVGRND_CLASS_STANDARD = 1 + integer, parameter :: LEVGRND_CLASS_DEEP_BEDROCK = 2 + integer, parameter :: LEVGRND_CLASS_SHALLOW_BEDROCK = 3 + + character(len=*), parameter :: subname = 'setSoilLayerClass' + + ! ------------------------------------------------------------------------ + ! Set classes of layers + ! ------------------------------------------------------------------------ + + do c = bounds%begc, bounds%endc + l = col%landunit(c) + if (hasBedrock(col_itype=col%itype(c), lun_itype=lun%itype(l))) then + ! NOTE(wjs, 2015-10-17) We are assuming that points with bedrock have both + ! "shallow" and "deep" bedrock. Currently, this is not true for lake columns: + ! lakes do not distinguish between "shallow" bedrock and "normal" soil. + ! However, that was just due to an oversight that is supposed to be corrected + ! soon; so to keep things simple we assume that any point with bedrock + ! potentially has both shallow and deep bedrock. + col%levgrnd_class(c, 1:col%nbedrock(c)) = LEVGRND_CLASS_STANDARD + if (col%nbedrock(c) < nlevsoi) then + col%levgrnd_class(c, (col%nbedrock(c) + 1) : nlevsoi) = LEVGRND_CLASS_SHALLOW_BEDROCK + end if + col%levgrnd_class(c, (nlevsoi + 1) : nlevmaxurbgrnd) = LEVGRND_CLASS_DEEP_BEDROCK + else + col%levgrnd_class(c, 1:nlevmaxurbgrnd) = LEVGRND_CLASS_STANDARD + end if + end do + + do j = 1, nlevmaxurbgrnd + do c = bounds%begc, bounds%endc + if (col%z(c,j) == spval) then + col%levgrnd_class(c,j) = ispval + end if + end do + end do + + end subroutine setSoilLayerClass + !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) use clm_varcon, only : zmin_bedrock @@ -638,36 +704,11 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) end if end do - ! ------------------------------------------------------------------------ + ! ---------------------------------------------- ! Set classes of layers - ! ------------------------------------------------------------------------ - - do c = bounds%begc, bounds%endc - l = col%landunit(c) - if (hasBedrock(col_itype=col%itype(c), lun_itype=lun%itype(l))) then - ! NOTE(wjs, 2015-10-17) We are assuming that points with bedrock have both - ! "shallow" and "deep" bedrock. Currently, this is not true for lake columns: - ! lakes do not distinguish between "shallow" bedrock and "normal" soil. - ! However, that was just due to an oversight that is supposed to be corrected - ! soon; so to keep things simple we assume that any point with bedrock - ! potentially has both shallow and deep bedrock. - col%levgrnd_class(c, 1:col%nbedrock(c)) = LEVGRND_CLASS_STANDARD - if (col%nbedrock(c) < nlevsoi) then - col%levgrnd_class(c, (col%nbedrock(c) + 1) : nlevsoi) = LEVGRND_CLASS_SHALLOW_BEDROCK - end if - col%levgrnd_class(c, (nlevsoi + 1) : nlevmaxurbgrnd) = LEVGRND_CLASS_DEEP_BEDROCK - else - col%levgrnd_class(c, 1:nlevmaxurbgrnd) = LEVGRND_CLASS_STANDARD - end if - end do + ! ---------------------------------------------- - do j = 1, nlevmaxurbgrnd - do c = bounds%begc, bounds%endc - if (col%z(c,j) == spval) then - col%levgrnd_class(c,j) = ispval - end if - end do - end do + call setSoilLayerClass(bounds) !----------------------------------------------- ! Read in topographic index and slope From c23fee1b7cca2a3f08b51b346cde47bd1aeb856d Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 27 May 2022 08:45:34 -0600 Subject: [PATCH 075/153] modify solar radiation energy balance check --- src/biogeophys/BalanceCheckMod.F90 | 6 ------ src/biogeophys/HillslopeHydrologyMod.F90 | 10 +++------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 2c214a8e0a..8e761b5d08 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -907,14 +907,8 @@ subroutine BalanceCheck( bounds, & ! level because of interactions between columns and since a separate check is done ! in the urban radiation module if (.not. lun%urbpoi(l)) then - ! patch radiation will no longer balance gridcell values - if(col%is_hillslope_column(c)) then errsol(p) = fsa(p) + fsr(p) & - (forc_solad_col(c,1) + forc_solad_col(c,2) + forc_solai(g,1) + forc_solai(g,2)) - else - errsol(p) = fsa(p) + fsr(p) & - - (forc_solad(g,1) + forc_solad(g,2) + forc_solai(g,1) + forc_solai(g,2)) - endif else errsol(p) = spval end if diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index fe6d6bceea..af937cdb8f 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -629,22 +629,18 @@ subroutine InitHillslope(bounds,fsurdat) ! Update layer classes if nbedrock has been modified call setSoilLayerClass(bounds) - ! Modify pft distributions ! this may require modifying subgridMod/natveg_patch_exists ! to ensure patch exists in every gridcell if (pft_distribution_method == pft_from_file) then call HillslopePftFromFile(bounds,col_pftndx) - endif - if (pft_distribution_method == pft_uniform_dominant_pft) then + else if (pft_distribution_method == pft_uniform_dominant_pft) then ! Specify single dominant pft per gridcell call HillslopeDominantPft(bounds) - endif - if (pft_distribution_method == pft_lowland_dominant_pft) then + else if (pft_distribution_method == pft_lowland_dominant_pft) then ! Specify different pfts for uplands / lowlands call HillslopeDominantLowlandPft(bounds) - endif - if (pft_distribution_method == pft_lowland_upland) then + else if (pft_distribution_method == pft_lowland_upland) then !upland_ivt = 13 ! c3 non-arctic grass !lowland_ivt = 7 ! broadleaf deciduous tree call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) From e46c80afb36a87bb4666efbed117e2df501edab0 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 1 Jun 2022 07:53:30 -0600 Subject: [PATCH 076/153] fix circular dependency due to namelist --- bld/CLMBuildNamelist.pm | 2 +- .../namelist_definition_ctsm.xml | 2 +- src/biogeophys/HillslopeHydrologyMod.F90 | 147 ++++++++---------- src/biogeophys/HydrologyDrainageMod.F90 | 2 +- src/biogeophys/SoilHydrologyMod.F90 | 119 +++++++++++++- src/biogeophys/WaterDiagnosticBulkType.F90 | 16 +- src/biogeophys/WaterStateType.F90 | 10 -- src/main/controlMod.F90 | 5 +- 8 files changed, 204 insertions(+), 99 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index e520b09403..215f9b0ef3 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4214,7 +4214,7 @@ sub write_output_files { soilhydrology_inparm luna friction_velocity mineral_nitrogen_dynamics soilwater_movement_inparm rooting_profile_inparm soil_resis_inparm bgc_shared canopyfluxes_inparm aerosol - clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm hillslope_hydrology_inparm + clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm hillslope_hydrology_inparm hillslope_properties_inparm cnprecision_inparm clm_glacier_behavior crop irrigation_inparm surfacealbedo_inparm water_tracers_inparm); diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 8a4dc34a0c..9c5ea98010 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -755,7 +755,7 @@ Method for calculating transmissivity of hillslope columns + group="hillslope_properties_inparm" valid_values="Standard,FromFile,DominantPftUniform,DominantPftLowland,PftLowlandUpland"> Method for distributing pfts across hillslope columns diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index af937cdb8f..e6b096fccb 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -8,13 +8,12 @@ module HillslopeHydrologyMod #include "shr_assert.h" use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg - use spmdMod , only : masterproc + use spmdMod , only : masterproc, iam use abortutils , only : endrun use clm_varctl , only : iulog use clm_varctl , only : use_hillslope_routing use decompMod , only : bounds_type use clm_varcon , only : rpi - use spmdMod , only : masterproc, iam ! !PUBLIC TYPES: implicit none @@ -32,16 +31,9 @@ module HillslopeHydrologyMod public HillslopeStreamOutflow public HillslopeUpdateStreamWater - integer, public :: head_gradient_method ! Method for calculating hillslope saturated head gradient - integer, public :: transmissivity_method ! Method for calculating transmissivity of hillslope columns integer, public :: pft_distribution_method ! Method for distributing pfts across hillslope columns + integer, public :: soil_profile_method ! Method for varying soil thickness across hillslope columns - ! Head gradient methods - integer, public, parameter :: kinematic = 0 - integer, public, parameter :: darcy = 1 - ! Transmissivity methods - integer, public, parameter :: uniform_transmissivity = 0 - integer, public, parameter :: layersum = 1 ! Streamflow methods integer, public, parameter :: streamflow_manning = 0 ! Pft distribution methods @@ -54,18 +46,20 @@ module HillslopeHydrologyMod ! PRIVATE character(len=*), parameter, private :: sourcefile = & __FILE__ - integer, private, parameter :: soil_profile_set_lowland_upland = 0 - integer, private, parameter :: soil_profile_linear = 1 + integer, private, parameter :: soil_profile_uniform = 0 + integer, private, parameter :: soil_profile_from_file = 1 + integer, private, parameter :: soil_profile_set_lowland_upland = 2 + integer, private, parameter :: soil_profile_linear = 3 !----------------------------------------------------------------------- contains !----------------------------------------------------------------------- - subroutine read_hillslope_hydrology_namelist() + subroutine read_hillslope_properties_namelist() ! ! DESCRIPTION - ! read in hillslope hydrology namelist variables + ! read in hillslope hydrology veg/soil properties namelist variables ! ! !USES: use abortutils , only : endrun @@ -81,57 +75,37 @@ subroutine read_hillslope_hydrology_namelist() implicit none integer :: nu_nml ! unit for namelist file integer :: nml_error ! namelist i/o error flag - character(len=*), parameter :: nmlname = 'hillslope_hydrology_inparm' - character(*), parameter :: subName = "('read_hillslope_hydrology_namelist')" - character(len=50) :: hillslope_head_gradient_method = 'Darcy' ! head gradient method string - character(len=50) :: hillslope_transmissivity_method = 'LayerSum' ! transmissivity method string + character(len=*), parameter :: nmlname = 'hillslope_properties_inparm' + character(*), parameter :: subName = "('read_hillslope_properties_namelist')" + ! Default values for namelist character(len=50) :: hillslope_pft_distribution_method = 'Standard' ! pft distribution method string + character(len=50) :: hillslope_soil_profile_method = 'Uniform' ! soil thickness distribution method string !----------------------------------------------------------------------- ! MUST agree with name in namelist and read statement - namelist /hillslope_hydrology_inparm/ & - hillslope_head_gradient_method, & - hillslope_transmissivity_method, & - hillslope_pft_distribution_method + namelist /hillslope_properties_inparm/ & + hillslope_pft_distribution_method, & + hillslope_soil_profile_method - ! Default values for namelist - head_gradient_method = darcy - transmissivity_method = layersum - pft_distribution_method = pft_standard +! pft_distribution_method = pft_standard +! soil_profile_method = soil_profile_uniform ! Read hillslope hydrology namelist if (masterproc) then nu_nml = getavu() open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) - call find_nlgroup_name(nu_nml, 'hillslope_hydrology_inparm', status=nml_error) + call find_nlgroup_name(nu_nml, 'hillslope_properties_inparm', status=nml_error) if (nml_error == 0) then - read(nu_nml, nml=hillslope_hydrology_inparm,iostat=nml_error) + read(nu_nml, nml=hillslope_properties_inparm,iostat=nml_error) if (nml_error /= 0) then - call endrun(subname // ':: ERROR reading hillslope hydrology namelist') + call endrun(subname // ':: ERROR reading hillslope properties namelist') end if else - call endrun(subname // ':: ERROR reading hillslope hydrology namelist') + call endrun(subname // ':: ERROR reading hillslope properties namelist') end if close(nu_nml) call relavu( nu_nml ) - ! Convert namelist strings to numerical values - if ( trim(hillslope_head_gradient_method) == 'Kinematic' ) then - head_gradient_method = kinematic - else if ( trim(hillslope_head_gradient_method) == 'Darcy' ) then - head_gradient_method = darcy - else - call endrun(msg="ERROR bad value for hillslope_head_gradient_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) - end if - - if ( trim(hillslope_transmissivity_method) == 'Uniform' ) then - transmissivity_method = uniform_transmissivity - else if ( trim(hillslope_transmissivity_method) == 'LayerSum') then - transmissivity_method = layersum - else - call endrun(msg="ERROR bad value for hillslope_transmissivity_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) - end if - if ( trim(hillslope_pft_distribution_method) == 'Standard' ) then pft_distribution_method = pft_standard else if ( trim(hillslope_pft_distribution_method) == 'FromFile' ) then @@ -143,26 +117,36 @@ subroutine read_hillslope_hydrology_namelist() else if ( trim(hillslope_pft_distribution_method) == 'PftLowlandUpland') then pft_distribution_method = pft_lowland_upland else - call endrun(msg="ERROR bad value for hillslope_transmissivity_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + call endrun(msg="ERROR bad value for hillslope_pft_distribution_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + + if ( trim(hillslope_soil_profile_method) == 'Uniform' ) then + soil_profile_method = soil_profile_uniform + else if ( trim(hillslope_soil_profile_method) == 'FromFile' ) then + soil_profile_method = soil_profile_from_file + else if ( trim(hillslope_soil_profile_method) == 'SetLowlandUpland' ) then + soil_profile_method = soil_profile_set_lowland_upland + else if ( trim(hillslope_soil_profile_method) == 'Linear') then + soil_profile_method = soil_profile_linear + else + call endrun(msg="ERROR bad value for hillslope_soil_profile_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) end if endif - call shr_mpi_bcast(head_gradient_method, mpicom) - call shr_mpi_bcast(transmissivity_method, mpicom) call shr_mpi_bcast(pft_distribution_method, mpicom) + call shr_mpi_bcast(soil_profile_method, mpicom) if (masterproc) then write(iulog,*) ' ' - write(iulog,*) 'hillslope_hydrology settings:' - write(iulog,*) ' hillslope_head_gradient_method = ',hillslope_head_gradient_method - write(iulog,*) ' hillslope_transmissivity_method = ',hillslope_transmissivity_method + write(iulog,*) 'hillslope_properties settings:' write(iulog,*) ' hillslope_pft_distribution_method = ',hillslope_pft_distribution_method + write(iulog,*) ' hillslope_soil_profile_method = ',hillslope_soil_profile_method endif - end subroutine read_hillslope_hydrology_namelist + end subroutine read_hillslope_properties_namelist !----------------------------------------------------------------------- @@ -222,8 +206,8 @@ subroutine InitHillslope(bounds,fsurdat) !----------------------------------------------------------------------- - ! Read in hillslope_hydrology namelist variables - call read_hillslope_hydrology_namelist() + ! Read in hillslope_properties namelist variables + call read_hillslope_properties_namelist() ! Open surface dataset to read in data below @@ -504,17 +488,23 @@ subroutine InitHillslope(bounds,fsurdat) col%hill_area(c) = hill_area(l,ci) ! azimuth of column col%hill_aspect(c) = hill_aspect(l,ci) - ! pft index of column - if ( allocated(hill_bedrock) ) then - do j = 1,nlevsoi - - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < hill_bedrock(l,ci) .and. zisoi(j) >= hill_bedrock(l,ci)) then - col%nbedrock(c) = j - end if - endif - enddo + ! soil thickness of column + if (soil_profile_method==soil_profile_from_file) then + if ( allocated(hill_bedrock) ) then + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < hill_bedrock(l,ci) .and. zisoi(j) >= hill_bedrock(l,ci)) then + col%nbedrock(c) = j + end if + endif + enddo + else + if (masterproc) then + call endrun( 'ERROR:: soil_profile_method = soil_profile_from_file, but h_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + endif endif + ! pft index of column if ( allocated(hill_pftndx) ) then col_pftndx(c) = hill_pftndx(l,ci) endif @@ -616,14 +606,16 @@ subroutine InitHillslope(bounds,fsurdat) hill_slope,hill_area,hill_length, & hill_width,hill_height,hill_aspect) - if ( allocated(hill_bedrock) ) then - deallocate(hill_bedrock) - else + if(soil_profile_method==soil_profile_from_file) then + if ( allocated(hill_bedrock) ) then + deallocate(hill_bedrock) + endif + else if (soil_profile_method==soil_profile_set_lowland_upland & + .or. soil_profile_method==soil_profile_linear) then ! Modify hillslope soil thickness profile call HillslopeSoilThicknessProfile(bounds,& - soil_profile_method=soil_profile_set_lowland_upland,& + soil_profile_method=soil_profile_method,& soil_depth_lowland_in=8.0_r8,soil_depth_upland_in=8.0_r8) - endif ! Update layer classes if nbedrock has been modified @@ -672,7 +664,6 @@ subroutine HillslopeSoilThicknessProfile(bounds,& use spmdMod , only : masterproc use fileutils , only : getfil use clm_varcon , only : spval, ispval, grlnd - use landunit_varcon , only : istsoil use ncdio_pio ! @@ -772,7 +763,6 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) use LandunitType , only : lun use ColumnType , only : col use clm_varcon , only : ispval - use landunit_varcon , only : istsoil, istcrop use PatchType , only : patch ! ! !ARGUMENTS: @@ -834,7 +824,6 @@ subroutine HillslopeDominantPft(bounds) use ColumnType , only : col use decompMod , only : get_clump_bounds, get_proc_clumps use clm_varcon , only : ispval - use landunit_varcon , only : istsoil use PatchType , only : patch ! ! !ARGUMENTS: @@ -882,7 +871,6 @@ subroutine HillslopeDominantLowlandPft(bounds) use ColumnType , only : col use decompMod , only : get_clump_bounds, get_proc_clumps use clm_varcon , only : ispval - use landunit_varcon , only : istsoil use PatchType , only : patch use pftconMod , only : pftcon, ndllf_evr_tmp_tree, nc3_nonarctic_grass, nc4_grass ! @@ -976,7 +964,6 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) use ColumnType , only : col use decompMod , only : get_clump_bounds, get_proc_clumps use clm_varcon , only : ispval - use landunit_varcon , only : istsoil use PatchType , only : patch use GridcellType , only : grc @@ -1143,7 +1130,7 @@ end subroutine HillslopeStreamOutflow !----------------------------------------------------------------------- subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & - waterfluxbulk_inst,wateratm2lndbulk_inst) + waterfluxbulk_inst,wateratm2lndbulk_inst,waterdiagnosticbulk_inst) ! ! !DESCRIPTION: ! Calculate discharge from stream channel @@ -1155,6 +1142,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & use WaterFluxBulkType , only : waterfluxbulk_type use WaterStateBulkType , only : waterstatebulk_type use Wateratm2lndBulkType, only : wateratm2lndbulk_type + use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type use spmdMod , only : masterproc use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil @@ -1166,7 +1154,8 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst type(wateratm2lndbulk_type), intent(inout) :: wateratm2lndbulk_inst - + type(waterdiagnosticbulk_type), intent(out) :: waterdiagnosticbulk_inst + integer :: c, l, g, i, j real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) real(r8) :: qflx_drain_perched_vol ! volumetric perched water table runoff (m3/s) @@ -1183,7 +1172,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, &! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Input: [real(r8) (:) ] column level correction runoff (mm H2O /s) qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) - stream_water_depth => waterstatebulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) + stream_water_depth => waterdiagnosticbulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) ) ! Get time step diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 63bb048d42..2ec682dca1 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -158,7 +158,7 @@ subroutine HydrologyDrainage(bounds, & call HillslopeUpdateStreamWater(bounds, & waterstatebulk_inst, waterfluxbulk_inst, & - wateratm2lndbulk_inst) + wateratm2lndbulk_inst, waterdiagnosticbulk_inst) endif endif diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 3e31eb94ae..f52da8cd1a 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -32,7 +32,8 @@ module SoilHydrologyMod use TemperatureType , only : temperature_type use LandunitType , only : lun use ColumnType , only : column_type, col - use PatchType , only : patch + use PatchType , only : patch + ! ! !PUBLIC TYPES: implicit none @@ -70,11 +71,106 @@ module SoilHydrologyMod real(r8), private :: baseflow_scalar = 1.e-2_r8 real(r8), parameter :: tolerance = 1.e-12_r8 ! tolerance for checking whether sublimation is greater than ice in top soil layer + integer, private :: head_gradient_method ! Method for calculating hillslope saturated head gradient + integer, private :: transmissivity_method ! Method for calculating transmissivity of hillslope columns + + ! Head gradient methods + integer, parameter, private :: kinematic = 0 + integer, parameter, private :: darcy = 1 + ! Transmissivity methods + integer, parameter, private :: uniform_transmissivity = 0 + integer, parameter, private :: layersum = 1 + character(len=*), parameter, private :: sourcefile = & __FILE__ contains + !----------------------------------------------------------------------- + subroutine hillslope_hydrology_ReadNML(NLFilename) + ! + ! DESCRIPTION + ! read in hillslope hydrology namelist variables related to + ! subsurface lateral flow + ! + ! !USES: + use abortutils , only : endrun + use fileutils , only : getavu, relavu + use spmdMod , only : mpicom, masterproc + use shr_mpi_mod , only : shr_mpi_bcast + use clm_varctl , only : iulog + use clm_nlUtilsMod , only : find_nlgroup_name + + ! !ARGUMENTS: + implicit none + character(len=*), intent(in) :: NLFilename ! Namelist filename + !-------------------------------------------------------------------- + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + character(len=*), parameter :: nmlname = 'hillslope_hydrology_inparm' + character(*), parameter :: subName = "('hillslope_hydrology_ReadNML')" + character(len=50) :: hillslope_head_gradient_method = 'Darcy' ! head gradient method string + character(len=50) :: hillslope_transmissivity_method = 'LayerSum' ! transmissivity method string + !----------------------------------------------------------------------- + +! MUST agree with name in namelist and read statement + namelist /hillslope_hydrology_inparm/ & + hillslope_head_gradient_method, & + hillslope_transmissivity_method + + ! Default values for namelist + head_gradient_method = darcy + transmissivity_method = layersum + + ! Read hillslope hydrology namelist + if (masterproc) then + nu_nml = getavu() + open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call find_nlgroup_name(nu_nml, 'hillslope_hydrology_inparm', status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=hillslope_hydrology_inparm,iostat=nml_error) + if (nml_error /= 0) then + call endrun(subname // ':: ERROR reading hillslope hydrology namelist') + end if + else + call endrun(subname // ':: ERROR reading hillslope hydrology namelist') + end if + close(nu_nml) + call relavu( nu_nml ) + + ! Convert namelist strings to numerical values + if ( trim(hillslope_head_gradient_method) == 'Kinematic' ) then + head_gradient_method = kinematic + else if ( trim(hillslope_head_gradient_method) == 'Darcy' ) then + head_gradient_method = darcy + else + call endrun(msg="ERROR bad value for hillslope_head_gradient_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + + if ( trim(hillslope_transmissivity_method) == 'Uniform' ) then + transmissivity_method = uniform_transmissivity + else if ( trim(hillslope_transmissivity_method) == 'LayerSum') then + transmissivity_method = layersum + else + call endrun(msg="ERROR bad value for hillslope_transmissivity_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) + end if + + endif + + call shr_mpi_bcast(head_gradient_method, mpicom) + call shr_mpi_bcast(transmissivity_method, mpicom) + + if (masterproc) then + + write(iulog,*) ' ' + write(iulog,*) 'hillslope_hydrology lateral flow settings:' + write(iulog,*) ' hillslope_head_gradient_method = ',hillslope_head_gradient_method + write(iulog,*) ' hillslope_transmissivity_method = ',hillslope_transmissivity_method + + endif + + end subroutine hillslope_hydrology_ReadNML + !----------------------------------------------------------------------- subroutine readParams( ncid ) ! @@ -158,6 +254,8 @@ subroutine soilHydReadNML( NLFilename ) end subroutine soilhydReadNML + + !----------------------------------------------------------------------- subroutine SetSoilWaterFractions(bounds, num_hydrologyc, filter_hydrologyc, & soilhydrology_inst, soilstate_inst, waterstatebulk_inst) @@ -1612,8 +1710,6 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & use LandunitType , only : lun use landunit_varcon , only : istsoil use clm_varctl , only : use_hillslope_routing - use HillslopeHydrologyMod, only : head_gradient_method, transmissivity_method - use HillslopeHydrologyMod, only : kinematic,darcy,uniform_transmissivity,layersum ! ! !ARGUMENTS: @@ -1648,6 +1744,14 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & real(r8) :: qflx_drain_perched_vol(bounds%begc:bounds%endc) ! volumetric lateral subsurface flow through active layer [m3/s] real(r8) :: qflx_drain_perched_out(bounds%begc:bounds%endc) ! lateral subsurface flow through active layer [mm/s] +!!$ integer, parameter :: head_gradient_method = 0 +!!$ integer, parameter :: transmissivity_method = 0 +!!$ integer, parameter :: kinematic = 1 +!!$ integer, parameter :: darcy = 0 +!!$ integer, parameter :: uniform_transmissivity = 1 +!!$ integer, parameter :: layersum = 0 + + associate( & nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) @@ -2002,8 +2106,6 @@ subroutine SubsurfaceLateralFlow(bounds, & use GridcellType , only : grc use landunit_varcon , only : istsoil, istcrop use clm_varctl , only : use_hillslope_routing - use HillslopeHydrologyMod, only : head_gradient_method, transmissivity_method - use HillslopeHydrologyMod, only : kinematic,darcy,uniform_transmissivity,layersum ! ! !ARGUMENTS: @@ -2018,6 +2120,13 @@ subroutine SubsurfaceLateralFlow(bounds, & type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst +!!$ integer, parameter :: head_gradient_method = 0 +!!$ integer, parameter :: transmissivity_method = 0 +!!$ integer, parameter :: kinematic = 1 +!!$ integer, parameter :: darcy = 0 +!!$ integer, parameter :: uniform_transmissivity = 1 +!!$ integer, parameter :: layersum = 0 + ! ! !LOCAL VARIABLES: character(len=32) :: subname = 'SubsurfaceLateralFlow' ! subroutine name diff --git a/src/biogeophys/WaterDiagnosticBulkType.F90 b/src/biogeophys/WaterDiagnosticBulkType.F90 index 7804fa3746..f7918d38cb 100644 --- a/src/biogeophys/WaterDiagnosticBulkType.F90 +++ b/src/biogeophys/WaterDiagnosticBulkType.F90 @@ -16,7 +16,7 @@ module WaterDiagnosticBulkType use shr_log_mod , only : errMsg => shr_log_errMsg use decompMod , only : bounds_type use abortutils , only : endrun - use clm_varctl , only : use_cn, iulog, use_luna + use clm_varctl , only : use_cn, iulog, use_luna, use_hillslope use clm_varpar , only : nlevgrnd, nlevsno, nlevcan use clm_varcon , only : spval use LandunitType , only : lun @@ -79,6 +79,9 @@ module WaterDiagnosticBulkType real(r8), pointer :: qflx_prec_intr_patch (:) ! patch interception of precipitation (mm H2O/s) real(r8), pointer :: qflx_prec_grnd_col (:) ! col water onto ground including canopy runoff (mm H2O/s) + ! Hillslope stream variables + real(r8), pointer :: stream_water_depth_lun (:) ! landunit depth of water in the streams (m) + contains ! Public interfaces @@ -221,6 +224,7 @@ subroutine InitBulkAllocate(this, bounds) allocate(this%fdry_patch (begp:endp)) ; this%fdry_patch (:) = nan allocate(this%qflx_prec_intr_patch (begp:endp)) ; this%qflx_prec_intr_patch (:) = nan allocate(this%qflx_prec_grnd_col (begc:endc)) ; this%qflx_prec_grnd_col (:) = nan + allocate(this%stream_water_depth_lun (begl:endl)) ; this%stream_water_depth_lun (:) = nan end subroutine InitBulkAllocate @@ -241,12 +245,14 @@ subroutine InitBulkHistory(this, bounds) ! !LOCAL VARIABLES: integer :: begp, endp integer :: begc, endc + integer :: begl, endl integer :: begg, endg real(r8), pointer :: data2dptr(:,:), data1dptr(:) ! temp. pointers for slicing larger arrays !------------------------------------------------------------------------ begp = bounds%begp; endp= bounds%endp begc = bounds%begc; endc= bounds%endc + begl = bounds%begl; endl= bounds%endl begg = bounds%begg; endg= bounds%endg this%h2osno_total_col(begc:endc) = spval @@ -541,6 +547,14 @@ subroutine InitBulkHistory(this, bounds) long_name=this%info%lname('interception'), & ptr_patch=this%qflx_prec_intr_patch, set_lake=0._r8) + if (use_hillslope) then + this%stream_water_depth_lun(begl:endl) = spval + call hist_addfld1d (fname=this%info%fname('STREAM_WATER_DEPTH'), & + units='m', avgflag='A', & + long_name=this%info%lname('depth of water in stream channel (hillslope hydrology only)'), & + ptr_lunit=this%stream_water_depth_lun, l2g_scale_type='natveg', default='inactive') + endif + end subroutine InitBulkHistory !----------------------------------------------------------------------- diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 3c51865b1c..1479894ae3 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -53,7 +53,6 @@ module WaterStateType ! Hillslope stream variables real(r8), pointer :: stream_water_volume_lun(:) ! landunit volume of water in the streams (m3) - real(r8), pointer :: stream_water_depth_lun (:) ! landunit depth of water in the streams (m) contains @@ -157,9 +156,6 @@ subroutine InitAllocate(this, bounds, tracer_vars) call AllocateVar1d(var = this%stream_water_volume_lun, name = 'stream_water_volume_lun', & container = tracer_vars, & bounds = bounds, subgrid_level = subgrid_level_landunit) - call AllocateVar1d(var = this%stream_water_depth_lun, name = 'stream_water_depth_lun', & - container = tracer_vars, & - bounds = bounds, subgrid_level = subgrid_level_landunit) end subroutine InitAllocate @@ -289,12 +285,6 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) long_name=this%info%lname('volume of water in stream channel (hillslope hydrology only)'), & ptr_lunit=this%stream_water_volume_lun, l2g_scale_type='natveg', default='inactive') - this%stream_water_depth_lun(begl:endl) = spval - call hist_addfld1d (fname=this%info%fname('STREAM_WATER_DEPTH'), units='m', & - avgflag='A', & - long_name=this%info%lname('depth of water in stream channel (hillslope hydrology only)'), & - ptr_lunit=this%stream_water_depth_lun, l2g_scale_type='natveg', default='inactive') - end if ! (rgk 02-02-2017) There is intentionally no entry here for stored plant water diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 6e503d4362..f1f25cb224 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -45,7 +45,7 @@ module controlMod use SoilBiogeochemLittVertTranspMod , only: som_adv_flux, max_depth_cryoturb use SoilBiogeochemVerticalProfileMod , only: surfprof_exp use SoilBiogeochemNitrifDenitrifMod , only: no_frozen_nitrif_denitrif - use SoilHydrologyMod , only: soilHydReadNML + use SoilHydrologyMod , only: soilHydReadNML,hillslope_hydrology_ReadNML use CNFireFactoryMod , only: CNFireReadNML use CanopyFluxesMod , only: CanopyFluxesReadNML use seq_drydep_mod , only: drydep_method, DD_XLND, n_drydep @@ -536,6 +536,9 @@ subroutine control_init(dtime) end if call soilHydReadNML( NLFilename ) + if ( use_hillslope ) then + call hillslope_hydrology_ReadNML( NLFilename ) + endif if ( use_cn ) then call CNFireReadNML( NLFilename ) call CNPrecisionControlReadNML( NLFilename ) From 93d2e17437842a88ae6cf30f0a4442a6e18d8e67 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 3 Jun 2022 07:51:48 -0600 Subject: [PATCH 077/153] modify subgrid weights --- src/biogeophys/HillslopeHydrologyMod.F90 | 158 +++++++++-------------- src/main/clm_initializeMod.F90 | 10 +- src/main/clm_instMod.F90 | 2 +- src/main/surfrdMod.F90 | 40 ++++-- 4 files changed, 101 insertions(+), 109 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index e6b096fccb..c977683e3d 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -22,6 +22,7 @@ module HillslopeHydrologyMod save ! !PUBLIC MEMBER FUNCTIONS: + public hillslope_properties_init public InitHillslope public HillslopeSoilThicknessProfile public HillslopeSetLowlandUplandPfts @@ -30,7 +31,7 @@ module HillslopeHydrologyMod public HillslopePftFromFile public HillslopeStreamOutflow public HillslopeUpdateStreamWater - + integer, public :: pft_distribution_method ! Method for distributing pfts across hillslope columns integer, public :: soil_profile_method ! Method for varying soil thickness across hillslope columns @@ -56,7 +57,7 @@ module HillslopeHydrologyMod contains !----------------------------------------------------------------------- - subroutine read_hillslope_properties_namelist() + subroutine hillslope_properties_init(NLFilename) ! ! DESCRIPTION ! read in hillslope hydrology veg/soil properties namelist variables @@ -67,12 +68,12 @@ subroutine read_hillslope_properties_namelist() use spmdMod , only : mpicom, masterproc use shr_mpi_mod , only : shr_mpi_bcast use clm_varctl , only : iulog - use controlMod , only : NLFilename use clm_nlUtilsMod , only : find_nlgroup_name ! !ARGUMENTS: - !------------------------------------------------------------------------------ implicit none + character(len=*), intent(in) :: NLFilename ! Namelist filename + !---------------------------------------------------------------------- integer :: nu_nml ! unit for namelist file integer :: nml_error ! namelist i/o error flag character(len=*), parameter :: nmlname = 'hillslope_properties_inparm' @@ -146,11 +147,11 @@ subroutine read_hillslope_properties_namelist() endif - end subroutine read_hillslope_properties_namelist + end subroutine hillslope_properties_init !----------------------------------------------------------------------- - subroutine InitHillslope(bounds,fsurdat) + subroutine InitHillslope(bounds,fsurdat,glc_behavior) ! ! !DESCRIPTION: ! Initialize hillslope geomorphology from input dataset @@ -168,11 +169,16 @@ subroutine InitHillslope(bounds,fsurdat) use landunit_varcon , only : istsoil use ncdio_pio use initVerticalMod , only : setSoilLayerClass + use reweightMod , only : reweight_wrapup + use subgridWeightsMod , only : compute_higher_order_weights + use glcBehaviorMod , only : glc_behavior_type + use subgridWeightsMod , only : check_weights ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds character(len=*) , intent(in) :: fsurdat ! surface data file name + type(glc_behavior_type), intent(in) :: glc_behavior integer, pointer :: ihillslope_in(:,:) ! read in - integer integer, pointer :: ncolumns_hillslope_in(:) ! read in number of columns integer, allocatable :: hill_ndx(:,:) ! hillslope index @@ -200,15 +206,11 @@ subroutine InitHillslope(bounds,fsurdat) real(r8) :: ncol_per_hillslope(nhillslope) ! number of columns per hillslope real(r8) :: hillslope_area(nhillslope) ! area of hillslope real(r8) :: nhill_per_landunit(nhillslope) ! total number of each representative hillslope per landunit - real(r8) :: check_weight character(len=*), parameter :: subname = 'InitHillslope' !----------------------------------------------------------------------- - ! Read in hillslope_properties namelist variables - call read_hillslope_properties_namelist() - ! Open surface dataset to read in data below call getfil (fsurdat, locfn, 0) @@ -580,25 +582,13 @@ subroutine InitHillslope(bounds,fsurdat) endif ! Recalculate column weights using input areas - check_weight = 0._r8 do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) if (col%is_hillslope_column(c)) then col%wtlunit(c) = (col%hill_area(c)/hillslope_area(nh)) & * (pct_hillslope(l,nh)*0.01_r8) endif - check_weight = check_weight + col%wtlunit(c) enddo - if (abs(1._r8 - check_weight) > 1.e-6_r8) then - write(iulog,*) 'HillslopeHydrologyMod column reweighting' - write(iulog,*) 'col%wtlunit does not sum to 1: ', check_weight - write(iulog,*) 'weights: ', col%wtlunit(lun%coli(l):lun%colf(l)) - write(iulog,*) 'location: ',grc%londeg(g),grc%latdeg(g) - write(iulog,*) ' ' - if (masterproc) then - call endrun( 'ERROR:: column weights do not sum to 1.'//errmsg(sourcefile, __LINE__) ) - end if - endif endif enddo ! end of landunit loop @@ -633,8 +623,9 @@ subroutine InitHillslope(bounds,fsurdat) ! Specify different pfts for uplands / lowlands call HillslopeDominantLowlandPft(bounds) else if (pft_distribution_method == pft_lowland_upland) then - !upland_ivt = 13 ! c3 non-arctic grass - !lowland_ivt = 7 ! broadleaf deciduous tree + ! example usage: + ! upland_ivt = 13 ! c3 non-arctic grass + ! lowland_ivt = 7 ! broadleaf deciduous tree call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) endif @@ -643,6 +634,18 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(col_pftndx) endif + ! Update higher order weights and check that weights sum to 1 + call compute_higher_order_weights(bounds) + if (masterproc) then + write(iulog,*) 'Checking modified hillslope weights via reweight_wrapup' + end if + + ! filters have not been allocated yet! + ! can check_weights be called directly here? +! call reweight_wrapup(bounds, glc_behavior) +! call check_weights(bounds) + call check_weights(bounds, active_only=.true.) + call ncd_pio_closefile(ncid) end subroutine InitHillslope @@ -755,8 +758,6 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) ! ! !DESCRIPTION: ! Reassign patch weights such that each column has a single pft. - ! upland_ivt/lowland_ivt patches must be allocated - ! in natveg_patch_exists (subgridMod) even if zero weight on fsurdat ! ! !USES @@ -771,43 +772,33 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) integer, intent(in) :: lowland_ivt ! ! !LOCAL VARIABLES: - integer :: nc,p,pu,pl,l,c ! indices - - real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc + integer :: p,c ! indices + integer :: npatches_per_column + logical :: check_npatches = .true. !------------------------------------------------------------------------ - do c = bounds%begc,bounds%endc - if (col%is_hillslope_column(c) .and. col%active(c)) then - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - pl = ispval - pu = ispval + do c = bounds%begc, bounds%endc + if (col%is_hillslope_column(c) .and. col%active(c)) then + ! In preparation for this re-weighting of patch type + ! only first patch was given a non-zero weight in surfrd_hillslope + npatches_per_column = 0 do p = col%patchi(c), col%patchf(c) - if(patch%itype(p) == lowland_ivt) pl = p - if(patch%itype(p) == upland_ivt) pu = p - enddo - - ! only reweight if pfts exist within column - if (pl /= ispval .and. pu /= ispval) then - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - - ! hillbottom + ! lowland if(col%cold(c) == ispval) then - patch%wtcol(pl) = sum_wtcol - patch%wtlunit(pl) = sum_wtlun - patch%wtgcell(pl) = sum_wtgrc - else - patch%wtcol(pu) = sum_wtcol - patch%wtlunit(pu) = sum_wtlun - patch%wtgcell(pu) = sum_wtgrc + patch%itype(p) = lowland_ivt + else ! upland + patch%itype(p) = upland_ivt endif + npatches_per_column = npatches_per_column + 1 + enddo + if (check_npatches) then + if ((npatches_per_column /= 1) .and. masterproc) then + call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) + end if endif endif - enddo ! end loop c + enddo end subroutine HillslopeSetLowlandUplandPfts @@ -817,6 +808,8 @@ subroutine HillslopeDominantPft(bounds) ! !DESCRIPTION: ! Reassign patch weights such that each column has a single pft ! determined by each column's most dominant pft on input dataset. + ! Best performance when used with n_dom_pfts = 1 (Actually, this + ! is probably redundant to behavior with n_dom_pts = 1 and pft_distribution_method = pft_standard) ! ! !USES @@ -864,6 +857,7 @@ subroutine HillslopeDominantLowlandPft(bounds) ! Reassign patch weights such that each column has a single, ! dominant pft. Use largest weight for lowland, 2nd largest ! weight for uplands + ! Best performance when used with n_dom_pfts = 2 ! ! !USES @@ -958,64 +952,40 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) ! ! !DESCRIPTION: ! Reassign patch weights using indices from surface data file + ! Assumes one patch per hillslope column ! ! !USES - use LandunitType , only : lun use ColumnType , only : col - use decompMod , only : get_clump_bounds, get_proc_clumps - use clm_varcon , only : ispval use PatchType , only : patch - use GridcellType , only : grc ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds integer, intent(in) :: col_pftndx(:) ! ! !LOCAL VARIABLES: - integer :: nc,p,pc,l,c ! indices - real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc - + integer :: p,c ! indices + integer :: npatches_per_column + logical :: check_npatches = .true. + !------------------------------------------------------------------------ do c = bounds%begc, bounds%endc if (col%is_hillslope_column(c) .and. col%active(c)) then - ! this may require modifying - ! subgridMod/natveg_patch_exists to ensure that - ! a patch exists on each column - - ! find patch index of specified vegetation type - pc = ispval + ! In preparation for this re-weighting of patch type + ! only first patch was given a non-zero weight in surfrd_hillslope + npatches_per_column = 0 do p = col%patchi(c), col%patchf(c) - if(patch%itype(p) == col_pftndx(c)) then - pc = p - exit - endif + patch%itype(p) = col_pftndx(c) + npatches_per_column = npatches_per_column + 1 enddo - - ! only reweight if pft exist within column - if (pc /= ispval) then - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - - patch%wtcol(pc) = sum_wtcol - patch%wtlunit(pc) = sum_wtlun - patch%wtgcell(pc) = sum_wtgrc - - else - write(iulog,*) 'no pft in column ',c, col_pftndx(c) - write(iulog,*) 'pfts ',c,patch%itype(col%patchi(c):col%patchf(c)) - write(iulog,*) 'weights ',c,patch%wtcol(col%patchi(c):col%patchf(c)) - write(iulog,*) 'location ',c,grc%londeg(col%gridcell(c)),grc%latdeg(col%gridcell(c)) - + if (check_npatches) then + if ((npatches_per_column /= 1) .and. masterproc) then + call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) + end if endif endif - enddo ! end loop c + enddo end subroutine HillslopePftFromFile diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index ba2bae4c89..1b6a5ae4ae 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -63,8 +63,9 @@ subroutine initialize1(dtime) use UrbanParamsType , only: IsSimpleBuildTemp use dynSubgridControlMod , only: dynSubgridControl_init use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_par_init - use CropReprPoolsMod , only: crop_repr_pools_init - + use CropReprPoolsMod , only: crop_repr_pools_init + use HillslopeHydrologyMod, only: hillslope_properties_init + ! ! !ARGUMENTS integer, intent(in) :: dtime ! model time step (seconds) @@ -106,7 +107,8 @@ subroutine initialize1(dtime) if (masterproc) call control_print() call dynSubgridControl_init(NLFilename) call crop_repr_pools_init() - + call hillslope_properties_init(NLFilename) + call t_stopf('clm_init1') end subroutine initialize1 @@ -125,7 +127,7 @@ subroutine initialize2(ni,nj) use clm_varctl , only : finidat, finidat_interp_source, finidat_interp_dest, fsurdat use clm_varctl , only : use_cn, use_fates use clm_varctl , only : use_crop, ndep_from_cpl, fates_spitfire_mode - use clm_varctl , only: use_hillslope + use clm_varctl , only : use_hillslope use clm_varorb , only : eccen, mvelpp, lambm0, obliqr use landunit_varcon , only : landunit_varcon_init, max_lunit, numurbl use pftconMod , only : pftcon diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index fbd728c10b..7e02a8f9aa 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -298,7 +298,7 @@ subroutine clm_instInit(bounds) call canopystate_inst%Init(bounds) if(use_hillslope) then - call InitHillslope(bounds, fsurdat) + call InitHillslope(bounds, fsurdat, glc_behavior) endif call soilstate_inst%Init(bounds) diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index f794ac5e09..7bb5022abc 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -72,7 +72,7 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, actual_numcft) use clm_varctl , only : create_crop_landunit, collapse_urban, & toosmall_soil, toosmall_crop, toosmall_glacier, & toosmall_lake, toosmall_wetland, toosmall_urban, & - n_dom_landunits, use_hillslope + n_dom_landunits use fileutils , only : getfil use domainMod , only : domain_type, domain_init, domain_clean use clm_instur , only : wt_lunit, topo_glc_mec, pct_urban_max @@ -191,11 +191,6 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, actual_numcft) call surfrd_veg_all(begg, endg, ncid, ldomain%ns, actual_numcft) - ! Obtain hillslope hydrology info - if(use_hillslope) then - call surfrd_hillslope(begg, endg, ncid, ldomain%ns) - endif - if (use_cndv) then call surfrd_veg_dgvm(begg, endg) end if @@ -601,7 +596,7 @@ subroutine surfrd_veg_all(begg, endg, ncid, ns, actual_numcft) ! Determine weight arrays for non-dynamic landuse mode ! ! !USES: - use clm_varctl , only : create_crop_landunit, use_fates, n_dom_pfts + use clm_varctl , only : create_crop_landunit, use_fates, n_dom_pfts, use_hillslope use clm_varpar , only : natpft_lb, natpft_ub, natpft_size, cft_size, cft_lb, cft_ub use clm_instur , only : wt_lunit, wt_nat_patch, wt_cft, fert_cft use landunit_varcon , only : istsoil, istcrop @@ -691,6 +686,12 @@ subroutine surfrd_veg_all(begg, endg, ncid, ns, actual_numcft) ' must also have a separate crop landunit, and vice versa)'//& errMsg(sourcefile, __LINE__)) end if + + ! Obtain hillslope hydrology information and modify pft weights + if(use_hillslope) then + call surfrd_hillslope(begg, endg, ncid, ns) + endif + ! Convert from percent to fraction wt_lunit(begg:endg,istsoil) = wt_lunit(begg:endg,istsoil) / 100._r8 wt_lunit(begg:endg,istcrop) = wt_lunit(begg:endg,istcrop) / 100._r8 @@ -760,9 +761,12 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! Determine number of hillslopes and columns for hillslope hydrology mode ! ! !USES: - use clm_instur, only : ncolumns_hillslope + use clm_instur, only : ncolumns_hillslope, wt_nat_patch use clm_varctl, only : nhillslope,max_columns_hillslope - use ncdio_pio , only : ncd_inqdid, ncd_inqdlen + use clm_varpar, only : natpft_size, natpft_lb + use ncdio_pio, only : ncd_inqdid, ncd_inqdlen + use pftconMod , only : noveg + use HillslopeHydrologyMod, only : pft_distribution_method, pft_from_file, pft_lowland_upland ! ! !ARGUMENTS: integer, intent(in) :: begg, endg @@ -770,7 +774,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) integer ,intent(in) :: ns ! domain size ! ! !LOCAL VARIABLES: - integer :: nh, m ! index + integer :: g, nh, m ! index integer :: dimid,varid ! netCDF id's integer :: ier ! error status logical :: readvar ! is variable on dataset @@ -805,6 +809,22 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) endif deallocate(arrayl) + ! pft_from_file assumes that 1 pft will exist on each + ! hillslope column. In prepration, set one pft weight + ! to 100 and the rest to 0. This will be reassigned when + ! initHillslope is called later. + if(pft_distribution_method == pft_from_file .or. & + pft_distribution_method == pft_lowland_upland) then + do g = begg, endg + ! If hillslopes will be used in a gridcell, modify wt_nat_patch, otherwise use original patch distribution + if(ncolumns_hillslope(g) > 0) then + ! First patch gets 100% weight; all other natural patches are zeroed out + wt_nat_patch(g,:) = 0._r8 + wt_nat_patch(g,natpft_lb) = 100._r8 + endif + enddo + endif + end subroutine surfrd_hillslope subroutine surfrd_lakemask(begg, endg) From 8fa676740782cc3cefea3e0c1a978b5685a96669 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 3 Jun 2022 10:00:33 -0600 Subject: [PATCH 078/153] change gridcell average runoff calculation --- src/main/lnd2atmMod.F90 | 42 +++++++++++++++++++++++++++----- src/main/subgridAveMod.F90 | 50 ++------------------------------------ 2 files changed, 38 insertions(+), 54 deletions(-) diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index deb191eb8b..3ed2fa8c7e 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -182,6 +182,9 @@ subroutine lnd2atm(bounds, & ! !LOCAL VARIABLES: integer :: c, l, g ! indices real(r8) :: eflx_sh_ice_to_liq_grc(bounds%begg:bounds%endg) ! sensible heat flux generated from the ice to liquid conversion, averaged to gridcell + real(r8), allocatable :: qflx_surf_col_to_rof(:) ! surface runoff that is sent directly to rof + real(r8), allocatable :: qflx_drain_col_to_rof(:) ! drainagec that is sent directly to rof + real(r8), allocatable :: qflx_drain_perched_col_to_rof(:) ! perched drainage that is sent directly to rof real(r8), parameter :: amC = 12.0_r8 ! Atomic mass number for Carbon real(r8), parameter :: amO = 16.0_r8 ! Atomic mass number for Oxygen real(r8), parameter :: amCO2 = amC + 2.0_r8*amO ! Atomic mass number for CO2 @@ -349,21 +352,48 @@ subroutine lnd2atm(bounds, & enddo ! If hillslope routing is used, exclude inputs to stream channel from gridcell averages to avoid double counting + allocate( & + qflx_surf_col_to_rof(bounds%begc:bounds%endc), & + qflx_drain_col_to_rof(bounds%begc:bounds%endc), & + qflx_drain_perched_col_to_rof(bounds%begc:bounds%endc)) + + qflx_surf_col_to_rof(bounds%begc:bounds%endc) = 0._r8 + qflx_drain_col_to_rof(bounds%begc:bounds%endc) = 0._r8 + qflx_drain_perched_col_to_rof(bounds%begc:bounds%endc) = 0._r8 + + do c = bounds%begc, bounds%endc + ! Exclude hillslope columns from gridcell average + ! hillslope runoff is sent to stream rather than directly + ! to rof, and is accounted for in qflx_rofliq_stream_grc + if (.not. col%is_hillslope_column(c)) then + qflx_surf_col_to_rof(c) = qflx_surf_col_to_rof(c) & + + water_inst%waterfluxbulk_inst%qflx_surf_col(c) + qflx_drain_col_to_rof(c) = qflx_drain_col_to_rof(c) & + + water_inst%waterfluxbulk_inst%qflx_drain_col(c) + qflx_drain_perched_col_to_rof(c) = & + qflx_drain_perched_col_to_rof(c) & + + water_inst%waterfluxbulk_inst%qflx_drain_perched_col(c) + endif + enddo + call c2g( bounds, & - water_inst%waterfluxbulk_inst%qflx_surf_col (bounds%begc:bounds%endc), & + qflx_surf_col_to_rof (bounds%begc:bounds%endc), & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc (bounds%begg:bounds%endg), & - c2l_scale_type= 'urbanf', l2g_scale_type='unity',c2l_scale_type2= 'exclude_hillslope') + c2l_scale_type= 'urbanf', l2g_scale_type='unity') call c2g( bounds, & - water_inst%waterfluxbulk_inst%qflx_drain_col (bounds%begc:bounds%endc), & + qflx_drain_col_to_rof (bounds%begc:bounds%endc), & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc (bounds%begg:bounds%endg), & - c2l_scale_type= 'urbanf', l2g_scale_type='unity',c2l_scale_type2= 'exclude_hillslope') + c2l_scale_type= 'urbanf', l2g_scale_type='unity') call c2g( bounds, & - water_inst%waterfluxbulk_inst%qflx_drain_perched_col (bounds%begc:bounds%endc), & + qflx_drain_perched_col_to_rof (bounds%begc:bounds%endc), & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(bounds%begg:bounds%endg), & - c2l_scale_type= 'urbanf', l2g_scale_type='unity',c2l_scale_type2= 'exclude_hillslope') + c2l_scale_type= 'urbanf', l2g_scale_type='unity') + deallocate(qflx_surf_col_to_rof,qflx_drain_col_to_rof, & + qflx_drain_perched_col_to_rof) + else call c2g( bounds, & diff --git a/src/main/subgridAveMod.F90 b/src/main/subgridAveMod.F90 index 8194d7e884..68431582ce 100644 --- a/src/main/subgridAveMod.F90 +++ b/src/main/subgridAveMod.F90 @@ -164,40 +164,6 @@ subroutine set_c2l_scale (bounds, c2l_scale_type, scale_c2l) end subroutine set_c2l_scale - subroutine set_c2l_scale_hillslope (bounds, c2l_scale_type, scale_c2l) - ! - ! !DESCRIPTION: - ! Set scale_c2l for hillslope c2l_scale_type values - ! set_c2l_scale must be called before set_c2l_scale_hillslope - ! Only hillslope column values are changed - ! - ! !ARGUMENTS: - type(bounds_type), intent(in) :: bounds - character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) - real(r8), intent(inout) :: scale_c2l(bounds%begc:bounds%endc) ! scale factor for column->landunit mapping - - ! - ! !LOCAL VARIABLES: - integer :: c,l ! indices - !------------------------------------------------------------------------ - - ! Enforce expected array sizes - SHR_ASSERT_ALL_FL((ubound(scale_c2l) == (/bounds%endc/)), sourcefile, __LINE__) - - if (c2l_scale_type == 'exclude_hillslope') then - do c = bounds%begc,bounds%endc - ! Only modify values of hillslope columns - if (col%is_hillslope_column(c)) then - scale_c2l(c) = 0.0_r8 - endif - enddo - else - write(iulog,*)'set_c2l_scale: scale type ',c2l_scale_type,' not supported' - call endrun(msg=errMsg(sourcefile, __LINE__)) - end if - - end subroutine set_c2l_scale_hillslope - !----------------------------------------------------------------------- subroutine p2c_1d (bounds, parr, carr, p2c_scale_type) ! @@ -792,7 +758,7 @@ subroutine c2l_2d (bounds, num2d, carr, larr, c2l_scale_type) end subroutine c2l_2d !----------------------------------------------------------------------- - subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type, c2l_scale_type2) + subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type) ! ! !DESCRIPTION: ! Perfrom subgrid-average from columns to gridcells. @@ -804,7 +770,6 @@ subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type, c2l_scale_ real(r8), intent(out) :: garr( bounds%begg: ) ! output gridcell array character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging - character(len=*), intent(in), optional :: c2l_scale_type2 ! second scale factor type ! ! !LOCAL VARIABLES: integer :: c,l,g,index ! indices @@ -823,11 +788,6 @@ subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type, c2l_scale_ call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) - ! Adjust scale_c2l for hillslope columns only - if (present(c2l_scale_type2)) then - call set_c2l_scale_hillslope (bounds, c2l_scale_type2, scale_c2l) - endif - garr(bounds%begg : bounds%endg) = spval sumwt(bounds%begg : bounds%endg) = 0._r8 do c = bounds%begc,bounds%endc @@ -858,7 +818,7 @@ subroutine c2g_1d(bounds, carr, garr, c2l_scale_type, l2g_scale_type, c2l_scale_ end subroutine c2g_1d !----------------------------------------------------------------------- - subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type, c2l_scale_type2) + subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type) ! ! !DESCRIPTION: ! Perfrom subgrid-average from columns to gridcells. @@ -871,7 +831,6 @@ subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type, c2l real(r8), intent(out) :: garr( bounds%begg: , 1: ) ! output gridcell array character(len=*), intent(in) :: c2l_scale_type ! scale factor type for averaging (see note at top of module) character(len=*), intent(in) :: l2g_scale_type ! scale factor type for averaging - character(len=*), intent(in), optional :: c2l_scale_type2 ! second scale factor type ! ! !LOCAL VARIABLES: integer :: j,c,g,l,index ! indices @@ -890,11 +849,6 @@ subroutine c2g_2d(bounds, num2d, carr, garr, c2l_scale_type, l2g_scale_type, c2l call set_c2l_scale (bounds, c2l_scale_type, scale_c2l) - ! Adjust scale_c2l for hillslope columns only - if (present(c2l_scale_type2)) then - call set_c2l_scale_hillslope (bounds, c2l_scale_type2, scale_c2l) - endif - garr(bounds%begg : bounds%endg,:) = spval do j = 1,num2d sumwt(bounds%begg : bounds%endg) = 0._r8 From 36627d836052f899dd9b05446025791b57d590b8 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 7 Jun 2022 13:32:20 -0600 Subject: [PATCH 079/153] remove qdischarge from HillslopeUpdateStreamWater --- src/biogeophys/HillslopeHydrologyMod.F90 | 25 ++++++++++++------------ src/biogeophys/HydrologyDrainageMod.F90 | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index c977683e3d..270252adfd 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -1100,7 +1100,7 @@ end subroutine HillslopeStreamOutflow !----------------------------------------------------------------------- subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & - waterfluxbulk_inst,wateratm2lndbulk_inst,waterdiagnosticbulk_inst) + waterfluxbulk_inst,waterdiagnosticbulk_inst) ! ! !DESCRIPTION: ! Calculate discharge from stream channel @@ -1111,7 +1111,6 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & use ColumnType , only : col use WaterFluxBulkType , only : waterfluxbulk_type use WaterStateBulkType , only : waterstatebulk_type - use Wateratm2lndBulkType, only : wateratm2lndbulk_type use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type use spmdMod , only : masterproc use clm_varcon , only : spval, ispval, grlnd @@ -1123,13 +1122,12 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & type(bounds_type), intent(in) :: bounds type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst - type(wateratm2lndbulk_type), intent(inout) :: wateratm2lndbulk_inst type(waterdiagnosticbulk_type), intent(out) :: waterdiagnosticbulk_inst integer :: c, l, g, i, j real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) - real(r8) :: qflx_drain_perched_vol ! volumetric perched water table runoff (m3/s) - real(r8) :: qflx_rsub_sat_vol ! volumetric correction runoff (m3/s) + real(r8) :: qflx_drain_perched_vol ! volumetric perched saturated drainage (m3/s) + real(r8) :: qflx_drain_vol ! volumetric saturated drainage (m3/s) real(r8) :: dtime ! land model time step (sec) character(len=*), parameter :: subname = 'HillslopeUpdateStreamWater' @@ -1138,9 +1136,8 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun, & ! Input/Output: [real(r8) (:) ] stream water volume (m3) qstreamflow => waterfluxbulk_inst%qstreamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) - qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Input: [real(r8) (:) ] discharge from columns (m3/s) - qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, &! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) - qflx_rsub_sat => waterfluxbulk_inst%qflx_rsub_sat_col , & ! Input: [real(r8) (:) ] column level correction runoff (mm H2O /s) + qflx_drain => waterfluxbulk_inst%qflx_drain_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) + qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) stream_water_depth => waterdiagnosticbulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) ) @@ -1151,19 +1148,21 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & do l = bounds%begl,bounds%endl if(lun%itype(l) == istsoil) then g = lun%gridcell(l) - + ! the drainage terms are 'net' quantities, so summing over + ! all columns in a hillslope is equivalent to the outflow + ! from the lowland column do c = lun%coli(l), lun%colf(l) if (col%is_hillslope_column(c) .and. col%active(c)) then qflx_surf_vol = qflx_surf(c)*1.e-3_r8 & *(grc%area(g)*1.e6_r8*col%wtgcell(c)) qflx_drain_perched_vol = qflx_drain_perched(c)*1.e-3_r8 & *(grc%area(g)*1.e6_r8*col%wtgcell(c)) - ! rsub_sat is not included in qdischarge, so add explicitly - qflx_rsub_sat_vol = qflx_rsub_sat(c)*1.e-3_r8 & + qflx_drain_vol = qflx_drain(c)*1.e-3_r8 & *(grc%area(g)*1.e6_r8*col%wtgcell(c)) + stream_water_volume(l) = stream_water_volume(l) & - + (qdischarge(c) + qflx_drain_perched_vol & - + qflx_rsub_sat_vol + qflx_surf_vol) * dtime + + (qflx_drain_perched_vol & + + qflx_drain_vol + qflx_surf_vol) * dtime endif enddo stream_water_volume(l) = stream_water_volume(l) & diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index 2ec682dca1..ec7c7c76e4 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -158,7 +158,7 @@ subroutine HydrologyDrainage(bounds, & call HillslopeUpdateStreamWater(bounds, & waterstatebulk_inst, waterfluxbulk_inst, & - wateratm2lndbulk_inst, waterdiagnosticbulk_inst) + waterdiagnosticbulk_inst) endif endif From 014868e79635688300eb6351ea687ce7eb2fae83 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 15 Jul 2022 13:18:46 -0600 Subject: [PATCH 080/153] minor cleanup --- src/biogeophys/HillslopeHydrologyMod.F90 | 51 +++++++++--------------- src/biogeophys/IrrigationMod.F90 | 9 ++++- src/biogeophys/SoilHydrologyMod.F90 | 10 ++--- src/biogeophys/SurfaceAlbedoType.F90 | 2 +- src/biogeophys/SurfaceRadiationMod.F90 | 12 +++--- src/biogeophys/WaterFluxType.F90 | 24 +++++------ src/main/TopoMod.F90 | 23 +++++++---- src/main/lnd2atmMod.F90 | 2 +- 8 files changed, 67 insertions(+), 66 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 270252adfd..0f0a3e70d3 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -558,27 +558,14 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) lun%stream_channel_length(l) = 0.5_r8 * lun%stream_channel_length(l) endif - ! if missing hillslope information on surface dataset, fill data - ! and recalculate hillslope_area + ! if missing hillslope information on surface dataset, + ! call endrun if (sum(hillslope_area) == 0._r8) then - do c = lun%coli(l), lun%colf(l) - nh = col%hillslope_ndx(c) - col%hill_area(c) = (grc%area(g)/real(lun%ncolumns(l),r8))*1.e6_r8 ! km2 to m2 - col%hill_width(c) = sqrt(col%hill_area(c)) - col%hill_slope(c) = tan((rpi/180.)*col%topo_slope(c)) - col%hill_aspect(c) = (rpi/2.) ! east (arbitrarily chosen) - if (nh > 0) then - col%hill_elev(c) = col%topo_std(c) & - *((c-lun%coli(l))/ncol_per_hillslope(nh)) - col%hill_distance(c) = sqrt(col%hill_area(c)) & - *((c-lun%coli(l))/ncol_per_hillslope(nh)) - pct_hillslope(l,nh) = 100/nhillslope - else - col%hill_elev(c) = col%topo_std(c) - col%hill_distance(c) = sqrt(col%hill_area(c)) - endif - enddo - + if (masterproc) then + write(iulog,*) 'Problem with input data: nhillcolumns is non-zero, but hillslope area is zero' + write(iulog,*) 'Check surface data for gridcell at (lon/lat): ', grc%londeg(g),grc%latdeg(g) + call endrun( 'ERROR:: sum of hillslope areas is zero.'//errmsg(sourcefile, __LINE__) ) + end if endif ! Recalculate column weights using input areas @@ -1032,14 +1019,14 @@ subroutine HillslopeStreamOutflow(bounds, & !----------------------------------------------------------------------- associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) - qstreamflow => waterfluxbulk_inst%qstreamflow_lun & ! Input: [real(r8) (:) ] stream water discharge (m3/s) + volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun & ! Input: [real(r8) (:) ] stream water discharge (m3/s) ) ! Get time step dtime = get_step_size_real() do l = bounds%begl,bounds%endl - qstreamflow(l) = 0._r8 + volumetric_streamflow(l) = 0._r8 if(lun%itype(l) == istsoil .and. lun%active(l)) then ! Streamflow calculated from Manning equation if(streamflow_method == streamflow_manning) then @@ -1051,7 +1038,7 @@ subroutine HillslopeStreamOutflow(bounds, & /(lun%stream_channel_width(l) + 2*stream_depth) if(hydraulic_radius <= 0._r8) then - qstreamflow(l) = 0._r8 + volumetric_streamflow(l) = 0._r8 else flow_velocity = (hydraulic_radius)**manning_exponent & * sqrt(lun%stream_channel_slope(l)) & @@ -1060,15 +1047,15 @@ subroutine HillslopeStreamOutflow(bounds, & if (stream_depth > lun%stream_channel_depth(l)) then if (overbank_method == 1) then ! try increasing dynamic slope - qstreamflow(l) = cross_sectional_area * flow_velocity & + volumetric_streamflow(l) = cross_sectional_area * flow_velocity & *(stream_depth/lun%stream_channel_depth(l)) else if (overbank_method == 2) then ! try increasing flow area cross section overbank_area = (stream_depth -lun%stream_channel_depth(l)) * 30._r8 * lun%stream_channel_width(l) - qstreamflow(l) = (cross_sectional_area + overbank_area) * flow_velocity + volumetric_streamflow(l) = (cross_sectional_area + overbank_area) * flow_velocity else if (overbank_method == 3) then ! try removing all overbank flow instantly - qstreamflow(l) = cross_sectional_area * flow_velocity & + volumetric_streamflow(l) = cross_sectional_area * flow_velocity & + (stream_depth-lun%stream_channel_depth(l)) & *lun%stream_channel_width(l)*lun%stream_channel_length(l)/dtime else @@ -1078,13 +1065,13 @@ subroutine HillslopeStreamOutflow(bounds, & endif else - qstreamflow(l) = cross_sectional_area * flow_velocity + volumetric_streamflow(l) = cross_sectional_area * flow_velocity endif ! scale streamflow by number of channel reaches - qstreamflow(l) = qstreamflow(l) * lun%stream_channel_number(l) + volumetric_streamflow(l) = volumetric_streamflow(l) * lun%stream_channel_number(l) - qstreamflow(l) = max(0._r8,min(qstreamflow(l),stream_water_volume(l)/dtime)) + volumetric_streamflow(l) = max(0._r8,min(volumetric_streamflow(l),stream_water_volume(l)/dtime)) endif else if (masterproc) then @@ -1135,7 +1122,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & !----------------------------------------------------------------------- associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun, & ! Input/Output: [real(r8) (:) ] stream water volume (m3) - qstreamflow => waterfluxbulk_inst%qstreamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) + volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) qflx_drain => waterfluxbulk_inst%qflx_drain_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) @@ -1166,11 +1153,11 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & endif enddo stream_water_volume(l) = stream_water_volume(l) & - - qstreamflow(l) * dtime + - volumetric_streamflow(l) * dtime ! account for negative drainage (via searchforwater in soilhydrology) if(stream_water_volume(l) < 0._r8) then - qstreamflow(l) = qstreamflow(l) + stream_water_volume(l)/dtime + volumetric_streamflow(l) = volumetric_streamflow(l) + stream_water_volume(l)/dtime stream_water_volume(l) = 0._r8 endif diff --git a/src/biogeophys/IrrigationMod.F90 b/src/biogeophys/IrrigationMod.F90 index 27cf050dd3..c78572f0e8 100644 --- a/src/biogeophys/IrrigationMod.F90 +++ b/src/biogeophys/IrrigationMod.F90 @@ -78,7 +78,7 @@ module IrrigationMod use abortutils , only : endrun use clm_instur , only : irrig_method use pftconMod , only : pftcon - use clm_varctl , only : iulog + use clm_varctl , only : iulog, use_hillslope use clm_varcon , only : isecspday, denh2o, spval, ispval use clm_varpar , only : nlevsoi, nlevgrnd use clm_time_manager , only : get_step_size @@ -362,6 +362,7 @@ subroutine ReadNamelist(this, NLFilename, use_aquifer_layer) use spmdMod , only : masterproc, mpicom use shr_mpi_mod , only : shr_mpi_bcast use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) + ! ! !ARGUMENTS: class(irrigation_type) , intent(inout) :: this @@ -583,6 +584,12 @@ subroutine CheckNamelistValidity(this, use_aquifer_layer) errMsg(sourcefile, __LINE__)) end if + if (use_aquifer_layer .and. use_hillslope) then + write(iulog,*) ' ERROR: use_hillslope and use_aquifer_layer may not be used simultaneously' + call endrun(msg=' ERROR: use_hillslope and use_aquifer_layer cannot both be set to true' // & + errMsg(sourcefile, __LINE__)) + end if + end associate end subroutine CheckNamelistValidity diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index f52da8cd1a..0c3e748055 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2178,7 +2178,7 @@ subroutine SubsurfaceLateralFlow(bounds, & hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) qflx_latflow_out => waterfluxbulk_inst%qflx_latflow_out_col, & ! Output: [real(r8) (:) ] lateral saturated outflow (mm/s) qflx_latflow_in => waterfluxbulk_inst%qflx_latflow_in_col, & ! Output: [real(r8) (:) ] lateral saturated inflow (mm/s) - qdischarge => waterfluxbulk_inst%qdischarge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) + volumetric_discharge => waterfluxbulk_inst%volumetric_discharge_col , & ! Output: [real(r8) (:) ] discharge from column (m3/s) tdepth => wateratm2lndbulk_inst%tdepth_grc , & ! Input: [real(r8) (:) ] depth of water in tributary channels (m) tdepth_bankfull => wateratm2lndbulk_inst%tdepthmax_grc , & ! Input: [real(r8) (:) ] bankfull depth of tributary channels (m) @@ -2224,7 +2224,7 @@ subroutine SubsurfaceLateralFlow(bounds, & qflx_latflow_in(c) = 0._r8 qflx_latflow_out(c) = 0._r8 qflx_net_latflow(c) = 0._r8 - qdischarge(c) = 0._r8 + volumetric_discharge(c) = 0._r8 qflx_latflow_out_vol(c) = 0._r8 end do @@ -2363,10 +2363,10 @@ subroutine SubsurfaceLateralFlow(bounds, & ! include ice impedance in transmissivity qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*head_gradient - ! qdischarge from lowest column is qflx_latflow_out_vol + ! volumetric_discharge from lowest column is qflx_latflow_out_vol ! scaled by total area of column in gridcell divided by column area if (col%cold(c) == ispval) then - qdischarge(c) = qflx_latflow_out_vol(c) & + volumetric_discharge(c) = qflx_latflow_out_vol(c) & *(grc%area(g)*1.e6_r8*col%wtgcell(c)/col%hill_area(c)) endif @@ -2394,7 +2394,7 @@ subroutine SubsurfaceLateralFlow(bounds, & endif ! convert flux to volumetric flow qflx_latflow_out_vol(c) = 1.e-3_r8*qflx_latflow_out(c)*(grc%area(g)*1.e6_r8*col%wtgcell(c)) - qdischarge(c) = qflx_latflow_out_vol(c) + volumetric_discharge(c) = qflx_latflow_out_vol(c) endif enddo diff --git a/src/biogeophys/SurfaceAlbedoType.F90 b/src/biogeophys/SurfaceAlbedoType.F90 index 05cec3ae1a..110df6bfb5 100644 --- a/src/biogeophys/SurfaceAlbedoType.F90 +++ b/src/biogeophys/SurfaceAlbedoType.F90 @@ -203,7 +203,7 @@ subroutine InitHistory(this, bounds) this%coszen_col(begc:endc) = spval call hist_addfld1d (fname='COSZEN', units='none', & - avgflag='A', long_name='cosine of solar zenith angle', & + avgflag='A', long_name='cosine of solar zenith angle (downscaled if downscaling is activated)', & ptr_col=this%coszen_col, default='inactive') this%albgri_col(begc:endc,:) = spval diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index a34ac3c951..558b2bf2ee 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -899,8 +899,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & rnir = albd(p,2)*forc_solad_col(c,2) + albi(p,2)*forc_solai(g,2) fsr(p) = rvis + rnir if (use_SSRE) then - rvisSF = albdSF(p,1)*forc_solad(g,1) + albiSF(p,1)*forc_solai(g,1) - rnirSF = albdSF(p,2)*forc_solad(g,2) + albiSF(p,2)*forc_solai(g,2) + rvisSF = albdSF(p,1)*forc_solad_col(c,1) + albiSF(p,1)*forc_solai(g,1) + rnirSF = albdSF(p,2)*forc_solad_col(c,2) + albiSF(p,2)*forc_solai(g,2) fsrSF(p) = rvisSF + rnirSF ssre_fsr(p) = fsr(p)-fsrSF(p) end if @@ -913,8 +913,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & fsr_vis_i(p) = albi(p,1)*forc_solai(g,1) fsr_nir_i(p) = albi(p,2)*forc_solai(g,2) if (use_SSRE) then - fsrSF_vis_d(p) = albdSF(p,1)*forc_solad(g,1) - fsrSF_nir_d(p) = albdSF(p,2)*forc_solad(g,2) + fsrSF_vis_d(p) = albdSF(p,1)*forc_solad_col(c,1) + fsrSF_nir_d(p) = albdSF(p,2)*forc_solad_col(c,2) fsrSF_vis_i(p) = albiSF(p,1)*forc_solai(g,1) fsrSF_nir_i(p) = albiSF(p,2)*forc_solai(g,2) @@ -940,8 +940,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & end if if (use_SSRE) then if ( is_near_local_noon( grc%londeg(g), deltasec=nint(dtime)/2 ) )then - fsrSF_vis_d_ln(p) = albdSF(p,1)*forc_solad(g,1) - fsrSF_nir_d_ln(p) = albdSF(p,2)*forc_solad(g,2) + fsrSF_vis_d_ln(p) = albdSF(p,1)*forc_solad_col(c,1) + fsrSF_nir_d_ln(p) = albdSF(p,2)*forc_solad_col(c,2) else fsrSF_vis_d_ln(p) = spval fsrSF_nir_d_ln(p) = spval diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index 2ab92fead2..5ac717ca59 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -74,8 +74,8 @@ module WaterFluxType real(r8), pointer :: qflx_drain_col (:) ! col sub-surface runoff (mm H2O /s) real(r8), pointer :: qflx_latflow_in_col (:) ! col hillslope lateral flow input (mm/s) real(r8), pointer :: qflx_latflow_out_col (:) ! col hillslope lateral flow output (mm/s) - real(r8), pointer :: qdischarge_col (:) ! col hillslope discharge (m3/s) - real(r8), pointer :: qstreamflow_lun (:) ! lun stream discharge (m3/s) + real(r8), pointer :: volumetric_discharge_col (:) ! col hillslope discharge (m3/s) + real(r8), pointer :: volumetric_streamflow_lun(:) ! lun stream discharge (m3/s) real(r8), pointer :: qflx_drain_perched_col (:) ! col sub-surface runoff from perched wt (mm H2O /s) real(r8), pointer :: qflx_top_soil_col (:) ! col net water input into soil from top (mm/s) real(r8), pointer :: qflx_floodc_col (:) ! col flood water flux at column level @@ -288,10 +288,10 @@ subroutine InitAllocate(this, bounds, tracer_vars) call AllocateVar1d(var = this%qflx_latflow_out_col, name = 'qflx_latflow_out_col', & container = tracer_vars, & bounds = bounds, subgrid_level = subgrid_level_column) - call AllocateVar1d(var = this%qdischarge_col, name = 'qdischarge_col', & + call AllocateVar1d(var = this%volumetric_discharge_col, name = 'volumetric_discharge_col', & container = tracer_vars, & bounds = bounds, subgrid_level = subgrid_level_column) - call AllocateVar1d(var = this%qstreamflow_lun, name = 'qstreamflow_lun', & + call AllocateVar1d(var = this%volumetric_streamflow_lun, name = 'volumetric_streamflow_lun', & container = tracer_vars, & bounds = bounds, subgrid_level = subgrid_level_landunit) call AllocateVar1d(var = this%qflx_top_soil_col, name = 'qflx_top_soil_col', & @@ -512,24 +512,24 @@ subroutine InitHistory(this, bounds) l2g_scale_type='natveg', c2l_scale_type='urbanf', & ptr_col=this%qflx_latflow_out_col) - this%qdischarge_col(begc:endc) = spval + this%volumetric_discharge_col(begc:endc) = spval call hist_addfld1d ( & - fname=this%info%fname('QDISCHARGE'), & + fname=this%info%fname('VOLUMETRIC_DISCHARGE'), & units='m3/s', & avgflag='A', & long_name=this%info%lname('hillslope discharge from column'), & l2g_scale_type='natveg', c2l_scale_type='urbanf', & - ptr_col=this%qdischarge_col) + ptr_col=this%volumetric_discharge_col) if (use_hillslope_routing) then - this%qstreamflow_lun(begl:endl) = spval + this%volumetric_streamflow_lun(begl:endl) = spval call hist_addfld1d ( & - fname=this%info%fname('QSTREAMFLOW'), & + fname=this%info%fname('VOLUMETRIC_STREAMFLOW'), & units='m3/s', & avgflag='A', & long_name=this%info%lname('streamflow discharge'), & l2g_scale_type='natveg', & - ptr_lunit=this%qstreamflow_lun) + ptr_lunit=this%volumetric_streamflow_lun) endif endif @@ -915,13 +915,13 @@ subroutine InitCold(this, bounds) this%qflx_surf_col(c) = 0._r8 this%qflx_latflow_in_col(c) = 0._r8 this%qflx_latflow_out_col(c) = 0._r8 - this%qdischarge_col(c) = 0._r8 + this%volumetric_discharge_col(c) = 0._r8 end if end do if (use_hillslope_routing) then do l = bounds%begl, bounds%endl if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then - this%qstreamflow_lun(l) = 0._r8 + this%volumetric_streamflow_lun(l) = 0._r8 end if end do endif diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index 5e054ef00c..4e09d4886f 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -275,19 +275,26 @@ subroutine UpdateTopo(this, bounds, num_icec, filter_icec, & ! This could operate over a filter like 'allc' in order to just operate over active ! points, but I'm not sure that would speed things up much, and would require passing ! in this additional filter. + do c = bounds%begc, bounds%endc if (.not. this%needs_downscaling_col(c)) then + ! For any point that isn't already set to be downscaled, set its topo value to the + ! atmosphere's topographic height. This is important for the hillslope block + ! below. For non-hillslope columns, this shouldn't matter, but is useful if + ! topo_col is written to the history file. g = col%gridcell(c) - l = col%landunit(c) - this%topo_col(c) = atm_topo(g) - - if (col%is_hillslope_column(c) .and. downscale_hillslope_meteorology) then - this%topo_col(c) = this%topo_col(c) & - + (col%hill_elev(c) - mean_hillslope_elevation(l)) - this%needs_downscaling_col(c) = .true. - endif end if + ! If needs_downscaling_col was already set, then that implies + ! that topo_col was previously set by update_glc2lnd_topo. + ! In that case, topo_col should be used as a starting point, + ! rather than the atmosphere's topo value. + if (col%is_hillslope_column(c) .and. downscale_hillslope_meteorology) then + l = col%landunit(c) + this%topo_col(c) = this%topo_col(c) & + + (col%hill_elev(c) - mean_hillslope_elevation(l)) + this%needs_downscaling_col(c) = .true. + endif end do call glc_behavior%update_glc_classes(bounds, this%topo_col(begc:endc)) diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index 3ed2fa8c7e..8fb8a5fe2a 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -347,7 +347,7 @@ subroutine lnd2atm(bounds, & g = lun%gridcell(l) water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & - + water_inst%waterfluxbulk_inst%qstreamflow_lun(l) & + + water_inst%waterfluxbulk_inst%volumetric_streamflow_lun(l) & *1e3_r8/(grc%area(g)*1.e6_r8) enddo From 1b029d08864a5de7a87927675aabbf72abbee812 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Sat, 16 Jul 2022 07:23:15 -0600 Subject: [PATCH 081/153] Remove build-namelist tests of origflag origflag=1 is no longer supported. origflag=0 is now implicitly the case all the time; the two failure tests of origflag=0 are already covered by other failure tests ("Zeng w lower=flux", "Zeng w lower=zeroflux": those simply set soilwater_movement_method=0 explicitly, whereas the tests I'm removing have that implicit due to clm4_5 physics). --- bld/unit_testers/build-namelist_test.pl | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 824826d578..bea379bdbd 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -771,21 +771,6 @@ sub cat_and_create_namelistinfile { GLC_TWO_WAY_COUPLING=>"FALSE", phys=>"clm4_5", }, - "-vic with origflag=1" =>{ options=>"-vichydro -envxml_dir .", - namelst=>"origflag=1", - GLC_TWO_WAY_COUPLING=>"FALSE", - phys=>"clm4_5", - }, - "l_bnd=flux with origflag=0"=>{ options=>"-envxml_dir .", - namelst=>"origflag=0, lower_boundary_condition=1", - GLC_TWO_WAY_COUPLING=>"FALSE", - phys=>"clm4_5", - }, - "l_bnd=zflux with origflag=0"=>{ options=>"-envxml_dir .", - namelst=>"origflag=0, lower_boundary_condition=2", - GLC_TWO_WAY_COUPLING=>"FALSE", - phys=>"clm4_5", - }, "bedrock with l_bnc=flux" =>{ options=>"-envxml_dir .", namelst=>"use_bedrock=.true., lower_boundary_condition=1", GLC_TWO_WAY_COUPLING=>"FALSE", From 9ff72410a6e2bb1fff3fb169e753bfec5f58e649 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Sat, 16 Jul 2022 07:29:52 -0600 Subject: [PATCH 082/153] Remove origflag=1 setting from oldhyd test --- cime_config/testdefs/testmods_dirs/clm/oldhyd/user_nl_clm | 1 - 1 file changed, 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/oldhyd/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/oldhyd/user_nl_clm index 351bce0a82..5ef1fc660a 100644 --- a/cime_config/testdefs/testmods_dirs/clm/oldhyd/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/oldhyd/user_nl_clm @@ -1,4 +1,3 @@ snow_cover_fraction_method = 'NiuYang2007' h2osfcflag = 0 - origflag = 1 use_subgrid_fluxes = .false. From c6f4441330cdf369fae74433c989325b65a39344 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Sat, 16 Jul 2022 07:45:01 -0600 Subject: [PATCH 083/153] Fix build-namelist test count Fix for removal of the origflag tests --- bld/unit_testers/build-namelist_test.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index bea379bdbd..be83da0f3d 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -163,7 +163,7 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 1844; +my $ntests = 1841; if ( defined($opts{'compare'}) ) { $ntests += 1254; } From 1b5a4b2cf123b9ea240fd743939abbe79797b351 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Sun, 17 Jul 2022 08:02:30 -0600 Subject: [PATCH 084/153] Get unit tests passing --- src/main/test/atm2lnd_test/test_downscale_forcings.pf | 11 +++++++++-- src/main/test/atm2lnd_test/test_partition_precip.pf | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/test/atm2lnd_test/test_downscale_forcings.pf b/src/main/test/atm2lnd_test/test_downscale_forcings.pf index d7705f2d56..a6c1a7e356 100644 --- a/src/main/test/atm2lnd_test/test_downscale_forcings.pf +++ b/src/main/test/atm2lnd_test/test_downscale_forcings.pf @@ -9,6 +9,7 @@ module test_downscale_forcings use unittestSimpleSubgridSetupsMod use unittestArrayMod use atm2lndType, only : atm2lnd_type, atm2lnd_params_type + use SurfaceAlbedoType, only : surfalb_type use Wateratm2lndBulkType, only : wateratm2lndbulk_type use WaterInfoBulkType, only : water_info_bulk_type use TopoMod, only : topo_type @@ -25,6 +26,7 @@ module test_downscale_forcings @TestCase type, extends(TestCase) :: TestDownscaleForcings type(atm2lnd_type) :: atm2lnd_inst + type(surfalb_type) :: surfalb_inst type(wateratm2lndbulk_type) :: wateratm2lndbulk_inst type(topo_type_always_downscale) :: topo_inst real(r8), allocatable :: eflx_sh_precip_conversion(:) @@ -204,8 +206,13 @@ contains class(TestDownscaleForcings), intent(inout) :: this this%eflx_sh_precip_conversion = col_array() - call downscale_forcings(bounds, this%topo_inst, & - this%atm2lnd_inst, this%wateratm2lndbulk_inst, & + call downscale_forcings(bounds, & + this%topo_inst, & + this%atm2lnd_inst, & + ! Currently surfalb_inst is only used for hillslope downscaling; we need to pass + ! it to satisfy the interface but we haven't bothered setting it up + this%surfalb_inst, & + this%wateratm2lndbulk_inst, & this%eflx_sh_precip_conversion) end subroutine call_downscale_forcings diff --git a/src/main/test/atm2lnd_test/test_partition_precip.pf b/src/main/test/atm2lnd_test/test_partition_precip.pf index c0d9065007..ba233263ce 100644 --- a/src/main/test/atm2lnd_test/test_partition_precip.pf +++ b/src/main/test/atm2lnd_test/test_partition_precip.pf @@ -5,6 +5,7 @@ module test_partition_precip use pfunit_mod use atm2lndMod use atm2lndType + use ColumnType, only : col use shr_kind_mod, only : r8 => shr_kind_r8 use unittestSubgridMod use unittestSimpleSubgridSetupsMod @@ -64,6 +65,7 @@ contains logical :: l_repartition_rain_snow type(atm2lnd_params_type) :: atm2lnd_params + integer :: c, g if (present(repartition_rain_snow)) then l_repartition_rain_snow = repartition_rain_snow @@ -89,6 +91,15 @@ contains this%wateratm2lndbulk_inst%forc_rain_not_downscaled_grc(bounds%begg:bounds%endg) = rain(:) this%wateratm2lndbulk_inst%forc_snow_not_downscaled_grc(bounds%begg:bounds%endg) = snow(:) this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc:bounds%endc) = temperature(:) + + ! In the production code, column-level versions of forc_rain and forc_snow are + ! initialized to the gridcell-level versions prior to the call to partition_precip; do + ! that here + do c = bounds%begc, bounds%endc + g = col%gridcell(c) + this%wateratm2lndbulk_inst%forc_rain_downscaled_col(c) = this%wateratm2lndbulk_inst%forc_rain_not_downscaled_grc(g) + this%wateratm2lndbulk_inst%forc_snow_downscaled_col(c) = this%wateratm2lndbulk_inst%forc_snow_not_downscaled_grc(g) + end do end subroutine set_inputs @Test From 99cfb53f29d9b393a0722494e7fe1284e932bfd8 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Sun, 17 Jul 2022 21:29:02 -0600 Subject: [PATCH 085/153] Temporary workaround for bare land smb flux issue Temporary workaround for https://github.com/ESCOMP/CTSM/issues/204 that allows the error check to remain in place usually but still lets hillslope hydrology runs pass. --- src/main/lnd2glcMod.F90 | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/lnd2glcMod.F90 b/src/main/lnd2glcMod.F90 index 2a9931851d..27fa7639d7 100644 --- a/src/main/lnd2glcMod.F90 +++ b/src/main/lnd2glcMod.F90 @@ -20,7 +20,7 @@ module lnd2glcMod use decompMod , only : get_proc_bounds, bounds_type, subgrid_level_column use domainMod , only : ldomain use clm_varpar , only : maxpatch_glc - use clm_varctl , only : iulog + use clm_varctl , only : iulog, use_hillslope use clm_varcon , only : spval, tfrz use column_varcon , only : col_itype_to_ice_class use landunit_varcon , only : istice, istsoil @@ -204,8 +204,16 @@ subroutine update_lnd2glc(this, bounds, num_do_smb_c, filter_do_smb_c, & ! Make sure we haven't already assigned the coupling fields for this point ! (this could happen, for example, if there were multiple columns in the ! istsoil landunit, which we aren't prepared to handle) -!scs if (fields_assigned(g,n)) then - if (1==2) then + ! + ! BUG(wjs, 2022-07-17, ESCOMP/CTSM#204) We have a known bug in the handling of bare + ! land fluxes when we potentially have multiple vegetated columns in a grid cell. + ! The most common configuration where this is the case is when use_hillslope is + ! true. In order to allow hillslope hydrology runs to work for now, we are + ! bypassing this error check when use_hillslope is true - under the assumption + ! that, for now, people aren't going to be interested in SMB in a run with + ! hillslope hydrology. Once we resolve ESCOMP/CTSM#204, we should remove the '.and. + ! .not. use_hillslope' part of this conditional. + if (fields_assigned(g,n) .and. .not. use_hillslope) then write(iulog,*) subname//' ERROR: attempt to assign coupling fields twice for the same index.' write(iulog,*) 'One possible cause is having multiple columns in the istsoil landunit,' write(iulog,*) 'which this routine cannot handle.' From 78cbfedad36db621acef6e03e35d05d27fa96d7f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 18 Jul 2022 09:18:08 -0600 Subject: [PATCH 086/153] more minor fixes --- src/biogeophys/HillslopeHydrologyMod.F90 | 25 +++++++++++++----------- src/biogeophys/IrrigationMod.F90 | 8 +------- src/biogeophys/SoilHydrologyMod.F90 | 23 ++++------------------ src/biogeophys/SurfaceRadiationMod.F90 | 1 - src/main/TopoMod.F90 | 4 ---- src/main/clm_initializeMod.F90 | 7 +++++++ src/main/clm_instMod.F90 | 9 ++++++++- src/main/initVerticalMod.F90 | 4 ---- src/main/lnd2atmMod.F90 | 14 +++++++------ 9 files changed, 42 insertions(+), 53 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 0f0a3e70d3..376c0031a4 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -744,7 +744,11 @@ end subroutine HillslopeSoilThicknessProfile subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) ! ! !DESCRIPTION: - ! Reassign patch weights such that each column has a single pft. + ! Reassign patch type of each column based on whether a column + ! is identified as a lowland or an upland. + ! Assumes each column has a single pft. + ! In preparation for this reassignment of patch type, only the + ! first patch was given a non-zero weight in surfrd_hillslope ! ! !USES @@ -767,12 +771,9 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) do c = bounds%begc, bounds%endc if (col%is_hillslope_column(c) .and. col%active(c)) then - ! In preparation for this re-weighting of patch type - ! only first patch was given a non-zero weight in surfrd_hillslope npatches_per_column = 0 do p = col%patchi(c), col%patchf(c) - ! lowland - if(col%cold(c) == ispval) then + if(col%cold(c) == ispval) then ! lowland patch%itype(p) = lowland_ivt else ! upland patch%itype(p) = upland_ivt @@ -793,8 +794,9 @@ end subroutine HillslopeSetLowlandUplandPfts subroutine HillslopeDominantPft(bounds) ! ! !DESCRIPTION: - ! Reassign patch weights such that each column has a single pft - ! determined by each column's most dominant pft on input dataset. + ! Reassign patch type of each column based on each gridcell's + ! most dominant pft on the input dataset. + ! Assumes each column has a single pft. ! Best performance when used with n_dom_pfts = 1 (Actually, this ! is probably redundant to behavior with n_dom_pts = 1 and pft_distribution_method = pft_standard) @@ -841,10 +843,11 @@ end subroutine HillslopeDominantPft subroutine HillslopeDominantLowlandPft(bounds) ! ! !DESCRIPTION: - ! Reassign patch weights such that each column has a single, - ! dominant pft. Use largest weight for lowland, 2nd largest - ! weight for uplands + ! Reassign patch type of each column based on each gridcell's + ! two most dominant pfts on the input dataset. ! Best performance when used with n_dom_pfts = 2 + ! Assumes each column has a single pft. + ! Use largest weight for lowland, 2nd largest weight for uplands ! ! !USES @@ -938,7 +941,7 @@ end subroutine HillslopeDominantLowlandPft subroutine HillslopePftFromFile(bounds,col_pftndx) ! ! !DESCRIPTION: - ! Reassign patch weights using indices from surface data file + ! Reassign patch type using indices from surface data file ! Assumes one patch per hillslope column ! ! !USES diff --git a/src/biogeophys/IrrigationMod.F90 b/src/biogeophys/IrrigationMod.F90 index c78572f0e8..faea425616 100644 --- a/src/biogeophys/IrrigationMod.F90 +++ b/src/biogeophys/IrrigationMod.F90 @@ -78,7 +78,7 @@ module IrrigationMod use abortutils , only : endrun use clm_instur , only : irrig_method use pftconMod , only : pftcon - use clm_varctl , only : iulog, use_hillslope + use clm_varctl , only : iulog use clm_varcon , only : isecspday, denh2o, spval, ispval use clm_varpar , only : nlevsoi, nlevgrnd use clm_time_manager , only : get_step_size @@ -584,12 +584,6 @@ subroutine CheckNamelistValidity(this, use_aquifer_layer) errMsg(sourcefile, __LINE__)) end if - if (use_aquifer_layer .and. use_hillslope) then - write(iulog,*) ' ERROR: use_hillslope and use_aquifer_layer may not be used simultaneously' - call endrun(msg=' ERROR: use_hillslope and use_aquifer_layer cannot both be set to true' // & - errMsg(sourcefile, __LINE__)) - end if - end associate end subroutine CheckNamelistValidity diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 0c3e748055..8611853174 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1744,14 +1744,6 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & real(r8) :: qflx_drain_perched_vol(bounds%begc:bounds%endc) ! volumetric lateral subsurface flow through active layer [m3/s] real(r8) :: qflx_drain_perched_out(bounds%begc:bounds%endc) ! lateral subsurface flow through active layer [mm/s] -!!$ integer, parameter :: head_gradient_method = 0 -!!$ integer, parameter :: transmissivity_method = 0 -!!$ integer, parameter :: kinematic = 1 -!!$ integer, parameter :: darcy = 0 -!!$ integer, parameter :: uniform_transmissivity = 1 -!!$ integer, parameter :: layersum = 0 - - associate( & nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) @@ -1905,11 +1897,11 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & enddo endif endif - else if (transmissivity_method == uniform_transmissivity) then - ! constant conductivity based on shallowest saturated layer hydraulic conductivity - transmis = (1.e-3_r8*hksat(c_src,k_perch(c_src))) & - *(zi(c_src,k_frost(c_src)) - zwt_perched(c_src) ) endif + else if (transmissivity_method == uniform_transmissivity) then + ! constant conductivity based on shallowest saturated layer hydraulic conductivity + transmis = (1.e-3_r8*hksat(c_src,k_perch(c_src))) & + *(zi(c_src,k_frost(c_src)) - zwt_perched(c_src) ) endif ! adjust by 'anisotropy factor' @@ -2120,13 +2112,6 @@ subroutine SubsurfaceLateralFlow(bounds, & type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst -!!$ integer, parameter :: head_gradient_method = 0 -!!$ integer, parameter :: transmissivity_method = 0 -!!$ integer, parameter :: kinematic = 1 -!!$ integer, parameter :: darcy = 0 -!!$ integer, parameter :: uniform_transmissivity = 1 -!!$ integer, parameter :: layersum = 0 - ! ! !LOCAL VARIABLES: character(len=32) :: subname = 'SubsurfaceLateralFlow' ! subroutine name diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index 558b2bf2ee..10d0db94ae 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -536,7 +536,6 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & associate( & snl => col%snl , & ! Input: [integer (:) ] negative number of snow layers [nbr] - forc_solad => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation, gridcell (W/m**2) forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col , & ! Input: [real(r8) (:,:) ] direct beam radiation, column (W/m**2) forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (W/m**2) diff --git a/src/main/TopoMod.F90 b/src/main/TopoMod.F90 index 4e09d4886f..b081c77482 100644 --- a/src/main/TopoMod.F90 +++ b/src/main/TopoMod.F90 @@ -268,10 +268,6 @@ subroutine UpdateTopo(this, bounds, num_icec, filter_icec, & enddo endif - ! For any point that isn't downscaled, set its topo value to the atmosphere's - ! topographic height. This shouldn't matter, but is useful if topo_col is written to - ! the history file. - ! ! This could operate over a filter like 'allc' in order to just operate over active ! points, but I'm not sure that would speed things up much, and would require passing ! in this additional filter. diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index 1b6a5ae4ae..e648fcb26a 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -166,6 +166,8 @@ subroutine initialize2(ni,nj) use CNSharedParamsMod , only : CNParamsSetSoilDepth use NutrientCompetitionFactoryMod , only : create_nutrient_competition_method use FATESFireFactoryMod , only : scalar_lightning + use HillslopeHydrologyMod , only : HillslopeSetLowlandUplandPfts,HillslopeDominantPft,HillslopeDominantLowlandPft,HillslopePftFromFile + ! ! !ARGUMENTS integer, intent(in) :: ni, nj ! global grid sizes @@ -274,6 +276,11 @@ subroutine initialize2(ni,nj) end do !$OMP END PARALLEL DO + ! Modify original patch types for hillslope hydrology + if(use_hillslope) then + + endif + ! Set global seg maps for gridcells, landlunits, columns and patches call decompInit_glcp(ni, nj, glc_behavior) diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 7e02a8f9aa..ef701f5393 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -297,7 +297,14 @@ subroutine clm_instInit(bounds) call canopystate_inst%Init(bounds) - if(use_hillslope) then + if(use_hillslope) then + ! check compatiblity with use_aquifer_layer +!!$ if (use_aquifer_layer()) then +!!$ write(iulog,*) ' ERROR: use_hillslope and use_aquifer_layer may not be used simultaneously' +!!$ call endrun(msg=' ERROR: use_hillslope and use_aquifer_layer cannot both be set to true' // & +!!$ errMsg(sourcefile, __LINE__)) +!!$ end if + ! Initialize hillslope properties call InitHillslope(bounds, fsurdat, glc_behavior) endif diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index efe857a1ca..7b04a8bf7d 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -197,10 +197,6 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) ! The distinction between "shallow" and "deep" bedrock is not made explicitly ! elsewhere. But, since these classes have somewhat different behavior, they are ! distinguished explicitly here. - integer, parameter :: LEVGRND_CLASS_STANDARD = 1 - integer, parameter :: LEVGRND_CLASS_DEEP_BEDROCK = 2 - integer, parameter :: LEVGRND_CLASS_SHALLOW_BEDROCK = 3 - character(len=*), parameter :: subname = 'initVertical' !------------------------------------------------------------------------ diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index 8fb8a5fe2a..5bf91ecefc 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -344,11 +344,13 @@ subroutine lnd2atm(bounds, & ! streamflow is volume/time, so sum over landunits (do not weight) water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) = 0._r8 do l = bounds%begl, bounds%endl - g = lun%gridcell(l) - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & - water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & - + water_inst%waterfluxbulk_inst%volumetric_streamflow_lun(l) & - *1e3_r8/(grc%area(g)*1.e6_r8) + if(lun%active(l)) then + g = lun%gridcell(l) + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) = & + water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) & + + water_inst%waterfluxbulk_inst%volumetric_streamflow_lun(l) & + *1e3_r8/(grc%area(g)*1.e6_r8) + endif enddo ! If hillslope routing is used, exclude inputs to stream channel from gridcell averages to avoid double counting @@ -365,7 +367,7 @@ subroutine lnd2atm(bounds, & ! Exclude hillslope columns from gridcell average ! hillslope runoff is sent to stream rather than directly ! to rof, and is accounted for in qflx_rofliq_stream_grc - if (.not. col%is_hillslope_column(c)) then + if (col%active(c) .and. .not. col%is_hillslope_column(c)) then qflx_surf_col_to_rof(c) = qflx_surf_col_to_rof(c) & + water_inst%waterfluxbulk_inst%qflx_surf_col(c) qflx_drain_col_to_rof(c) = qflx_drain_col_to_rof(c) & From 607ee4dc85df25fecce1404eaedc14947eb096c4 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 21 Jul 2022 12:29:26 -0600 Subject: [PATCH 087/153] move initHillslope call earlier --- bld/CLMBuildNamelist.pm | 1 + bld/namelist_files/namelist_defaults_ctsm.xml | 1 + .../namelist_definition_ctsm.xml | 5 + src/biogeophys/HillslopeHydrologyMod.F90 | 295 +++++++++++++----- src/biogeophys/WaterFluxType.F90 | 4 +- src/main/clm_initializeMod.F90 | 14 +- src/main/clm_instMod.F90 | 14 +- src/main/initVerticalMod.F90 | 13 +- src/main/surfrdMod.F90 | 53 +++- 9 files changed, 295 insertions(+), 105 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 215f9b0ef3..bc5def1f81 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3248,6 +3248,7 @@ sub setup_logic_hillslope { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_head_gradient_method' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_transmissivity_method' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_pft_distribution_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_soil_profile_method' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope_routing', 'use_hillslope'=>$nl_flags->{'use_hillslope'} ); my $use_hillslope = $nl->get_value('use_hillslope'); my $use_hillslope_routing = $nl->get_value('use_hillslope_routing'); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index f4b635869d..4e28e3f7e2 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -603,6 +603,7 @@ attributes from the config_cache.xml file (with keys converted to upper-case). Darcy LayerSum Standard +Uniform .true. diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 9c5ea98010..7f133fb46b 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -759,6 +759,11 @@ Method for calculating transmissivity of hillslope columns Method for distributing pfts across hillslope columns + +Method for distributing soil thickness across hillslope columns + + Toggle to turn on the plant hydraulic stress model diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 376c0031a4..fac473c421 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -24,8 +24,11 @@ module HillslopeHydrologyMod ! !PUBLIC MEMBER FUNCTIONS: public hillslope_properties_init public InitHillslope + public SetHillslopeSoilThickness public HillslopeSoilThicknessProfile public HillslopeSetLowlandUplandPfts + public HillslopeDominantPftIndex + public HillslopeTwoLargestPftIndices public HillslopeDominantPft public HillslopeDominantLowlandPft public HillslopePftFromFile @@ -88,9 +91,6 @@ subroutine hillslope_properties_init(NLFilename) hillslope_pft_distribution_method, & hillslope_soil_profile_method -! pft_distribution_method = pft_standard -! soil_profile_method = soil_profile_uniform - ! Read hillslope hydrology namelist if (masterproc) then nu_nml = getavu() @@ -149,9 +149,28 @@ subroutine hillslope_properties_init(NLFilename) end subroutine hillslope_properties_init + !----------------------------------------------------------------------- + subroutine check_aquifer_layer() + ! + ! !DESCRIPTION: + ! Check whether use_hillslope and use_aquifer_layer are both set + ! The use of use_hillslope is implied by the call to this function + ! in InitHillslope, but explicitly compare here for clarity. + ! + ! !USES: + use clm_varctl , only : use_hillslope + use SoilWaterMovementMod , only : use_aquifer_layer + if(use_hillslope .and. use_aquifer_layer()) then + write(iulog,*) ' ERROR: use_hillslope and use_aquifer_layer may not be used simultaneously' + call endrun(msg=' ERROR: use_hillslope and use_aquifer_layer cannot both be set to true' // & + errMsg(sourcefile, __LINE__)) + end if + + end subroutine check_aquifer_layer + !----------------------------------------------------------------------- - subroutine InitHillslope(bounds,fsurdat,glc_behavior) + subroutine InitHillslope(bounds,fsurdat) ! ! !DESCRIPTION: ! Initialize hillslope geomorphology from input dataset @@ -161,26 +180,19 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) use GridcellType , only : grc use ColumnType , only : col use clm_varctl , only : nhillslope, max_columns_hillslope - use clm_varcon , only : zmin_bedrock, zisoi - use clm_varpar , only : nlevsoi use spmdMod , only : masterproc use fileutils , only : getfil use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil use ncdio_pio - use initVerticalMod , only : setSoilLayerClass - use reweightMod , only : reweight_wrapup - use subgridWeightsMod , only : compute_higher_order_weights - use glcBehaviorMod , only : glc_behavior_type - use subgridWeightsMod , only : check_weights ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds character(len=*) , intent(in) :: fsurdat ! surface data file name - type(glc_behavior_type), intent(in) :: glc_behavior integer, pointer :: ihillslope_in(:,:) ! read in - integer integer, pointer :: ncolumns_hillslope_in(:) ! read in number of columns + integer, allocatable :: ncolumns_hillslope(:) ! number of hillslope columns integer, allocatable :: hill_ndx(:,:) ! hillslope index integer, allocatable :: col_ndx(:,:) ! column index integer, allocatable :: col_dndx(:,:) ! downhill column index @@ -211,12 +223,16 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) !----------------------------------------------------------------------- + ! consistency check + call check_aquifer_layer() + ! Open surface dataset to read in data below call getfil (fsurdat, locfn, 0) call ncd_pio_openfile (ncid, locfn, 0) allocate( & + ncolumns_hillslope(bounds%begl:bounds%endl), & pct_hillslope(bounds%begl:bounds%endl,nhillslope), & hill_ndx (bounds%begl:bounds%endl,max_columns_hillslope), & col_ndx (bounds%begl:bounds%endl,max_columns_hillslope), & @@ -240,6 +256,7 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) + ncolumns_hillslope(l) = ncolumns_hillslope_in(g) ! vegetated landunits having nonzero hillslope columns if(lun%itype(l) == istsoil .and. ncolumns_hillslope_in(g) > 0) then do c = lun%coli(l), lun%colf(l) @@ -490,22 +507,6 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) col%hill_area(c) = hill_area(l,ci) ! azimuth of column col%hill_aspect(c) = hill_aspect(l,ci) - ! soil thickness of column - if (soil_profile_method==soil_profile_from_file) then - if ( allocated(hill_bedrock) ) then - do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < hill_bedrock(l,ci) .and. zisoi(j) >= hill_bedrock(l,ci)) then - col%nbedrock(c) = j - end if - endif - enddo - else - if (masterproc) then - call endrun( 'ERROR:: soil_profile_method = soil_profile_from_file, but h_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if - endif - endif ! pft index of column if ( allocated(hill_pftndx) ) then col_pftndx(c) = hill_pftndx(l,ci) @@ -560,7 +561,7 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) ! if missing hillslope information on surface dataset, ! call endrun - if (sum(hillslope_area) == 0._r8) then + if (ncolumns_hillslope(l) > 0 .and. sum(hillslope_area) == 0._r8) then if (masterproc) then write(iulog,*) 'Problem with input data: nhillcolumns is non-zero, but hillslope area is zero' write(iulog,*) 'Check surface data for gridcell at (lon/lat): ', grc%londeg(g),grc%latdeg(g) @@ -569,6 +570,7 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) endif ! Recalculate column weights using input areas + ! The higher order weights will be updated in a subsequent reweight_wrapup call do c = lun%coli(l), lun%colf(l) nh = col%hillslope_ndx(c) if (col%is_hillslope_column(c)) then @@ -579,25 +581,10 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) endif enddo ! end of landunit loop - deallocate(pct_hillslope,hill_ndx,col_ndx,col_dndx, & + deallocate(ncolumns_hillslope,pct_hillslope,hill_ndx,col_ndx,col_dndx, & hill_slope,hill_area,hill_length, & hill_width,hill_height,hill_aspect) - if(soil_profile_method==soil_profile_from_file) then - if ( allocated(hill_bedrock) ) then - deallocate(hill_bedrock) - endif - else if (soil_profile_method==soil_profile_set_lowland_upland & - .or. soil_profile_method==soil_profile_linear) then - ! Modify hillslope soil thickness profile - call HillslopeSoilThicknessProfile(bounds,& - soil_profile_method=soil_profile_method,& - soil_depth_lowland_in=8.0_r8,soil_depth_upland_in=8.0_r8) - endif - - ! Update layer classes if nbedrock has been modified - call setSoilLayerClass(bounds) - ! Modify pft distributions ! this may require modifying subgridMod/natveg_patch_exists ! to ensure patch exists in every gridcell @@ -612,7 +599,7 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) else if (pft_distribution_method == pft_lowland_upland) then ! example usage: ! upland_ivt = 13 ! c3 non-arctic grass - ! lowland_ivt = 7 ! broadleaf deciduous tree + ! lowland_ivt = 7 ! broadleaf deciduous tree call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) endif @@ -620,23 +607,112 @@ subroutine InitHillslope(bounds,fsurdat,glc_behavior) deallocate(hill_pftndx) deallocate(col_pftndx) endif - - ! Update higher order weights and check that weights sum to 1 - call compute_higher_order_weights(bounds) - if (masterproc) then - write(iulog,*) 'Checking modified hillslope weights via reweight_wrapup' - end if - - ! filters have not been allocated yet! - ! can check_weights be called directly here? -! call reweight_wrapup(bounds, glc_behavior) -! call check_weights(bounds) - call check_weights(bounds, active_only=.true.) call ncd_pio_closefile(ncid) end subroutine InitHillslope + !----------------------------------------------------------------------- + + subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_depth_upland_in) + ! + ! !DESCRIPTION: + ! Set hillslope column nbedrock values + ! + ! !USES: + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col + use clm_varctl , only : nhillslope, max_columns_hillslope + use clm_varcon , only : zmin_bedrock, zisoi + use clm_varpar , only : nlevsoi + use spmdMod , only : masterproc + use fileutils , only : getfil + use clm_varcon , only : spval, ispval, grlnd + use ncdio_pio + + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + character(len=*) , intent(in) :: fsurdat ! surface data file name + real(r8), intent(in), optional :: soil_depth_lowland_in + real(r8), intent(in), optional :: soil_depth_upland_in + real(r8), pointer :: fhillslope_in(:,:) ! read in - float + + type(file_desc_t) :: ncid ! netcdf id + logical :: readvar ! check whether variable on file + character(len=256) :: locfn ! local filename + integer :: ierr ! error code + integer :: c, l, g, j, ci ! indices + + real(r8) :: soil_depth_lowland + real(r8) :: soil_depth_upland + real(r8), parameter :: soil_depth_lowland_default = 8.0 + real(r8), parameter :: soil_depth_upland_default = 8.0 + character(len=*), parameter :: subname = 'SetHillslopeSoilThickness' + + !----------------------------------------------------------------------- + + if(soil_profile_method==soil_profile_from_file) then + + ! Open surface dataset to read in data below + call getfil (fsurdat, locfn, 0) + call ncd_pio_openfile (ncid, locfn, 0) + + call ncd_io(ncid=ncid, varname='h_bedrock', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + if (readvar) then + allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) + if (masterproc) then + write(iulog,*) 'h_bedrock found on surface data set' + else + if (masterproc) then + call endrun( 'ERROR:: soil_profile_method = "FromFile", but h_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + end if + end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c) .and. col%active(c)) then + ci = c-lun%coli(l)+1 + do j = 1,nlevsoi + if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < fhillslope_in(g,ci) & + .and. zisoi(j) >= fhillslope_in(g,ci)) then + col%nbedrock(c) = j + end if + endif + enddo + endif + enddo + enddo + deallocate(fhillslope_in) + end if + call ncd_pio_closefile(ncid) + + else if (soil_profile_method==soil_profile_set_lowland_upland & + .or. soil_profile_method==soil_profile_linear) then + + if(present(soil_depth_lowland_in)) then + soil_depth_lowland = soil_depth_lowland_in + else + soil_depth_lowland = soil_depth_lowland_default + endif + + if(present(soil_depth_upland_in)) then + soil_depth_upland = soil_depth_upland_in + else + soil_depth_upland = soil_depth_upland_default + endif + + ! Modify hillslope soil thickness profile + call HillslopeSoilThicknessProfile(bounds,& + soil_profile_method=soil_profile_method,& + soil_depth_lowland_in=soil_depth_lowland,& + soil_depth_upland_in=soil_depth_upland) + endif + + end subroutine SetHillslopeSoilThickness + !----------------------------------------------------------------------- subroutine HillslopeSoilThicknessProfile(bounds,& soil_profile_method,soil_depth_lowland_in,soil_depth_upland_in) @@ -770,7 +846,7 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) !------------------------------------------------------------------------ do c = bounds%begc, bounds%endc - if (col%is_hillslope_column(c) .and. col%active(c)) then + if (col%is_hillslope_column(c)) then npatches_per_column = 0 do p = col%patchi(c), col%patchf(c) if(col%cold(c) == ispval) then ! lowland @@ -790,15 +866,85 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) end subroutine HillslopeSetLowlandUplandPfts + !------------------------------------------------------------------------ + subroutine HillslopeDominantPftIndex(weights,lbound,pindex) + ! + ! !DESCRIPTION: + ! Locate each gridcell's most dominant pft on the input dataset. + ! This is different than using n_dom_pts = 1, because it is meant + ! to be applied only to gridcells having active hillslope hydrology. + ! This routine is called from surfrd_hillslope. + + ! + ! !USES + ! + ! !ARGUMENTS: + real(r8), intent(in) :: weights(:) ! array of patch weights + integer, intent(in) :: lbound ! lower bound of weights + integer, intent(out) :: pindex ! index of largest weight + ! + ! !LOCAL VARIABLES: + integer :: pdom(1) + + !------------------------------------------------------------------------ + + pdom = maxloc(weights) + pindex = pdom(1) + (lbound - 1) + + end subroutine HillslopeDominantPftIndex + + !------------------------------------------------------------------------ + subroutine HillslopeTwoLargestPftIndices(weights,lbound,pindex1,pindex2) + ! + ! !DESCRIPTION: + ! Locate each gridcell's two most dominant patches on the input dataset. + ! This is different than using n_dom_pts = 2, because it is meant + ! to be applied only to gridcells having active hillslope hydrology. + ! This routine is called from surfrd_hillslope. + + ! + ! !USES + ! + ! !ARGUMENTS: + real(r8), intent(in) :: weights(:) ! array of patch weights + integer, intent(in) :: lbound ! lower bound of weights + integer, intent(out) :: pindex1 ! index of largest weight + integer, intent(out) :: pindex2 ! index of next largest weight + ! + ! !LOCAL VARIABLES: + integer :: pdom(1),psubdom(1) + real(r8),allocatable :: mask(:) + + !------------------------------------------------------------------------ + + pdom = maxloc(weights) + ! create mask to exclude pdom + allocate(mask(size(weights))) + mask(:) = 1. + mask(pdom(1)) = 0. + ! check that more than one nonzero patch weight exists, + ! if not return identical indices + if (sum(mask*weights) > 0) then + psubdom = maxloc(mask*weights) + else + psubdom = pdom + endif + deallocate(mask) + + pindex1 = pdom(1) + (lbound - 1) + pindex2 = psubdom(1) + (lbound - 1) + + end subroutine HillslopeTwoLargestPftIndices + !------------------------------------------------------------------------ subroutine HillslopeDominantPft(bounds) ! ! !DESCRIPTION: - ! Reassign patch type of each column based on each gridcell's + ! Reassign patch weights of each column based on each gridcell's ! most dominant pft on the input dataset. ! Assumes each column has a single pft. - ! Best performance when used with n_dom_pfts = 1 (Actually, this - ! is probably redundant to behavior with n_dom_pts = 1 and pft_distribution_method = pft_standard) + ! If n_dom_pfts = 1 or if HillslopeDominantPftIndex is called + ! in surfrd_hillslope, this routine does not act on hillslope columns. ! ! !USES @@ -812,14 +958,14 @@ subroutine HillslopeDominantPft(bounds) type(bounds_type), intent(in) :: bounds ! ! !LOCAL VARIABLES: - integer :: nc,p,pu,pl,l,c ! indices - integer :: pdom(1) - real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc + integer :: c ! indices + integer :: pdom(1) ! patch index + real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc ! sum of patch weights !------------------------------------------------------------------------ do c = bounds%begc,bounds%endc - if (col%is_hillslope_column(c) .and. col%active(c)) then + if (col%is_hillslope_column(c) .and. (col%npatches(c) > 1)) then pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) pdom = pdom + (col%patchi(c) - 1) @@ -827,11 +973,11 @@ subroutine HillslopeDominantPft(bounds) sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 + patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtcol(pdom(1)) = sum_wtcol + patch%wtcol(pdom(1)) = sum_wtcol patch%wtlunit(pdom(1)) = sum_wtlun patch%wtgcell(pdom(1)) = sum_wtgrc endif @@ -843,9 +989,10 @@ end subroutine HillslopeDominantPft subroutine HillslopeDominantLowlandPft(bounds) ! ! !DESCRIPTION: - ! Reassign patch type of each column based on each gridcell's - ! two most dominant pfts on the input dataset. - ! Best performance when used with n_dom_pfts = 2 + ! Reassign patch weights of each column based on each gridcell's + ! two most dominant pfts on the input dataset. + ! HillslopeTwoLargestPftIndices is called in surfrd_hillslope to + ! prepare the patch weights for this routine. ! Assumes each column has a single pft. ! Use largest weight for lowland, 2nd largest weight for uplands @@ -871,7 +1018,7 @@ subroutine HillslopeDominantLowlandPft(bounds) !------------------------------------------------------------------------ do c = bounds%begc,bounds%endc - if (col%is_hillslope_column(c) .and. col%active(c)) then + if (col%is_hillslope_column(c)) then pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) ! create mask to exclude pdom allocate(mask(col%npatches(c))) @@ -943,6 +1090,8 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) ! !DESCRIPTION: ! Reassign patch type using indices from surface data file ! Assumes one patch per hillslope column + ! In preparation for this reassignment of patch type, only the + ! first patch was given a non-zero weight in surfrd_hillslope. ! ! !USES use ColumnType , only : col @@ -961,7 +1110,7 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) !------------------------------------------------------------------------ do c = bounds%begc, bounds%endc - if (col%is_hillslope_column(c) .and. col%active(c)) then + if (col%is_hillslope_column(c)) then ! In preparation for this re-weighting of patch type ! only first patch was given a non-zero weight in surfrd_hillslope npatches_per_column = 0 diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index 5ac717ca59..fb4ba242fe 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -519,7 +519,7 @@ subroutine InitHistory(this, bounds) avgflag='A', & long_name=this%info%lname('hillslope discharge from column'), & l2g_scale_type='natveg', c2l_scale_type='urbanf', & - ptr_col=this%volumetric_discharge_col) + ptr_col=this%volumetric_discharge_col,default='inactive') if (use_hillslope_routing) then this%volumetric_streamflow_lun(begl:endl) = spval @@ -527,7 +527,7 @@ subroutine InitHistory(this, bounds) fname=this%info%fname('VOLUMETRIC_STREAMFLOW'), & units='m3/s', & avgflag='A', & - long_name=this%info%lname('streamflow discharge'), & + long_name=this%info%lname('volumetric streamflow from hillslope'), & l2g_scale_type='natveg', & ptr_lunit=this%volumetric_streamflow_lun) endif diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index e648fcb26a..76945f32cc 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -166,11 +166,11 @@ subroutine initialize2(ni,nj) use CNSharedParamsMod , only : CNParamsSetSoilDepth use NutrientCompetitionFactoryMod , only : create_nutrient_competition_method use FATESFireFactoryMod , only : scalar_lightning - use HillslopeHydrologyMod , only : HillslopeSetLowlandUplandPfts,HillslopeDominantPft,HillslopeDominantLowlandPft,HillslopePftFromFile + use HillslopeHydrologyMod , only : InitHillslope ! ! !ARGUMENTS - integer, intent(in) :: ni, nj ! global grid sizes + integer, intent(in) :: ni, nj ! global grid sizes ! ! !LOCAL VARIABLES: integer :: c,g,i,j,k,l,n,p ! indices @@ -276,14 +276,14 @@ subroutine initialize2(ni,nj) end do !$OMP END PARALLEL DO - ! Modify original patch types for hillslope hydrology - if(use_hillslope) then - - endif - ! Set global seg maps for gridcells, landlunits, columns and patches call decompInit_glcp(ni, nj, glc_behavior) + if(use_hillslope) then + ! Initialize hillslope properties + call InitHillslope(bounds_proc, fsurdat) + endif + ! Set filters call allocFilters() diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index ef701f5393..7924c2111e 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -8,7 +8,7 @@ module clm_instMod use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type use clm_varpar , only : ndecomp_pools, nlevdecomp_full - use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_fates, use_hillslope + use clm_varctl , only : use_cn, use_c13, use_c14, use_lch4, use_cndv, use_fates use clm_varctl , only : iulog use clm_varctl , only : use_crop, snow_cover_fraction_method, paramfile use SoilBiogeochemDecompCascadeConType , only : mimics_decomp, no_soil_decomp, century_decomp, decomp_method @@ -49,7 +49,6 @@ module clm_instMod use EnergyFluxType , only : energyflux_type use FrictionVelocityMod , only : frictionvel_type use GlacierSurfaceMassBalanceMod , only : glacier_smb_type - use HillslopeHydrologyMod , only : InitHillslope use InfiltrationExcessRunoffMod , only : infiltration_excess_runoff_type use IrrigationMod , only : irrigation_type use LakeStateType , only : lakestate_type @@ -297,17 +296,6 @@ subroutine clm_instInit(bounds) call canopystate_inst%Init(bounds) - if(use_hillslope) then - ! check compatiblity with use_aquifer_layer -!!$ if (use_aquifer_layer()) then -!!$ write(iulog,*) ' ERROR: use_hillslope and use_aquifer_layer may not be used simultaneously' -!!$ call endrun(msg=' ERROR: use_hillslope and use_aquifer_layer cannot both be set to true' // & -!!$ errMsg(sourcefile, __LINE__)) -!!$ end if - ! Initialize hillslope properties - call InitHillslope(bounds, fsurdat, glc_behavior) - endif - call soilstate_inst%Init(bounds) call SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) ! sets hydraulic and thermal soil properties diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index 7b04a8bf7d..aeea19813f 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -19,7 +19,7 @@ module initVerticalMod use clm_varctl , only : use_vancouver, use_mexicocity, use_extralakelayers use clm_varctl , only : use_bedrock, rundef use clm_varctl , only : soil_layerstruct_predefined, soil_layerstruct_userdefined - use clm_varctl , only : use_fates + use clm_varctl , only : use_fates, use_hillslope use clm_varcon , only : zlak, dzlak, zsoi, dzsoi, zisoi, dzsoi_decomp, spval, ispval, grlnd use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, is_hydrologically_active use landunit_varcon , only : istdlak, istice @@ -148,7 +148,9 @@ end subroutine setSoilLayerClass !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) - use clm_varcon, only : zmin_bedrock + use clm_varcon , only : zmin_bedrock + use HillslopeHydrologyMod, only : SetHillslopeSoilThickness + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -578,6 +580,13 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) deallocate(zbedrock_in) + ! Set hillslope column bedrock values + if(use_hillslope) then + call SetHillslopeSoilThickness(bounds,fsurdat, & + soil_depth_lowland_in=8.5_r8,& + soil_depth_upland_in =2.0_r8) + endif + !----------------------------------------------- ! Set lake levels and layers (no interfaces) !----------------------------------------------- diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 7bb5022abc..937800ed1c 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -766,7 +766,9 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) use clm_varpar, only : natpft_size, natpft_lb use ncdio_pio, only : ncd_inqdid, ncd_inqdlen use pftconMod , only : noveg - use HillslopeHydrologyMod, only : pft_distribution_method, pft_from_file, pft_lowland_upland + use HillslopeHydrologyMod, only : pft_distribution_method, pft_from_file, pft_uniform_dominant_pft, pft_lowland_dominant_pft, pft_lowland_upland + use HillslopeHydrologyMod, only : HillslopeDominantPftIndex,HillslopeTwoLargestPftIndices + ! ! !ARGUMENTS: integer, intent(in) :: begg, endg @@ -774,13 +776,13 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) integer ,intent(in) :: ns ! domain size ! ! !LOCAL VARIABLES: - integer :: g, nh, m ! index + integer :: g, nh, m, n ! index integer :: dimid,varid ! netCDF id's integer :: ier ! error status logical :: readvar ! is variable on dataset integer,pointer :: arrayl(:) ! local array (needed because ncd_io expects a pointer) character(len=32) :: subname = 'surfrd_hillslope' ! subroutine name -!----------------------------------------------------------------------- + !----------------------------------------------------------------------- ! number of hillslopes per landunit call ncd_inqdid(ncid,'nhillslope',dimid,readvar) @@ -809,22 +811,57 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) endif deallocate(arrayl) - ! pft_from_file assumes that 1 pft will exist on each - ! hillslope column. In prepration, set one pft weight - ! to 100 and the rest to 0. This will be reassigned when - ! initHillslope is called later. + ! pft_from_file and pft_lowland_upland assume that 1 pft + ! will exist on each hillslope column. In prepration, set one + ! pft weight to 100 and the rest to 0. The vegetation type + ! (patch%itype) will be reassigned when initHillslope is called later. if(pft_distribution_method == pft_from_file .or. & pft_distribution_method == pft_lowland_upland) then do g = begg, endg ! If hillslopes will be used in a gridcell, modify wt_nat_patch, otherwise use original patch distribution if(ncolumns_hillslope(g) > 0) then ! First patch gets 100% weight; all other natural patches are zeroed out - wt_nat_patch(g,:) = 0._r8 + wt_nat_patch(g,:) = 0._r8 wt_nat_patch(g,natpft_lb) = 100._r8 endif enddo endif + ! pft_uniform_dominant_pft uses the patch with the + ! largest weight for all hillslope columns in the gridcell + if (pft_distribution_method == pft_uniform_dominant_pft) then + do g = begg, endg + ! If hillslopes will be used in a gridcell, modify wt_nat_patch, + ! otherwise use original patch distribution + if(ncolumns_hillslope(g) > 0) then + call HillslopeDominantPftIndex(wt_nat_patch(g,:),natpft_lb,m) + wt_nat_patch(g,:) = 0._r8 + wt_nat_patch(g,m) = 100._r8 + endif + enddo + endif + + ! pft_lowland_dominant_pft uses the two patches with the + ! largest weights for the hillslope columns in the gridcell + if (pft_distribution_method == pft_lowland_dominant_pft) then + do g = begg, endg + ! If hillslopes will be used in a gridcell, modify wt_nat_patch, otherwise use original patch distribution + if(ncolumns_hillslope(g) > 0) then + call HillslopeTwoLargestPftIndices(wt_nat_patch(g,:),natpft_lb,m,n) + ! Preserve the relative weights of the largest and + ! next largest weights using arbitrarily chosen values + ! (i.e. m should be larger than n) This will minimize + ! memory usage while still allowing HillslopeDominantLowlandPft + ! to pick out the two largest patch types. + if(m /= n) then + wt_nat_patch(g,:) = 0._r8 + wt_nat_patch(g,m) = 75._r8 + wt_nat_patch(g,n) = 25._r8 + endif + endif + enddo + endif + end subroutine surfrd_hillslope subroutine surfrd_lakemask(begg, endg) From c4d20378382499016c16a8d14c0812f2f2a165e9 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 22 Jul 2022 10:07:07 -0600 Subject: [PATCH 088/153] update patch%mxy --- src/biogeophys/HillslopeHydrologyMod.F90 | 10 ++++++++-- src/cpl/utils/lnd_import_export_utils.F90 | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index fac473c421..6a8730e95c 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -831,6 +831,7 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) use LandunitType , only : lun use ColumnType , only : col use clm_varcon , only : ispval + use clm_varpar , only : natpft_lb use PatchType , only : patch ! ! !ARGUMENTS: @@ -849,11 +850,16 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) if (col%is_hillslope_column(c)) then npatches_per_column = 0 do p = col%patchi(c), col%patchf(c) - if(col%cold(c) == ispval) then ! lowland + if(col%cold(c) == ispval) then + ! lowland patch%itype(p) = lowland_ivt - else ! upland + else + ! upland patch%itype(p) = upland_ivt endif + ! update mxy as is done in initSubgridMod.add_patch + patch%mxy(p) = patch%itype(p) + (1 - natpft_lb) + npatches_per_column = npatches_per_column + 1 enddo if (check_npatches) then diff --git a/src/cpl/utils/lnd_import_export_utils.F90 b/src/cpl/utils/lnd_import_export_utils.F90 index 5a459d1ddd..092fd81205 100644 --- a/src/cpl/utils/lnd_import_export_utils.F90 +++ b/src/cpl/utils/lnd_import_export_utils.F90 @@ -144,6 +144,7 @@ end subroutine check_for_errors !============================================================================= subroutine check_for_nans(array, fname, begg) + use GridcellType , only : grc ! input/output variables real(r8) , intent(in) :: array(:) @@ -161,7 +162,7 @@ subroutine check_for_nans(array, fname, begg) write(iulog,*) 'Which are NaNs = ', isnan(array) do i = 1, size(array) if (isnan(array(i))) then - write(iulog,*) "NaN found in field ", trim(fname), ' at gridcell index ',begg+i-1 + write(iulog,*) "NaN found in field ", trim(fname), ' at gridcell index ',begg+i-1,grc%londeg(begg+i-1),grc%latdeg(begg+i-1) end if end do call shr_sys_abort(' ERROR: One or more of the output from CLM to the coupler are NaN ' ) From e4c79e65f8bd6ea3b001eb2381cdd79d62169bff Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 4 Aug 2022 10:31:11 -0600 Subject: [PATCH 089/153] fix circular dependency (use_fun) --- src/main/clm_instMod.F90 | 14 ++++++++++++++ src/main/initVerticalMod.F90 | 14 +++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 7924c2111e..0ce12ac8e5 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -200,6 +200,12 @@ subroutine clm_instInit(bounds) use SoilWaterRetentionCurveFactoryMod , only : create_soil_water_retention_curve use decompMod , only : get_proc_bounds use BalanceCheckMod , only : GetBalanceCheckSkipSteps + +!scs + use clm_varctl , only : use_hillslope + use HillslopeHydrologyMod, only : SetHillslopeSoilThickness + use initVerticalMod , only : setSoilLayerClass + ! ! !ARGUMENTS type(bounds_type), intent(in) :: bounds ! processor bounds @@ -268,6 +274,14 @@ subroutine clm_instInit(bounds) glc_behavior, & urbanparams_inst%thick_wall(begl:endl), & urbanparams_inst%thick_roof(begl:endl)) +!scs + ! Set hillslope column bedrock values + if(use_hillslope) then + call SetHillslopeSoilThickness(bounds,fsurdat, & + soil_depth_lowland_in=8.5_r8,& + soil_depth_upland_in =2.0_r8) + call setSoilLayerClass(bounds) + endif !----------------------------------------------- ! Set cold-start values for snow levels, snow layers and snow interfaces diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index aeea19813f..0a0b0ed300 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -19,7 +19,7 @@ module initVerticalMod use clm_varctl , only : use_vancouver, use_mexicocity, use_extralakelayers use clm_varctl , only : use_bedrock, rundef use clm_varctl , only : soil_layerstruct_predefined, soil_layerstruct_userdefined - use clm_varctl , only : use_fates, use_hillslope + use clm_varctl , only : use_fates!scs, use_hillslope use clm_varcon , only : zlak, dzlak, zsoi, dzsoi, zisoi, dzsoi_decomp, spval, ispval, grlnd use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, is_hydrologically_active use landunit_varcon , only : istdlak, istice @@ -149,7 +149,7 @@ end subroutine setSoilLayerClass !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) use clm_varcon , only : zmin_bedrock - use HillslopeHydrologyMod, only : SetHillslopeSoilThickness +!scs use HillslopeHydrologyMod, only : SetHillslopeSoilThickness ! ! !ARGUMENTS: @@ -581,11 +581,11 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) deallocate(zbedrock_in) ! Set hillslope column bedrock values - if(use_hillslope) then - call SetHillslopeSoilThickness(bounds,fsurdat, & - soil_depth_lowland_in=8.5_r8,& - soil_depth_upland_in =2.0_r8) - endif +!!$ if(use_hillslope) then +!!$ call SetHillslopeSoilThickness(bounds,fsurdat, & +!!$ soil_depth_lowland_in=8.5_r8,& +!!$ soil_depth_upland_in =2.0_r8) +!!$ endif !----------------------------------------------- ! Set lake levels and layers (no interfaces) From 569cbbd83c0cff9beefd676b97070b91969562db Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 4 Aug 2022 10:47:46 -0600 Subject: [PATCH 090/153] remove comments --- src/main/clm_instMod.F90 | 7 +++---- src/main/initVerticalMod.F90 | 10 +--------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 0ce12ac8e5..7393116da6 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -201,9 +201,8 @@ subroutine clm_instInit(bounds) use decompMod , only : get_proc_bounds use BalanceCheckMod , only : GetBalanceCheckSkipSteps -!scs - use clm_varctl , only : use_hillslope - use HillslopeHydrologyMod, only : SetHillslopeSoilThickness + use clm_varctl , only : use_hillslope + use HillslopeHydrologyMod , only : SetHillslopeSoilThickness use initVerticalMod , only : setSoilLayerClass ! @@ -274,7 +273,7 @@ subroutine clm_instInit(bounds) glc_behavior, & urbanparams_inst%thick_wall(begl:endl), & urbanparams_inst%thick_roof(begl:endl)) -!scs + ! Set hillslope column bedrock values if(use_hillslope) then call SetHillslopeSoilThickness(bounds,fsurdat, & diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index 0a0b0ed300..fce9a1f83f 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -19,7 +19,7 @@ module initVerticalMod use clm_varctl , only : use_vancouver, use_mexicocity, use_extralakelayers use clm_varctl , only : use_bedrock, rundef use clm_varctl , only : soil_layerstruct_predefined, soil_layerstruct_userdefined - use clm_varctl , only : use_fates!scs, use_hillslope + use clm_varctl , only : use_fates use clm_varcon , only : zlak, dzlak, zsoi, dzsoi, zisoi, dzsoi_decomp, spval, ispval, grlnd use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall, is_hydrologically_active use landunit_varcon , only : istdlak, istice @@ -149,7 +149,6 @@ end subroutine setSoilLayerClass !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) use clm_varcon , only : zmin_bedrock -!scs use HillslopeHydrologyMod, only : SetHillslopeSoilThickness ! ! !ARGUMENTS: @@ -580,13 +579,6 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) deallocate(zbedrock_in) - ! Set hillslope column bedrock values -!!$ if(use_hillslope) then -!!$ call SetHillslopeSoilThickness(bounds,fsurdat, & -!!$ soil_depth_lowland_in=8.5_r8,& -!!$ soil_depth_upland_in =2.0_r8) -!!$ endif - !----------------------------------------------- ! Set lake levels and layers (no interfaces) !----------------------------------------------- From 5a5ab1d2724eec1e1a90c47ef5981f16b45fd786 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 9 Aug 2022 08:22:15 -0600 Subject: [PATCH 091/153] move allocate statement in HillslopeHydrologyMod --- src/biogeophys/HillslopeHydrologyMod.F90 | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 6a8730e95c..fa450575f1 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -385,18 +385,6 @@ subroutine InitHillslope(bounds,fsurdat) hill_height(l,:) = fhillslope_in(g,:) enddo - call ncd_io(ncid=ncid, varname='h_bedrock', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - allocate(hill_bedrock (bounds%begl:bounds%endl,max_columns_hillslope), stat=ierr) - if (masterproc) then - write(iulog,*) 'h_bedrock found on surface data set' - end if - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - hill_bedrock(l,:) = fhillslope_in(g,:) - enddo - end if - deallocate(fhillslope_in) allocate(ihillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) @@ -659,9 +647,9 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d call getfil (fsurdat, locfn, 0) call ncd_pio_openfile (ncid, locfn, 0) + allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='h_bedrock', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (readvar) then - allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) if (masterproc) then write(iulog,*) 'h_bedrock found on surface data set' else From 96ded97f6988c9c8b61c3d3da3c5e0f03360e35d Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 26 Aug 2022 08:01:05 -0600 Subject: [PATCH 092/153] fix linear soil profile slope --- src/biogeophys/HillslopeHydrologyMod.F90 | 10 ++++++++-- src/biogeophys/WaterFluxType.F90 | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index fa450575f1..1257e43557 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -735,6 +735,7 @@ subroutine HillslopeSoilThicknessProfile(bounds,& real(r8) :: soil_depth_upland real(r8), parameter :: soil_depth_lowland_default = 8.0 real(r8), parameter :: soil_depth_upland_default = 8.0 + real(r8), parameter :: toosmall_distance = 1e-6 character(len=*), parameter :: subname = 'HillslopeSoilThicknessProfile' @@ -780,8 +781,13 @@ subroutine HillslopeSoilThicknessProfile(bounds,& do l = bounds%begl,bounds%endl min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) - m = (soil_depth_lowland - soil_depth_upland)/ & - (max_hill_dist - min_hill_dist) + + if(abs(max_hill_dist - min_hill_dist) > toosmall_distance) then + m = (soil_depth_lowland - soil_depth_upland)/ & + (max_hill_dist - min_hill_dist) + else + m = 0._r8 + endif b = soil_depth_upland do c = lun%coli(l), lun%colf(l) diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index fb4ba242fe..8b2c4279ed 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -419,6 +419,7 @@ subroutine InitHistory(this, bounds) begp = bounds%begp; endp= bounds%endp begc = bounds%begc; endc= bounds%endc + begl = bounds%begl; endl= bounds%endl begg = bounds%begg; endg= bounds%endg this%qflx_through_liq_patch(begp:endp) = spval From 61eb82ff2c862eca136ca89ac9ccb12d91c8689d Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 15 Sep 2022 13:53:00 -0600 Subject: [PATCH 093/153] minor cleanup --- src/biogeochem/DryDepVelocity.F90 | 8 -------- src/main/atm2lndType.F90 | 1 + src/main/initGridCellsMod.F90 | 3 +-- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/biogeochem/DryDepVelocity.F90 b/src/biogeochem/DryDepVelocity.F90 index 390de90a4b..18423f9b13 100644 --- a/src/biogeochem/DryDepVelocity.F90 +++ b/src/biogeochem/DryDepVelocity.F90 @@ -284,14 +284,6 @@ subroutine depvel_compute( bounds, & if ( n_drydep == 0 ) return - associate( & - forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) - forc_solad => atm2lnd_inst%forc_solad_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) - forc_t => atm2lnd_inst%forc_t_downscaled_col , & ! Input: [real(r8) (:) ] downscaled atmospheric temperature (Kelvin) - forc_q => wateratm2lndbulk_inst%forc_q_downscaled_col , & ! Input: [real(r8) (:) ] downscaled atmospheric specific humidity (kg/kg) - forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] downscaled surface pressure (Pa) - forc_rain => wateratm2lndbulk_inst%forc_rain_downscaled_col , & ! Input: [real(r8) (:) ] downscaled rain rate [mm/s] - associate( & forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) forc_solad => atm2lnd_inst%forc_solad_downscaled_col, & ! Input: [real(r8) (:,:) ] direct beam radiation (visible only) diff --git a/src/main/atm2lndType.F90 b/src/main/atm2lndType.F90 index d4b3370f18..b99e0c8ba1 100644 --- a/src/main/atm2lndType.F90 +++ b/src/main/atm2lndType.F90 @@ -563,6 +563,7 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='atmospheric incident solar radiation received from atmosphere (pre-downscaling)', & ptr_lnd=this%forc_solar_not_downscaled_grc) + this%forc_o3_grc(begg:endg) = spval call hist_addfld1d (fname='ATM_O3', units='mol/mol', & avgflag='A', long_name='atmospheric ozone partial pressure', & ptr_lnd=this%forc_o3_grc, default = 'inactive') diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index 193819f531..3cd5ecf1e6 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -271,8 +271,7 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) npatches_added = npatches_added + 1 end if end do - ->>>>>>> escomp/master + end do end if SHR_ASSERT_FL(nlunits_added == nlunits, sourcefile, __LINE__) From 3ef6829cf673b13096901caf0ba6e9374ea671ec Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 11 Nov 2022 09:56:22 -0700 Subject: [PATCH 094/153] add illumination threshold for solar downscaling --- src/biogeophys/HillslopeHydrologyMod.F90 | 11 +++++------ src/biogeophys/SoilHydrologyMod.F90 | 11 +++++++++++ src/main/atm2lndMod.F90 | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 1257e43557..a3fb016e23 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -520,6 +520,7 @@ subroutine InitHillslope(bounds,fsurdat) ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 ! Number of representative hillslopes per landunit ! is the total area divided by individual area + ! include factor of 0.5 because a channel is shared by ~2 hillslopes lun%stream_channel_number(l) = 0._r8 do nh = 1, nhillslope @@ -528,23 +529,21 @@ subroutine InitHillslope(bounds,fsurdat) *pct_hillslope(l,nh)*0.01/hillslope_area(nh) lun%stream_channel_number(l) = lun%stream_channel_number(l) & - + nhill_per_landunit(nh) + + 0.5_r8 * nhill_per_landunit(nh) endif enddo ! Calculate steam channel length ! Total length of stream banks is individual widths - ! times number of hillslopes per landunit divided - ! by 2 to convert from bank length to channel length - + ! times number of hillslopes per landunit + ! include factor of 0.5 because a channel is shared by ~2 hillslopes lun%stream_channel_length(l) = 0._r8 do c = lun%coli(l), lun%colf(l) if(col%cold(c) == ispval) then lun%stream_channel_length(l) = lun%stream_channel_length(l) & - + col%hill_width(c) * nhill_per_landunit(col%hillslope_ndx(c)) + + col%hill_width(c) * 0.5_r8 * nhill_per_landunit(col%hillslope_ndx(c)) endif enddo - lun%stream_channel_length(l) = 0.5_r8 * lun%stream_channel_length(l) endif ! if missing hillslope information on surface dataset, diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 8611853174..ccd22bc511 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2092,6 +2092,7 @@ subroutine SubsurfaceLateralFlow(bounds, & ! !USES: use clm_time_manager , only : get_step_size use clm_varpar , only : nlevsoi, nlevgrnd, nlayer, nlayert + use clm_varctl , only : nhillslope use clm_varcon , only : pondmx, watmin,rpi, secspday use column_varcon , only : icol_road_perv use abortutils , only : endrun @@ -2138,6 +2139,7 @@ subroutine SubsurfaceLateralFlow(bounds, & real(r8) :: head_gradient ! hydraulic head gradient (m/m) real(r8) :: stream_water_depth ! depth of water in stream channel (m) real(r8) :: stream_channel_depth ! depth of stream channel (m) + real(r8) :: available_stream_water ! stream water (m3) real(r8), parameter :: n_baseflow = 1 ! drainage power law exponent real(r8), parameter :: k_anisotropic = 1._r8 ! anisotropy scalar real(r8) :: qflx_latflow_out_vol(bounds%begc:bounds%endc) ! volumetric lateral flow (m3/s) @@ -2348,6 +2350,15 @@ subroutine SubsurfaceLateralFlow(bounds, & ! include ice impedance in transmissivity qflx_latflow_out_vol(c) = transmis*col%hill_width(c)*head_gradient + ! When head gradient is negative (losing stream channel), + ! limit outflow by available stream channel water + if (qflx_latflow_out_vol(c) < 0._r8) then + available_stream_water = stream_water_volume(l)/lun%stream_channel_number(l)/nhillslope + if(abs(qflx_latflow_out_vol(c))*dtime > available_stream_water) then + qflx_latflow_out_vol(c) = -available_stream_water/dtime + endif + endif + ! volumetric_discharge from lowest column is qflx_latflow_out_vol ! scaled by total area of column in gridcell divided by column area if (col%cold(c) == ispval) then diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 098f15fb76..c3a4766ddb 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -758,6 +758,8 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) real(r8) :: norm(numrad) real(r8) :: sum_solar(bounds%begg:bounds%endg,numrad) real(r8) :: sum_wtgcell(bounds%begg:bounds%endg) + real(r8) :: illum_frac(bounds%begg:bounds%endg) + real(r8), parameter :: illumination_threshold = 0.05 logical :: checkConservation = .true. character(len=*), parameter :: subname = 'downscale_hillslope_solar' @@ -778,25 +780,37 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) ! Initialize column forcing sum_solar(bounds%begg:bounds%endg,1:numrad) = 0._r8 sum_wtgcell(bounds%begg:bounds%endg) = 0._r8 + illum_frac(bounds%begg:bounds%endg) = 0._r8 do c = bounds%begc,bounds%endc g = col%gridcell(c) if (col%is_hillslope_column(c) .and. col%active(c)) then if (coszen_grc(g) > 0._r8) then forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) + if (coszen_col(c) > 0._r8) then + illum_frac(g) = illum_frac(g) + col%wtgcell(c) + endif endif sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtgcell(c)*forc_solad_col(c,1:numrad) sum_wtgcell(g) = sum_wtgcell(g) + col%wtgcell(c) end if end do - + + ! Calculate illuminated fraction of gridcell + do g = bounds%begg,bounds%endg + if (sum_wtgcell(g) > 0._r8) then + illum_frac(g) = illum_frac(g)/sum_wtgcell(g) + endif + enddo + ! Normalize column level solar do c = bounds%begc,bounds%endc if (col%is_hillslope_column(c) .and. col%active(c)) then g = col%gridcell(c) do n = 1,numrad ! absorbed energy is solar flux x area landunit (sum_wtgcell) - if(sum_solar(g,n) > 0._r8) then + !if(sum_solar(g,n) > 0._r8) then + if(sum_solar(g,n) > 0._r8.and.illum_frac(g) > illumination_threshold) then norm(n) = sum_wtgcell(g)*forc_solad_grc(g,n)/sum_solar(g,n) forc_solad_col(c,n) = forc_solad_col(c,n)*norm(n) else From 98636e8b55d68441fac00f8b5c8e62ed11a55549 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 18 Nov 2022 07:42:17 -0700 Subject: [PATCH 095/153] no hillslope columns when lun%wtgcell is zero --- src/biogeophys/HillslopeHydrologyMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index a3fb016e23..ce015e25ae 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -257,8 +257,8 @@ subroutine InitHillslope(bounds,fsurdat) do l = bounds%begl,bounds%endl g = lun%gridcell(l) ncolumns_hillslope(l) = ncolumns_hillslope_in(g) - ! vegetated landunits having nonzero hillslope columns - if(lun%itype(l) == istsoil .and. ncolumns_hillslope_in(g) > 0) then + ! vegetated landunits having nonzero hillslope columns and nonzero weight + if(lun%wtgcell(l) > 0._r8 .and. lun%itype(l) == istsoil .and. ncolumns_hillslope_in(g) > 0) then do c = lun%coli(l), lun%colf(l) col%is_hillslope_column(c) = .true. enddo From 00e71e11e08e27442f1b287bec1fe6bf29497b04 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 3 Feb 2023 11:53:52 -0700 Subject: [PATCH 096/153] write global indices --- src/biogeophys/SoilHydrologyMod.F90 | 2 +- src/main/histFileMod.F90 | 41 +++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index ccd22bc511..1d5701a318 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2352,7 +2352,7 @@ subroutine SubsurfaceLateralFlow(bounds, & ! When head gradient is negative (losing stream channel), ! limit outflow by available stream channel water - if (qflx_latflow_out_vol(c) < 0._r8) then + if (use_hillslope_routing .and. (qflx_latflow_out_vol(c) < 0._r8)) then available_stream_water = stream_water_volume(l)/lun%stream_channel_number(l)/nhillslope if(abs(qflx_latflow_out_vol(c))*dtime > available_stream_water) then qflx_latflow_out_vol(c) = -available_stream_water/dtime diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index e8beafbf40..5d879c4596 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -15,7 +15,7 @@ module histFileMod use clm_varctl , only : iulog, use_fates, compname, use_cn, use_crop use clm_varcon , only : spval, ispval use clm_varcon , only : grlnd, nameg, namel, namec, namep - use decompMod , only : get_proc_bounds, get_proc_global, bounds_type, get_global_index_array + use decompMod , only : get_proc_bounds, get_proc_global, bounds_type, get_global_index, get_global_index_array use decompMod , only : subgrid_level_gridcell, subgrid_level_landunit, subgrid_level_column use GridcellType , only : grc use LandunitType , only : lun @@ -2982,7 +2982,7 @@ subroutine htape_timeconst(t, mode) ! !USES: use clm_varpar , only : nlevsoi use clm_varctl , only : use_hillslope - use clm_varcon , only : zsoi, zlak, secspday, isecspday, isecsphr, isecspmin + use clm_varcon , only : zsoi, zlak, secspday, isecspday, isecsphr, isecspmin, ispval use domainMod , only : ldomain, lon1d, lat1d use clm_time_manager, only : get_nstep, get_curr_date, get_curr_time use clm_time_manager, only : get_ref_date, get_calendar, NO_LEAP_C, GREGORIAN_C @@ -3036,7 +3036,7 @@ subroutine htape_timeconst(t, mode) ! integer :: sec_hist_nhtfrq ! hist_nhtfrq converted to seconds ! !LOCAL VARIABLES: - integer :: vid,n,i,j,m ! indices + integer :: vid,n,i,j,m,c ! indices integer :: nstep ! current step integer :: mcsec ! seconds of current date integer :: mdcur ! current day @@ -3062,6 +3062,9 @@ subroutine htape_timeconst(t, mode) real(r8), pointer :: histo(:,:) ! temporary integer :: status real(r8) :: zsoi_1d(1) + type(bounds_type) :: bounds + integer :: ier ! error status + integer, pointer :: icarr(:) ! temporary character(len=*),parameter :: subname = 'htape_timeconst' !----------------------------------------------------------------------- @@ -3069,6 +3072,9 @@ subroutine htape_timeconst(t, mode) !*** Time constant grid variables only on first time-sample of file *** !------------------------------------------------------------------------------- + call get_proc_bounds(bounds) + + if (tape(t)%ntimes == 1) then if (mode == 'define') then call ncd_defvar(varname='levgrnd', xtype=tape(t)%ncprec, & @@ -3208,8 +3214,33 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='hslp_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_aspect' , data=col%hill_aspect, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_cold' , data=col%cold, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_colu' , data=col%colu, dim1name=namec, ncid=nfid(t), flag='write') + + ! write global indices rather than local indices + allocate(icarr(bounds%begc:bounds%endc),stat=ier) + if (ier /= 0) then + call endrun(msg=' allocation error of icarr'//errMsg(sourcefile, __LINE__)) + end if + + do c = bounds%begc,bounds%endc + if (col%cold(c) /= ispval) then + icarr(c)= get_global_index(subgrid_index=col%cold(c), subgrid_level=subgrid_level_column) + else + icarr(c)= col%cold(c) + endif + enddo + + call ncd_io(varname='hslp_cold' , data=icarr, dim1name=namec, ncid=nfid(t), flag='write') + + do c = bounds%begc,bounds%endc + if (col%colu(c) /= ispval) then + icarr(c)= get_global_index(subgrid_index=col%colu(c), subgrid_level=subgrid_level_column) + else + icarr(c)= col%colu(c) + endif + enddo + + call ncd_io(varname='hslp_colu' , data=icarr, dim1name=namec, ncid=nfid(t), flag='write') + deallocate(icarr) endif if(use_fates)then From 806c6f60eefbe2116def77ac29e542a1d4ea7429 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 15 May 2023 09:25:50 -0600 Subject: [PATCH 097/153] add h_slope --- src/biogeophys/HydrologyNoDrainageMod.F90 | 5 ++- src/biogeophys/SoilHydrologyMod.F90 | 48 +++++++++++--------- src/biogeophys/SoilWaterMovementMod.F90 | 13 +++++- src/biogeophys/SurfaceWaterMod.F90 | 54 +++++++++++++++++++++-- src/main/initVerticalMod.F90 | 9 +++- 5 files changed, 99 insertions(+), 30 deletions(-) diff --git a/src/biogeophys/HydrologyNoDrainageMod.F90 b/src/biogeophys/HydrologyNoDrainageMod.F90 index 59dc7f3da3..78db1ef68f 100644 --- a/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -165,7 +165,7 @@ subroutine HydrologyNoDrainage(bounds, & use SoilWaterMovementMod , only : SoilWater use SoilWaterRetentionCurveMod, only : soil_water_retention_curve_type use SoilWaterMovementMod , only : use_aquifer_layer - use SoilWaterPlantSinkMod , only : Compute_EffecRootFrac_And_VertTranSink + use SoilWaterPlantSinkMod, only : Compute_EffecRootFrac_And_VertTranSink use SurfaceWaterMod , only : UpdateH2osfc ! @@ -325,7 +325,8 @@ subroutine HydrologyNoDrainage(bounds, & call UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & infiltration_excess_runoff_inst, & energyflux_inst, soilhydrology_inst, & - b_waterflux_inst, b_waterstate_inst, b_waterdiagnostic_inst) + b_waterflux_inst, b_waterstate_inst, b_waterdiagnostic_inst, & + soilstate_inst) call Infiltration(bounds, num_hydrologyc, filter_hydrologyc, & b_waterflux_inst) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 1d5701a318..27f49035a8 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -65,7 +65,7 @@ module SoilHydrologyMod real(r8) :: perched_baseflow_scalar ! Scalar multiplier for perched base flow rate (kg/m2/s) real(r8) :: e_ice ! Soil ice impedance factor (unitless) end type params_type - type(params_type), private :: params_inst + type(params_type), public :: params_inst !----------------------------------------------------------------------- real(r8), private :: baseflow_scalar = 1.e-2_r8 @@ -1830,10 +1830,11 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & ! bankfull height is defined to be zero head_gradient = (col%hill_elev(c)-zwt_perched(c)) & ! ignore overbankfull storage - - min(max((stream_water_depth - stream_channel_depth), & - (col%hill_elev(c)-frost_table(c))),0._r8) + - max(min((stream_water_depth - stream_channel_depth),0._r8), & + (col%hill_elev(c)-frost_table(c))) head_gradient = head_gradient / (col%hill_distance(c)) + ! head_gradient cannot be negative when channel is empty if (stream_water_depth <= 0._r8) then head_gradient = max(head_gradient, 0._r8) @@ -2172,6 +2173,7 @@ subroutine SubsurfaceLateralFlow(bounds, & depth => soilhydrology_inst%depth_col , & ! Input: [real(r8) (:,:) ] VIC soil depth icefrac => soilhydrology_inst%icefrac_col , & ! Output: [real(r8) (:,:) ] fraction of ice in layer + frost_table => soilhydrology_inst%frost_table_col , & ! Input: [real(r8) (:) ] frost table depth (m) zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) stream_water_volume => waterstatebulk_inst%stream_water_volume_lun, & ! Input: [real(r8) (:) ] stream water volume (m3) @@ -2443,25 +2445,29 @@ subroutine SubsurfaceLateralFlow(bounds, & if(drainage_tot > 0.) then !rising water table do j = jwt(c)+1,1,-1 - ! analytical expression for specific yield - s_y = watsat(c,j) & - * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) - s_y=max(s_y,params_inst%aq_sp_yield_min) - - drainage_layer=min(drainage_tot,(s_y*dz(c,j)*1.e3)) - - drainage_layer=max(drainage_layer,0._r8) - h2osoi_liq(c,j) = h2osoi_liq(c,j) + drainage_layer - - drainage_tot = drainage_tot - drainage_layer - - if (drainage_tot <= 0.) then - zwt(c) = zwt(c) - drainage_layer/s_y/1000._r8 - exit - else - zwt(c) = zi(c,j-1) + + ! ensure water is not added to frozen layers + if (zi(c,j) < frost_table(c)) then + ! analytical expression for specific yield + s_y = watsat(c,j) & + * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) + s_y=max(s_y,params_inst%aq_sp_yield_min) + + drainage_layer=min(drainage_tot,(s_y*dz(c,j)*1.e3)) + + drainage_layer=max(drainage_layer,0._r8) + h2osoi_liq(c,j) = h2osoi_liq(c,j) + drainage_layer + + drainage_tot = drainage_tot - drainage_layer + + if (drainage_tot <= 0.) then + zwt(c) = zwt(c) - drainage_layer/s_y/1000._r8 + exit + else + zwt(c) = zi(c,j-1) + endif endif - + enddo !-- remove residual drainage -------------------------------- diff --git a/src/biogeophys/SoilWaterMovementMod.F90 b/src/biogeophys/SoilWaterMovementMod.F90 index 1d990b7f5c..f24b5a1abb 100644 --- a/src/biogeophys/SoilWaterMovementMod.F90 +++ b/src/biogeophys/SoilWaterMovementMod.F90 @@ -1141,6 +1141,7 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & real(r8) :: vLiqRes(bounds%begc:bounds%endc,1:nlevsoi) ! residual for the volumetric liquid water content (v/v) real(r8) :: dwat_temp + real(r8) :: over_saturation !----------------------------------------------------------------------- associate(& @@ -1154,6 +1155,7 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & qcharge => soilhydrology_inst%qcharge_col , & ! Input: [real(r8) (:) ] aquifer recharge rate (mm/s) zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m) + watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity) smp_l => soilstate_inst%smp_l_col , & ! Input: [real(r8) (:,:) ] soil matrix potential [mm] hk_l => soilstate_inst%hk_l_col , & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] ice water (kg/m2) @@ -1390,10 +1392,17 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & end do ! substep loop -! save number of adaptive substeps used during time step + ! save number of adaptive substeps used during time step nsubsteps(c) = nsubstep -! check for negative moisture values + ! check for over-saturated layers + do j = nlayers,2,-1 + over_saturation = max(h2osoi_liq(c,j)-(watsat(c,j)*m_to_mm*dz(c,j)),0._r8) + h2osoi_liq(c,j) = min(watsat(c,j)*m_to_mm*dz(c,j), h2osoi_liq(c,j)) + h2osoi_liq(c,j-1) = h2osoi_liq(c,j-1) + over_saturation + end do + + ! check for negative moisture values do j = 2, nlayers if(h2osoi_liq(c,j) < -1e-6_r8) then write(*,*) 'layer, h2osoi_liq: ', c,j,h2osoi_liq(c,j) diff --git a/src/biogeophys/SurfaceWaterMod.F90 b/src/biogeophys/SurfaceWaterMod.F90 index b293dd792c..cb0f7e212c 100644 --- a/src/biogeophys/SurfaceWaterMod.F90 +++ b/src/biogeophys/SurfaceWaterMod.F90 @@ -345,16 +345,20 @@ end subroutine UpdateState_TooSmallH2osfcToSoil subroutine UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & infiltration_excess_runoff_inst, & energyflux_inst, soilhydrology_inst, & - waterfluxbulk_inst, waterstatebulk_inst, waterdiagnosticbulk_inst) + waterfluxbulk_inst, waterstatebulk_inst, & + waterdiagnosticbulk_inst, soilstate_inst) ! ! !DESCRIPTION: ! Calculate fluxes out of h2osfc and update the h2osfc state ! + use SoilStateType , only : soilstate_type + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points type(infiltration_excess_runoff_type), intent(in) :: infiltration_excess_runoff_inst + type(soilstate_type) , intent(in) :: soilstate_inst type(energyflux_type) , intent(in) :: energyflux_inst type(soilhydrology_type) , intent(in) :: soilhydrology_inst type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst @@ -378,6 +382,7 @@ subroutine UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & qflx_h2osfc_surf => waterfluxbulk_inst%qflx_h2osfc_surf_col , & ! Output: [real(r8) (:) ] surface water runoff (mm H2O /s) qflx_h2osfc_drain => waterfluxbulk_inst%qflx_h2osfc_drain_col , & ! Output: [real(r8) (:) ] bottom drainage from h2osfc (mm H2O /s) + icefrac => soilhydrology_inst%icefrac_col , & ! Input: [real(r8) (:,:) ] fraction of ice h2osfc_thresh => soilhydrology_inst%h2osfc_thresh_col, & ! Input: [real(r8) (:) ] level at which h2osfc "percolates" h2osfcflag => soilhydrology_inst%h2osfcflag & ! Input: integer ) @@ -412,6 +417,8 @@ subroutine UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & h2osfc = h2osfc_partial(bounds%begc:bounds%endc), & frac_h2osfc = frac_h2osfc(bounds%begc:bounds%endc), & qinmax = qinmax(bounds%begc:bounds%endc), & + icefrac = icefrac(bounds%begc:bounds%endc,1), & + soilstate_inst = soilstate_inst, & qflx_h2osfc_drain = qflx_h2osfc_drain(bounds%begc:bounds%endc)) ! Update h2osfc based on fluxes @@ -483,6 +490,10 @@ subroutine QflxH2osfcSurf(bounds, num_hydrologyc, filter_hydrologyc, & if(h2osfc(c) > h2osfc_thresh(c) .and. h2osfcflag/=0) then ! spatially variable k_wet k_wet=1.0e-4_r8 * sin((rpi/180._r8) * topo_slope(c)) + if (col%is_hillslope_column(c)) then + ! may require a minimum value to ensure non-zero outflow + k_wet = 1e-4_r8 * max(col%hill_slope(c),0.02_r8) + endif qflx_h2osfc_surf(c) = k_wet * frac_infclust * (h2osfc(c) - h2osfc_thresh(c)) qflx_h2osfc_surf(c)=min(qflx_h2osfc_surf(c),(h2osfc(c) - h2osfc_thresh(c))/dtime) @@ -501,8 +512,8 @@ end subroutine QflxH2osfcSurf !----------------------------------------------------------------------- subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & - h2osfcflag, h2osfc, frac_h2osfc, qinmax, & - qflx_h2osfc_drain) + h2osfcflag, h2osfc, frac_h2osfc, qinmax, icefrac, & + soilstate_inst, qflx_h2osfc_drain) ! ! !DESCRIPTION: ! Compute qflx_h2osfc_drain @@ -510,6 +521,11 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & ! Note that, if h2osfc is negative, then qflx_h2osfc_drain will be negative - acting ! to exactly restore h2osfc to 0. ! + ! !USES: + use ColumnType , only: col + use SoilHydrologyMod, only: params_inst + use SoilStateType , only: soilstate_type + ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter @@ -518,11 +534,19 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) , intent(in) :: h2osfc( bounds%begc: ) ! surface water (mm) real(r8) , intent(in) :: frac_h2osfc( bounds%begc: ) ! fraction of ground covered by surface water (0 to 1) real(r8) , intent(in) :: qinmax( bounds%begc: ) ! maximum infiltration rate (mm H2O /s) + real(r8) , intent(in) :: icefrac( bounds%begc: ) ! soil ice fraction in top soil layer () + type(soilstate_type), intent(in) :: soilstate_inst real(r8) , intent(inout) :: qflx_h2osfc_drain( bounds%begc: ) ! bottom drainage from h2osfc (mm H2O /s) ! ! !LOCAL VARIABLES: integer :: fc, c real(r8) :: dtime ! land model time step (sec) + real(r8) :: ice_imped ! ice impedance () + real(r8) :: den ! temporary variable + real(r8) :: hk1 ! surface hydraulic conductivity (mm/s) + real(r8) :: smp1 ! minimum soil suction (mm) + + real(r8),parameter :: m_to_mm = 1.e3_r8 !convert meters to mm character(len=*), parameter :: subname = 'QflxH2osfcDrain' !----------------------------------------------------------------------- @@ -532,6 +556,13 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & SHR_ASSERT_ALL_FL((ubound(qinmax) == (/bounds%endc/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(qflx_h2osfc_drain) == (/bounds%endc/)), sourcefile, __LINE__) + associate(& + z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) + sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) + smp => soilstate_inst%smp_l_col , & ! Input: [real(r8) (:,:) ] soil matrix potential [mm] + hk => soilstate_inst%hk_l_col & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) + ) ! end associate statement + dtime = get_step_size_real() do fc = 1, num_hydrologyc @@ -540,7 +571,20 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & if (h2osfc(c) < 0.0) then qflx_h2osfc_drain(c) = h2osfc(c)/dtime else - qflx_h2osfc_drain(c)=min(frac_h2osfc(c)*qinmax(c),h2osfc(c)/dtime) + + ! calculate surface soil layer hydraulic properties + ice_imped = 10._r8**(-params_inst%e_ice*icefrac(c)) + den = z(c,1)* m_to_mm + hk1 = frac_h2osfc(c)*ice_imped*hk(c,1) + smp1 = -sucsat(c,1) + + ! compute the flux into the top soil layer + qflx_h2osfc_drain(c) = -hk1*(smp(c,1) - smp1)/den + hk1 + + ! bound drainage values + qflx_h2osfc_drain(c)=min(frac_h2osfc(c)*qinmax(c),qflx_h2osfc_drain(c)) + qflx_h2osfc_drain(c)=min(h2osfc(c)/dtime,qflx_h2osfc_drain(c)) + if(h2osfcflag==0) then ! ensure no h2osfc qflx_h2osfc_drain(c)= max(0._r8,h2osfc(c)/dtime) @@ -548,6 +592,8 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & end if end do + end associate + end subroutine QflxH2osfcDrain end module SurfaceWaterMod diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index fce9a1f83f..b492708a14 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -744,7 +744,14 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) do c = begc,endc ! microtopographic parameter, units are meters (try smooth function of slope) slope0 = params_inst%slopemax**(1._r8/params_inst%slopebeta) - col%micro_sigma(c) = (col%topo_slope(c) + slope0)**(params_inst%slopebeta) + + if (col%is_hillslope_column(c)) then + + col%micro_sigma(c) = (atan(col%hill_slope(c)) + slope0)**(params_inst%slopebeta) + else + col%micro_sigma(c) = (col%topo_slope(c) + slope0)**(params_inst%slopebeta) + endif + end do call ncd_pio_closefile(ncid) From 2d9cb4d743e0fa924674090a4ac8b65d34591f8e Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 21 Aug 2023 11:28:33 -0600 Subject: [PATCH 098/153] back out surface water drainage change --- src/biogeophys/SurfaceWaterMod.F90 | 55 ++++-------------------------- 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/src/biogeophys/SurfaceWaterMod.F90 b/src/biogeophys/SurfaceWaterMod.F90 index cb0f7e212c..1550cfba56 100644 --- a/src/biogeophys/SurfaceWaterMod.F90 +++ b/src/biogeophys/SurfaceWaterMod.F90 @@ -345,20 +345,16 @@ end subroutine UpdateState_TooSmallH2osfcToSoil subroutine UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & infiltration_excess_runoff_inst, & energyflux_inst, soilhydrology_inst, & - waterfluxbulk_inst, waterstatebulk_inst, & - waterdiagnosticbulk_inst, soilstate_inst) + waterfluxbulk_inst, waterstatebulk_inst, waterdiagnosticbulk_inst) ! ! !DESCRIPTION: ! Calculate fluxes out of h2osfc and update the h2osfc state ! - use SoilStateType , only : soilstate_type - ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter integer , intent(in) :: filter_hydrologyc(:) ! column filter for soil points type(infiltration_excess_runoff_type), intent(in) :: infiltration_excess_runoff_inst - type(soilstate_type) , intent(in) :: soilstate_inst type(energyflux_type) , intent(in) :: energyflux_inst type(soilhydrology_type) , intent(in) :: soilhydrology_inst type(waterfluxbulk_type) , intent(inout) :: waterfluxbulk_inst @@ -382,7 +378,6 @@ subroutine UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & qflx_h2osfc_surf => waterfluxbulk_inst%qflx_h2osfc_surf_col , & ! Output: [real(r8) (:) ] surface water runoff (mm H2O /s) qflx_h2osfc_drain => waterfluxbulk_inst%qflx_h2osfc_drain_col , & ! Output: [real(r8) (:) ] bottom drainage from h2osfc (mm H2O /s) - icefrac => soilhydrology_inst%icefrac_col , & ! Input: [real(r8) (:,:) ] fraction of ice h2osfc_thresh => soilhydrology_inst%h2osfc_thresh_col, & ! Input: [real(r8) (:) ] level at which h2osfc "percolates" h2osfcflag => soilhydrology_inst%h2osfcflag & ! Input: integer ) @@ -417,8 +412,6 @@ subroutine UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & h2osfc = h2osfc_partial(bounds%begc:bounds%endc), & frac_h2osfc = frac_h2osfc(bounds%begc:bounds%endc), & qinmax = qinmax(bounds%begc:bounds%endc), & - icefrac = icefrac(bounds%begc:bounds%endc,1), & - soilstate_inst = soilstate_inst, & qflx_h2osfc_drain = qflx_h2osfc_drain(bounds%begc:bounds%endc)) ! Update h2osfc based on fluxes @@ -463,6 +456,7 @@ subroutine QflxH2osfcSurf(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) :: dtime ! land model time step (sec) real(r8) :: frac_infclust ! fraction of submerged area that is connected real(r8) :: k_wet ! linear reservoir coefficient for h2osfc + real(r8),paramter :: min_hill_slope = 1e-3_r8! minimum value of hillslope for outflow character(len=*), parameter :: subname = 'QflxH2osfcSurf' !----------------------------------------------------------------------- @@ -491,8 +485,8 @@ subroutine QflxH2osfcSurf(bounds, num_hydrologyc, filter_hydrologyc, & ! spatially variable k_wet k_wet=1.0e-4_r8 * sin((rpi/180._r8) * topo_slope(c)) if (col%is_hillslope_column(c)) then - ! may require a minimum value to ensure non-zero outflow - k_wet = 1e-4_r8 * max(col%hill_slope(c),0.02_r8) + ! require a minimum value to ensure non-zero outflow + k_wet = 1e-4_r8 * max(col%hill_slope(c),min_hill_slope) endif qflx_h2osfc_surf(c) = k_wet * frac_infclust * (h2osfc(c) - h2osfc_thresh(c)) @@ -512,8 +506,8 @@ end subroutine QflxH2osfcSurf !----------------------------------------------------------------------- subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & - h2osfcflag, h2osfc, frac_h2osfc, qinmax, icefrac, & - soilstate_inst, qflx_h2osfc_drain) + h2osfcflag, h2osfc, frac_h2osfc, qinmax, & + qflx_h2osfc_drain) ! ! !DESCRIPTION: ! Compute qflx_h2osfc_drain @@ -521,11 +515,6 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & ! Note that, if h2osfc is negative, then qflx_h2osfc_drain will be negative - acting ! to exactly restore h2osfc to 0. ! - ! !USES: - use ColumnType , only: col - use SoilHydrologyMod, only: params_inst - use SoilStateType , only: soilstate_type - ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds integer , intent(in) :: num_hydrologyc ! number of column soil points in column filter @@ -534,19 +523,11 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) , intent(in) :: h2osfc( bounds%begc: ) ! surface water (mm) real(r8) , intent(in) :: frac_h2osfc( bounds%begc: ) ! fraction of ground covered by surface water (0 to 1) real(r8) , intent(in) :: qinmax( bounds%begc: ) ! maximum infiltration rate (mm H2O /s) - real(r8) , intent(in) :: icefrac( bounds%begc: ) ! soil ice fraction in top soil layer () - type(soilstate_type), intent(in) :: soilstate_inst real(r8) , intent(inout) :: qflx_h2osfc_drain( bounds%begc: ) ! bottom drainage from h2osfc (mm H2O /s) ! ! !LOCAL VARIABLES: integer :: fc, c real(r8) :: dtime ! land model time step (sec) - real(r8) :: ice_imped ! ice impedance () - real(r8) :: den ! temporary variable - real(r8) :: hk1 ! surface hydraulic conductivity (mm/s) - real(r8) :: smp1 ! minimum soil suction (mm) - - real(r8),parameter :: m_to_mm = 1.e3_r8 !convert meters to mm character(len=*), parameter :: subname = 'QflxH2osfcDrain' !----------------------------------------------------------------------- @@ -556,13 +537,6 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & SHR_ASSERT_ALL_FL((ubound(qinmax) == (/bounds%endc/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(qflx_h2osfc_drain) == (/bounds%endc/)), sourcefile, __LINE__) - associate(& - z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) - sucsat => soilstate_inst%sucsat_col , & ! Input: [real(r8) (:,:) ] minimum soil suction (mm) - smp => soilstate_inst%smp_l_col , & ! Input: [real(r8) (:,:) ] soil matrix potential [mm] - hk => soilstate_inst%hk_l_col & ! Input: [real(r8) (:,:) ] hydraulic conductivity (mm/s) - ) ! end associate statement - dtime = get_step_size_real() do fc = 1, num_hydrologyc @@ -571,20 +545,7 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & if (h2osfc(c) < 0.0) then qflx_h2osfc_drain(c) = h2osfc(c)/dtime else - - ! calculate surface soil layer hydraulic properties - ice_imped = 10._r8**(-params_inst%e_ice*icefrac(c)) - den = z(c,1)* m_to_mm - hk1 = frac_h2osfc(c)*ice_imped*hk(c,1) - smp1 = -sucsat(c,1) - - ! compute the flux into the top soil layer - qflx_h2osfc_drain(c) = -hk1*(smp(c,1) - smp1)/den + hk1 - - ! bound drainage values - qflx_h2osfc_drain(c)=min(frac_h2osfc(c)*qinmax(c),qflx_h2osfc_drain(c)) - qflx_h2osfc_drain(c)=min(h2osfc(c)/dtime,qflx_h2osfc_drain(c)) - + qflx_h2osfc_drain(c)=min(frac_h2osfc(c)*qinmax(c),h2osfc(c)/dtime) if(h2osfcflag==0) then ! ensure no h2osfc qflx_h2osfc_drain(c)= max(0._r8,h2osfc(c)/dtime) @@ -592,8 +553,6 @@ subroutine QflxH2osfcDrain(bounds, num_hydrologyc, filter_hydrologyc, & end if end do - end associate - end subroutine QflxH2osfcDrain end module SurfaceWaterMod From 3f4b9a8757488cdf80fb3a28f4e4d82f1298e6b6 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 22 Aug 2023 14:04:29 -0600 Subject: [PATCH 099/153] small fixes --- src/biogeophys/HydrologyNoDrainageMod.F90 | 3 +-- src/biogeophys/SurfaceWaterMod.F90 | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/biogeophys/HydrologyNoDrainageMod.F90 b/src/biogeophys/HydrologyNoDrainageMod.F90 index 78db1ef68f..c7086d8473 100644 --- a/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -325,8 +325,7 @@ subroutine HydrologyNoDrainage(bounds, & call UpdateH2osfc(bounds, num_hydrologyc, filter_hydrologyc, & infiltration_excess_runoff_inst, & energyflux_inst, soilhydrology_inst, & - b_waterflux_inst, b_waterstate_inst, b_waterdiagnostic_inst, & - soilstate_inst) + b_waterflux_inst, b_waterstate_inst, b_waterdiagnostic_inst) call Infiltration(bounds, num_hydrologyc, filter_hydrologyc, & b_waterflux_inst) diff --git a/src/biogeophys/SurfaceWaterMod.F90 b/src/biogeophys/SurfaceWaterMod.F90 index 1550cfba56..562c64cc18 100644 --- a/src/biogeophys/SurfaceWaterMod.F90 +++ b/src/biogeophys/SurfaceWaterMod.F90 @@ -456,7 +456,7 @@ subroutine QflxH2osfcSurf(bounds, num_hydrologyc, filter_hydrologyc, & real(r8) :: dtime ! land model time step (sec) real(r8) :: frac_infclust ! fraction of submerged area that is connected real(r8) :: k_wet ! linear reservoir coefficient for h2osfc - real(r8),paramter :: min_hill_slope = 1e-3_r8! minimum value of hillslope for outflow + real(r8),parameter :: min_hill_slope = 1e-3_r8! minimum value of hillslope for outflow character(len=*), parameter :: subname = 'QflxH2osfcSurf' !----------------------------------------------------------------------- From 3034da18c940fb4d7c4ded0465bbf7842b882abb Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 11 Sep 2023 12:59:39 -0600 Subject: [PATCH 100/153] back out two answer changers --- src/biogeophys/SoilHydrologyMod.F90 | 4 ++-- src/biogeophys/SoilWaterMovementMod.F90 | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 27f49035a8..71b8a9ef96 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2447,7 +2447,7 @@ subroutine SubsurfaceLateralFlow(bounds, & do j = jwt(c)+1,1,-1 ! ensure water is not added to frozen layers - if (zi(c,j) < frost_table(c)) then +!scs if (zi(c,j) < frost_table(c)) then ! analytical expression for specific yield s_y = watsat(c,j) & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) @@ -2466,7 +2466,7 @@ subroutine SubsurfaceLateralFlow(bounds, & else zwt(c) = zi(c,j-1) endif - endif +!scs endif enddo diff --git a/src/biogeophys/SoilWaterMovementMod.F90 b/src/biogeophys/SoilWaterMovementMod.F90 index f24b5a1abb..b56e33706f 100644 --- a/src/biogeophys/SoilWaterMovementMod.F90 +++ b/src/biogeophys/SoilWaterMovementMod.F90 @@ -1395,12 +1395,12 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & ! save number of adaptive substeps used during time step nsubsteps(c) = nsubstep - ! check for over-saturated layers - do j = nlayers,2,-1 - over_saturation = max(h2osoi_liq(c,j)-(watsat(c,j)*m_to_mm*dz(c,j)),0._r8) - h2osoi_liq(c,j) = min(watsat(c,j)*m_to_mm*dz(c,j), h2osoi_liq(c,j)) - h2osoi_liq(c,j-1) = h2osoi_liq(c,j-1) + over_saturation - end do +!!$ ! check for over-saturated layers +!!$ do j = nlayers,2,-1 +!!$ over_saturation = max(h2osoi_liq(c,j)-(watsat(c,j)*m_to_mm*dz(c,j)),0._r8) +!!$ h2osoi_liq(c,j) = min(watsat(c,j)*m_to_mm*dz(c,j), h2osoi_liq(c,j)) +!!$ h2osoi_liq(c,j-1) = h2osoi_liq(c,j-1) + over_saturation +!!$ end do ! check for negative moisture values do j = 2, nlayers From 5924c680499bff065e207d6cc2bc98272866e2f0 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Mon, 11 Sep 2023 13:56:41 -0600 Subject: [PATCH 101/153] reintroduce if-block --- src/biogeophys/SoilHydrologyMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 71b8a9ef96..27f49035a8 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2447,7 +2447,7 @@ subroutine SubsurfaceLateralFlow(bounds, & do j = jwt(c)+1,1,-1 ! ensure water is not added to frozen layers -!scs if (zi(c,j) < frost_table(c)) then + if (zi(c,j) < frost_table(c)) then ! analytical expression for specific yield s_y = watsat(c,j) & * ( 1. - (1.+1.e3*zwt(c)/sucsat(c,j))**(-1./bsw(c,j))) @@ -2466,7 +2466,7 @@ subroutine SubsurfaceLateralFlow(bounds, & else zwt(c) = zi(c,j-1) endif -!scs endif + endif enddo From 4708a4a609a51516bca62d9c2fd547328d5d1fe1 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Thu, 5 Oct 2023 08:21:19 -0600 Subject: [PATCH 102/153] use find_k_max_indices in surfrdMod --- src/biogeophys/HillslopeHydrologyMod.F90 | 157 +++++++--------------- src/cpl/utils/lnd_import_export_utils.F90 | 2 +- src/main/atm2lndMod.F90 | 3 +- src/main/initVerticalMod.F90 | 16 --- src/main/surfrdMod.F90 | 39 ++++-- 5 files changed, 77 insertions(+), 140 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index ce015e25ae..55fa5c53bd 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -27,8 +27,6 @@ module HillslopeHydrologyMod public SetHillslopeSoilThickness public HillslopeSoilThicknessProfile public HillslopeSetLowlandUplandPfts - public HillslopeDominantPftIndex - public HillslopeTwoLargestPftIndices public HillslopeDominantPft public HillslopeDominantLowlandPft public HillslopePftFromFile @@ -184,6 +182,7 @@ subroutine InitHillslope(bounds,fsurdat) use fileutils , only : getfil use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil + use subgridWeightsMod , only : compute_higher_order_weights use ncdio_pio ! @@ -577,9 +576,6 @@ subroutine InitHillslope(bounds,fsurdat) ! to ensure patch exists in every gridcell if (pft_distribution_method == pft_from_file) then call HillslopePftFromFile(bounds,col_pftndx) - else if (pft_distribution_method == pft_uniform_dominant_pft) then - ! Specify single dominant pft per gridcell - call HillslopeDominantPft(bounds) else if (pft_distribution_method == pft_lowland_dominant_pft) then ! Specify different pfts for uplands / lowlands call HillslopeDominantLowlandPft(bounds) @@ -595,6 +591,9 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(col_pftndx) endif + ! Update higher order weights and check that weights sum to 1 + call compute_higher_order_weights(bounds) + call ncd_pio_closefile(ncid) end subroutine InitHillslope @@ -865,76 +864,6 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) end subroutine HillslopeSetLowlandUplandPfts - !------------------------------------------------------------------------ - subroutine HillslopeDominantPftIndex(weights,lbound,pindex) - ! - ! !DESCRIPTION: - ! Locate each gridcell's most dominant pft on the input dataset. - ! This is different than using n_dom_pts = 1, because it is meant - ! to be applied only to gridcells having active hillslope hydrology. - ! This routine is called from surfrd_hillslope. - - ! - ! !USES - ! - ! !ARGUMENTS: - real(r8), intent(in) :: weights(:) ! array of patch weights - integer, intent(in) :: lbound ! lower bound of weights - integer, intent(out) :: pindex ! index of largest weight - ! - ! !LOCAL VARIABLES: - integer :: pdom(1) - - !------------------------------------------------------------------------ - - pdom = maxloc(weights) - pindex = pdom(1) + (lbound - 1) - - end subroutine HillslopeDominantPftIndex - - !------------------------------------------------------------------------ - subroutine HillslopeTwoLargestPftIndices(weights,lbound,pindex1,pindex2) - ! - ! !DESCRIPTION: - ! Locate each gridcell's two most dominant patches on the input dataset. - ! This is different than using n_dom_pts = 2, because it is meant - ! to be applied only to gridcells having active hillslope hydrology. - ! This routine is called from surfrd_hillslope. - - ! - ! !USES - ! - ! !ARGUMENTS: - real(r8), intent(in) :: weights(:) ! array of patch weights - integer, intent(in) :: lbound ! lower bound of weights - integer, intent(out) :: pindex1 ! index of largest weight - integer, intent(out) :: pindex2 ! index of next largest weight - ! - ! !LOCAL VARIABLES: - integer :: pdom(1),psubdom(1) - real(r8),allocatable :: mask(:) - - !------------------------------------------------------------------------ - - pdom = maxloc(weights) - ! create mask to exclude pdom - allocate(mask(size(weights))) - mask(:) = 1. - mask(pdom(1)) = 0. - ! check that more than one nonzero patch weight exists, - ! if not return identical indices - if (sum(mask*weights) > 0) then - psubdom = maxloc(mask*weights) - else - psubdom = pdom - endif - deallocate(mask) - - pindex1 = pdom(1) + (lbound - 1) - pindex2 = psubdom(1) + (lbound - 1) - - end subroutine HillslopeTwoLargestPftIndices - !------------------------------------------------------------------------ subroutine HillslopeDominantPft(bounds) ! @@ -952,6 +881,7 @@ subroutine HillslopeDominantPft(bounds) use decompMod , only : get_clump_bounds, get_proc_clumps use clm_varcon , only : ispval use PatchType , only : patch + use array_utils , only : find_k_max_indices ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -965,7 +895,8 @@ subroutine HillslopeDominantPft(bounds) do c = bounds%begc,bounds%endc if (col%is_hillslope_column(c) .and. (col%npatches(c) > 1)) then - pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) + + call find_k_max_indices(patch%wtcol(col%patchi(c):col%patchf(c)),1,1,pdom) pdom = pdom + (col%patchi(c) - 1) sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) @@ -1003,32 +934,34 @@ subroutine HillslopeDominantLowlandPft(bounds) use clm_varcon , only : ispval use PatchType , only : patch use pftconMod , only : pftcon, ndllf_evr_tmp_tree, nc3_nonarctic_grass, nc4_grass + use array_utils , only : find_k_max_indices ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds ! ! !LOCAL VARIABLES: - integer :: nc,p,pu,pl,l,c ! indices - integer :: pdom(1),psubdom(1) + integer :: p,c ! indices integer :: plow, phigh + integer :: max_index(1) + integer, allocatable :: max_indices(:) ! largest weight pft indices real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc - real(r8),allocatable :: mask(:) !------------------------------------------------------------------------ + allocate(max_indices(2)) do c = bounds%begc,bounds%endc if (col%is_hillslope_column(c)) then - pdom = maxloc(patch%wtcol(col%patchi(c):col%patchf(c))) - ! create mask to exclude pdom - allocate(mask(col%npatches(c))) - mask(:) = 1. - mask(pdom(1)) = 0. - pdom = pdom + (col%patchi(c) - 1) - - psubdom = maxloc(mask*patch%wtcol(col%patchi(c):col%patchf(c))) - psubdom = psubdom + (col%patchi(c) - 1) - deallocate(mask) + ! if only one pft exists, find dominant pft index and set 2nd index to the same value + + if (size(patch%wtcol(col%patchi(c):col%patchf(c))) == 1) then + call find_k_max_indices(patch%wtcol(col%patchi(c):col%patchf(c)),1,1,max_index) + max_indices(1) = max_index(1) + (col%patchi(c) - 1) + max_indices(2) = max_indices(1) + else + call find_k_max_indices(patch%wtcol(col%patchi(c):col%patchf(c)),1,2,max_indices) + max_indices = max_indices + (col%patchi(c) - 1) + endif sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) @@ -1037,34 +970,36 @@ subroutine HillslopeDominantLowlandPft(bounds) patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - - ! assumes trees are 1-8, shrubs 9-11, and grasses 12-14 - ! and puts the lowest ivt on the lowland column - if ((patch%itype(pdom(1)) > patch%itype(psubdom(1)) & - .and. patch%itype(psubdom(1)) > 0) .or. & - (patch%itype(pdom(1)) == 0)) then - plow = psubdom(1) - phigh = pdom(1) + + ! Put the highest stature vegetation on the lowland column + ! non-tree and tree ; place tree on lowland + ! grass and shrub ; place shrub on lowland + ! bare soil and vegetation; place vegetation on lowland + if ((.not. pftcon%is_tree(patch%itype(max_indices(1))) .and. pftcon%is_tree(patch%itype(max_indices(2)))) & + .or. (pftcon%is_grass(patch%itype(max_indices(1))) .and. pftcon%is_shrub(patch%itype(max_indices(2)))) & + .or. (patch%itype(max_indices(1)) == 0)) then + plow = max_indices(2) + phigh = max_indices(1) else - plow = pdom(1) - phigh = psubdom(1) + plow = max_indices(1) + phigh = max_indices(2) endif ! Special cases (subjective) ! if NET/BDT assign BDT to lowland - if ((patch%itype(pdom(1)) == ndllf_evr_tmp_tree) .and. pftcon%is_tree(patch%itype(psubdom(1)))) then - plow = psubdom(1) - phigh = pdom(1) + if ((patch%itype(max_indices(1)) == ndllf_evr_tmp_tree) .and. pftcon%is_tree(patch%itype(max_indices(2)))) then + plow = max_indices(2) + phigh = max_indices(1) endif ! if C3/C4 assign C4 to lowland - if ((patch%itype(pdom(1)) == nc4_grass) .and. (patch%itype(psubdom(1)) == nc3_nonarctic_grass)) then - plow = pdom(1) - phigh = psubdom(1) + if ((patch%itype(max_indices(1)) == nc4_grass) .and. (patch%itype(max_indices(2)) == nc3_nonarctic_grass)) then + plow = max_indices(1) + phigh = max_indices(2) endif - if ((patch%itype(pdom(1)) == nc3_nonarctic_grass) .and. (patch%itype(psubdom(1)) == nc4_grass)) then - plow = psubdom(1) - phigh = pdom(1) + if ((patch%itype(max_indices(1)) == nc3_nonarctic_grass) .and. (patch%itype(max_indices(2)) == nc4_grass)) then + plow = max_indices(2) + phigh = max_indices(1) endif if(col%cold(c) == ispval) then @@ -1080,7 +1015,8 @@ subroutine HillslopeDominantLowlandPft(bounds) endif endif enddo ! end loop c - + deallocate(max_indices) + end subroutine HillslopeDominantLowlandPft !------------------------------------------------------------------------ @@ -1095,6 +1031,7 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) ! !USES use ColumnType , only : col use PatchType , only : patch + use clm_varpar , only : natpft_lb ! ! !ARGUMENTS: @@ -1115,6 +1052,8 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) npatches_per_column = 0 do p = col%patchi(c), col%patchf(c) patch%itype(p) = col_pftndx(c) + ! update mxy as is done in initSubgridMod.add_patch + patch%mxy(p) = patch%itype(p) + (1 - natpft_lb) npatches_per_column = npatches_per_column + 1 enddo if (check_npatches) then diff --git a/src/cpl/utils/lnd_import_export_utils.F90 b/src/cpl/utils/lnd_import_export_utils.F90 index 788afc578a..1b40cb0e6c 100644 --- a/src/cpl/utils/lnd_import_export_utils.F90 +++ b/src/cpl/utils/lnd_import_export_utils.F90 @@ -163,7 +163,7 @@ subroutine check_for_nans(array, fname, begg, direction) write(iulog,*) 'Which are NaNs = ', isnan(array) do i = 1, size(array) if (isnan(array(i))) then - write(iulog,*) "NaN found in field ", trim(fname), ' at gridcell index ',begg+i-1,grc%londeg(begg+i-1),grc%latdeg(begg+i-1) + write(iulog,*) "NaN found in field ", trim(fname), ' at gridcell index/lon/lat: ',begg+i-1,grc%londeg(begg+i-1),grc%latdeg(begg+i-1) end if end do call shr_sys_abort(' ERROR: One or more of the CTSM cap '//direction//' fields are NaN ' ) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index c3a4766ddb..e1904125af 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -809,8 +809,7 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) g = col%gridcell(c) do n = 1,numrad ! absorbed energy is solar flux x area landunit (sum_wtgcell) - !if(sum_solar(g,n) > 0._r8) then - if(sum_solar(g,n) > 0._r8.and.illum_frac(g) > illumination_threshold) then + if(sum_solar(g,n) > 0._r8 .and. illum_frac(g) > illumination_threshold) then norm(n) = sum_wtgcell(g)*forc_solad_grc(g,n)/sum_solar(g,n) forc_solad_col(c,n) = forc_solad_col(c,n)*norm(n) else diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index b492708a14..92788a4609 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -182,22 +182,6 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) integer :: begc, endc integer :: begl, endl integer :: jmin_bedrock - ! Possible values for levgrnd_class. The important thing is that, for a given column, - ! layers that are fundamentally different (e.g., soil vs bedrock) have different - ! values. This information is used in the vertical interpolation in init_interp. - ! - ! IMPORTANT: These values should not be changed lightly. e.g., try to avoid changing - ! the values assigned to LEVGRND_CLASS_STANDARD, LEVGRND_CLASS_DEEP_BEDROCK, etc. The - ! problem with changing these is that init_interp expects that layers with a value of - ! (e.g.) 1 on the source file correspond to layers with a value of 1 on the - ! destination file. So if you change the values of these constants, you either need to - ! adequately inform users of this change, or build in some translation mechanism in - ! init_interp (such as via adding more metadata to the restart file on the meaning of - ! these different values). - ! - ! The distinction between "shallow" and "deep" bedrock is not made explicitly - ! elsewhere. But, since these classes have somewhat different behavior, they are - ! distinguished explicitly here. character(len=*), parameter :: subname = 'initVertical' !------------------------------------------------------------------------ diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 6fad760f01..3935b170d6 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -899,8 +899,8 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) use ncdio_pio, only : ncd_inqdid, ncd_inqdlen use pftconMod , only : noveg use HillslopeHydrologyMod, only : pft_distribution_method, pft_from_file, pft_uniform_dominant_pft, pft_lowland_dominant_pft, pft_lowland_upland - use HillslopeHydrologyMod, only : HillslopeDominantPftIndex,HillslopeTwoLargestPftIndices - + use array_utils, only: find_k_max_indices + ! ! !ARGUMENTS: integer, intent(in) :: begg, endg @@ -908,9 +908,10 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) integer ,intent(in) :: ns ! domain size ! ! !LOCAL VARIABLES: - integer :: g, nh, m, n ! index + integer :: g, nh, m, n ! index integer :: dimid,varid ! netCDF id's integer :: ier ! error status + integer, allocatable :: max_indices(:) ! largest weight pft indices logical :: readvar ! is variable on dataset integer,pointer :: arrayl(:) ! local array (needed because ncd_io expects a pointer) character(len=32) :: subname = 'surfrd_hillslope' ! subroutine name @@ -962,36 +963,50 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! pft_uniform_dominant_pft uses the patch with the ! largest weight for all hillslope columns in the gridcell if (pft_distribution_method == pft_uniform_dominant_pft) then + allocate(max_indices(1)) do g = begg, endg ! If hillslopes will be used in a gridcell, modify wt_nat_patch, ! otherwise use original patch distribution if(ncolumns_hillslope(g) > 0) then - call HillslopeDominantPftIndex(wt_nat_patch(g,:),natpft_lb,m) + + call find_k_max_indices(wt_nat_patch(g,:),natpft_lb,1,max_indices) wt_nat_patch(g,:) = 0._r8 - wt_nat_patch(g,m) = 100._r8 + wt_nat_patch(g,max_indices(1)) = 100._r8 + endif enddo + deallocate(max_indices) endif ! pft_lowland_dominant_pft uses the two patches with the ! largest weights for the hillslope columns in the gridcell if (pft_distribution_method == pft_lowland_dominant_pft) then + allocate(max_indices(2)) do g = begg, endg ! If hillslopes will be used in a gridcell, modify wt_nat_patch, otherwise use original patch distribution if(ncolumns_hillslope(g) > 0) then - call HillslopeTwoLargestPftIndices(wt_nat_patch(g,:),natpft_lb,m,n) + ! Preserve the relative weights of the largest and ! next largest weights using arbitrarily chosen values - ! (i.e. m should be larger than n) This will minimize - ! memory usage while still allowing HillslopeDominantLowlandPft - ! to pick out the two largest patch types. - if(m /= n) then + ! (i.e. 1 should be larger than 2) that sum to 100. + ! This will minimize memory usage while still allowing + ! HillslopeDominantLowlandPft to pick out the two largest patch types. + + call find_k_max_indices(wt_nat_patch(g,:),natpft_lb,2,max_indices) + ! check that 2nd index weight is non-zero + if (wt_nat_patch(g,max_indices(2)) > 0._r8) then + wt_nat_patch(g,:) = 0._r8 + wt_nat_patch(g,max_indices(1)) = 75._r8 + wt_nat_patch(g,max_indices(2)) = 25._r8 + else + ! if only one pft exists, set its weight to 100 per cent wt_nat_patch(g,:) = 0._r8 - wt_nat_patch(g,m) = 75._r8 - wt_nat_patch(g,n) = 25._r8 + wt_nat_patch(g,max_indices(1)) = 100._r8 endif + endif enddo + deallocate(max_indices) endif end subroutine surfrd_hillslope From d303ccb77e790a93822d353f812049455c934031 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 6 Oct 2023 13:35:22 -0600 Subject: [PATCH 103/153] Whitespace alignment in CLMBuildNamelist.pm. --- bld/CLMBuildNamelist.pm | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index e5bda4680d..8eaa4ece8b 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3350,22 +3350,22 @@ sub setup_logic_hillslope { # my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'downscale_hillslope_meteorology' ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_head_gradient_method' ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_transmissivity_method' ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_pft_distribution_method' ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_soil_profile_method' ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope_routing', 'use_hillslope'=>$nl_flags->{'use_hillslope'} ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'downscale_hillslope_meteorology' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_head_gradient_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_transmissivity_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_pft_distribution_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'hillslope_soil_profile_method' ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_hillslope_routing', 'use_hillslope'=>$nl_flags->{'use_hillslope'} ); my $use_hillslope = $nl->get_value('use_hillslope'); my $use_hillslope_routing = $nl->get_value('use_hillslope_routing'); - if ( (! &value_is_true($use_hillslope)) && &value_is_true($use_hillslope_routing) ) { - $log->fatal_error("Cannot turn on use_hillslope_routing when use_hillslope is off\n" ); - } + if ( (! &value_is_true($use_hillslope)) && &value_is_true($use_hillslope_routing) ) { + $log->fatal_error("Cannot turn on use_hillslope_routing when use_hillslope is off\n" ); + } my $downscale_hillslope_meteorology = $nl->get_value('use_hillslope_routing'); - if ( (! &value_is_true($use_hillslope)) && &value_is_true($downscale_hillslope_meteorology) ) { - $log->fatal_error("Cannot turn on downscale_hillslope_meteorology when use_hillslope is off\n" ); - } + if ( (! &value_is_true($use_hillslope)) && &value_is_true($downscale_hillslope_meteorology) ) { + $log->fatal_error("Cannot turn on downscale_hillslope_meteorology when use_hillslope is off\n" ); + } } #------------------------------------------------------------------------------- From bd4a04e7c2e851b66cde9cf71e9ce3bc6fb2a1ac Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 6 Oct 2023 13:39:21 -0600 Subject: [PATCH 104/153] Remove redundant check in CLMBuildNamelist.pm. --- bld/CLMBuildNamelist.pm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 8eaa4ece8b..65943339a1 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3362,10 +3362,6 @@ sub setup_logic_hillslope { if ( (! &value_is_true($use_hillslope)) && &value_is_true($use_hillslope_routing) ) { $log->fatal_error("Cannot turn on use_hillslope_routing when use_hillslope is off\n" ); } - my $downscale_hillslope_meteorology = $nl->get_value('use_hillslope_routing'); - if ( (! &value_is_true($use_hillslope)) && &value_is_true($downscale_hillslope_meteorology) ) { - $log->fatal_error("Cannot turn on downscale_hillslope_meteorology when use_hillslope is off\n" ); - } } #------------------------------------------------------------------------------- From 5491aae3a6fcaa55cf03e575e924883fa7d821ce Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 6 Oct 2023 13:40:40 -0600 Subject: [PATCH 105/153] remove HillslopeDominantPft --- src/biogeophys/HillslopeHydrologyMod.F90 | 52 ------------------------ 1 file changed, 52 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 55fa5c53bd..ed7e6fa547 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -27,7 +27,6 @@ module HillslopeHydrologyMod public SetHillslopeSoilThickness public HillslopeSoilThicknessProfile public HillslopeSetLowlandUplandPfts - public HillslopeDominantPft public HillslopeDominantLowlandPft public HillslopePftFromFile public HillslopeStreamOutflow @@ -864,57 +863,6 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) end subroutine HillslopeSetLowlandUplandPfts - !------------------------------------------------------------------------ - subroutine HillslopeDominantPft(bounds) - ! - ! !DESCRIPTION: - ! Reassign patch weights of each column based on each gridcell's - ! most dominant pft on the input dataset. - ! Assumes each column has a single pft. - ! If n_dom_pfts = 1 or if HillslopeDominantPftIndex is called - ! in surfrd_hillslope, this routine does not act on hillslope columns. - - ! - ! !USES - use LandunitType , only : lun - use ColumnType , only : col - use decompMod , only : get_clump_bounds, get_proc_clumps - use clm_varcon , only : ispval - use PatchType , only : patch - use array_utils , only : find_k_max_indices - ! - ! !ARGUMENTS: - type(bounds_type), intent(in) :: bounds - ! - ! !LOCAL VARIABLES: - integer :: c ! indices - integer :: pdom(1) ! patch index - real(r8) :: sum_wtcol, sum_wtlun, sum_wtgrc ! sum of patch weights - - !------------------------------------------------------------------------ - - do c = bounds%begc,bounds%endc - if (col%is_hillslope_column(c) .and. (col%npatches(c) > 1)) then - - call find_k_max_indices(patch%wtcol(col%patchi(c):col%patchf(c)),1,1,pdom) - pdom = pdom + (col%patchi(c) - 1) - - sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) - sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) - sum_wtgrc = sum(patch%wtgcell(col%patchi(c):col%patchf(c))) - - patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 - patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - - patch%wtcol(pdom(1)) = sum_wtcol - patch%wtlunit(pdom(1)) = sum_wtlun - patch%wtgcell(pdom(1)) = sum_wtgrc - endif - enddo ! end loop c - - end subroutine HillslopeDominantPft - !------------------------------------------------------------------------ subroutine HillslopeDominantLowlandPft(bounds) ! From 79141f832f8c945adda26853b41c76e003c096ab Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 6 Oct 2023 13:57:51 -0600 Subject: [PATCH 106/153] Do not allow use_hillslope with transient land cover change. --- bld/CLMBuildNamelist.pm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 65943339a1..71365669eb 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -2576,6 +2576,8 @@ sub setup_logic_do_transient_pfts { $cannot_be_true = "$var cannot be combined with use_cndv"; } elsif (&value_is_true($nl->get_value('use_fates'))) { $cannot_be_true = "$var cannot be combined with use_fates"; + } elsif (&value_is_true($nl->get_value('use_hillslope'))) { + $cannot_be_true = "$var cannot be combined with use_hillslope"; } if ($cannot_be_true) { @@ -2651,6 +2653,8 @@ sub setup_logic_do_transient_crops { # do_transient_crops. However, this hasn't been tested, so to be safe, # we are not allowing this combination for now. $cannot_be_true = "$var has not been tested with FATES, so for now these two options cannot be combined"; + } elsif (&value_is_true($nl->get_value('use_hillslope'))) { + $cannot_be_true = "$var cannot be combined with use_hillslope"; } if ($cannot_be_true) { @@ -2746,6 +2750,8 @@ sub setup_logic_do_transient_lakes { if (&value_is_true($nl->get_value($var))) { if (&value_is_true($nl->get_value('collapse_urban'))) { $log->fatal_error("$var cannot be combined with collapse_urban"); + } elsif (&value_is_true($nl->get_value('use_hillslope'))) { + $log->fatal_error("$var cannot be combined with use_hillslope"); } if ($n_dom_pfts > 0 || $n_dom_landunits > 0 || $toosmall_soil > 0 || $toosmall_crop > 0 || $toosmall_glacier > 0 || $toosmall_lake > 0 || $toosmall_wetland > 0 || $toosmall_urban > 0) { $log->fatal_error("$var cannot be combined with any of the of the following > 0: n_dom_pfts > 0, n_dom_landunit > 0, toosmall_soil > 0._r8, toosmall_crop > 0._r8, toosmall_glacier > 0._r8, toosmall_lake > 0._r8, toosmall_wetland > 0._r8, toosmall_urban > 0._r8"); @@ -2809,6 +2815,8 @@ sub setup_logic_do_transient_urban { if (&value_is_true($nl->get_value($var))) { if (&value_is_true($nl->get_value('collapse_urban'))) { $log->fatal_error("$var cannot be combined with collapse_urban"); + } elsif (&value_is_true($nl->get_value('use_hillslope'))) { + $log->fatal_error("$var cannot be combined with use_hillslope"); } if ($n_dom_pfts > 0 || $n_dom_landunits > 0 || $toosmall_soil > 0 || $toosmall_crop > 0 || $toosmall_glacier > 0 || $toosmall_lake > 0 || $toosmall_wetland > 0 || $toosmall_urban > 0) { $log->fatal_error("$var cannot be combined with any of the of the following > 0: n_dom_pfts > 0, n_dom_landunit > 0, toosmall_soil > 0._r8, toosmall_crop > 0._r8, toosmall_glacier > 0._r8, toosmall_lake > 0._r8, toosmall_wetland > 0._r8, toosmall_urban > 0._r8"); From fa5161fd8ac312d1d2793da82fbf737c8a34676d Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 6 Oct 2023 15:38:18 -0600 Subject: [PATCH 107/153] Compile fixes from merge of ctsm5.1.dev142. --- src/biogeophys/WaterStateType.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index ca120ce8c2..67dc944ea3 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -15,7 +15,7 @@ module WaterStateType use decompMod , only : subgrid_level_patch, subgrid_level_column, subgrid_level_landunit, subgrid_level_gridcell use clm_varctl , only : use_bedrock, use_excess_ice, iulog use spmdMod , only : masterproc - use clm_varctl , only : use_fates + use clm_varctl , only : use_fates, use_hillslope use clm_varpar , only : nlevgrnd, nlevsoi, nlevurb, nlevmaxurbgrnd, nlevsno use clm_varcon , only : spval use LandunitType , only : lun @@ -300,6 +300,7 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) avgflag='A', & long_name=this%info%lname('volume of water in stream channel (hillslope hydrology only)'), & ptr_lunit=this%stream_water_volume_lun, l2g_scale_type='natveg', default='inactive') + end if ! Add excess ice fields to history From 53b8719db4b06ec6323c233d4459838c0279bfdc Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 3 Nov 2023 13:28:59 -0600 Subject: [PATCH 108/153] Add Hillslope test. --- .../testdefs/testmods_dirs/clm/Hillslope/include_user_mods | 1 + .../testdefs/testmods_dirs/clm/Hillslope/shell_commands | 4 ++++ cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm | 5 +++++ 3 files changed, 10 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Hillslope/include_user_mods new file mode 100644 index 0000000000..fe0e18cf88 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/include_user_mods @@ -0,0 +1 @@ +../default diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands new file mode 100644 index 0000000000..d8dbbb99c3 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands @@ -0,0 +1,4 @@ +./xmlchange CLM_BLDNML_OPTS="-bgc sp" +meshfile=/glade/work/samrabin/hillslope_inputs/ESMFmesh_10x15_synthetic_cosphill_1.0.nc +./xmlchange ATM_DOMAIN_MESH=${meshfile},LND_DOMAIN_MESH=${meshfile} +./xmlchange NTASKS=-2 diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm new file mode 100644 index 0000000000..069edfddbd --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -0,0 +1,5 @@ +fsurdat = '/glade/p/cesmdata/cseg/inputdata/lnd/clm2/surfdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.0.nc' +use_hillslope = .true. +use_hillslope_routing = .true. +hillslope_pft_distribution_method = 'PftLowlandUpland' +use_ssre = .false. From 0e7a9a934d42e41303c598d852b44d1b940be54a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 3 Nov 2023 13:40:08 -0600 Subject: [PATCH 109/153] Removed NTASKS=-2 from shell_commands. --- cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands | 1 - 1 file changed, 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands index d8dbbb99c3..56318395d1 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands @@ -1,4 +1,3 @@ ./xmlchange CLM_BLDNML_OPTS="-bgc sp" meshfile=/glade/work/samrabin/hillslope_inputs/ESMFmesh_10x15_synthetic_cosphill_1.0.nc ./xmlchange ATM_DOMAIN_MESH=${meshfile},LND_DOMAIN_MESH=${meshfile} -./xmlchange NTASKS=-2 From dbf68459821be5c5b10f8732f1d1e7bab36ddd82 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 28 Nov 2023 07:54:19 -0700 Subject: [PATCH 110/153] set c_dst --- src/biogeophys/SoilHydrologyMod.F90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index 27f49035a8..18a8e01944 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -2297,13 +2297,16 @@ subroutine SubsurfaceLateralFlow(bounds, & ! should a warning be used instead? head_gradient = min(max(head_gradient,-2._r8),2._r8) - ! Calculate transmissivity of source column + ! Determine source and destination columns if (head_gradient >= 0._r8) then c_src = c + c_dst = col%cold(c) else c_src = col%cold(c) + c_dst = c endif - + + ! Calculate transmissivity of source column transmis = 0._r8 if(c_src /= ispval) then ! transmissivity non-zero only when saturated conditions exist From 226f0387096b5c967adfd2d3ff3a448aa892f09f Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 28 Nov 2023 08:13:20 -0700 Subject: [PATCH 111/153] move g assignment out of if-block --- src/main/atm2lndMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index e1904125af..084cf56c68 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -805,8 +805,8 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) ! Normalize column level solar do c = bounds%begc,bounds%endc + g = col%gridcell(c) if (col%is_hillslope_column(c) .and. col%active(c)) then - g = col%gridcell(c) do n = 1,numrad ! absorbed energy is solar flux x area landunit (sum_wtgcell) if(sum_solar(g,n) > 0._r8 .and. illum_frac(g) > illumination_threshold) then From e8af14d4b87bef50d8890718604e18bc465faac5 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 28 Nov 2023 08:19:01 -0700 Subject: [PATCH 112/153] revert last change; instead move forc_solar_col inside if-block --- src/main/atm2lndMod.F90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 084cf56c68..7ebfff202e 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -805,8 +805,8 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) ! Normalize column level solar do c = bounds%begc,bounds%endc - g = col%gridcell(c) if (col%is_hillslope_column(c) .and. col%active(c)) then + g = col%gridcell(c) do n = 1,numrad ! absorbed energy is solar flux x area landunit (sum_wtgcell) if(sum_solar(g,n) > 0._r8 .and. illum_frac(g) > illumination_threshold) then @@ -816,12 +816,12 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) forc_solad_col(c,n) = forc_solad_grc(g,n) endif enddo + forc_solar_col(c) = sum(forc_solad_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) end if - forc_solar_col(c) = sum(forc_solad_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) end do - ! check conservation + ! check conservation if(checkConservation) then sum_solar(bounds%begg:bounds%endg,1:numrad) = 0._r8 sum_wtgcell(bounds%begg:bounds%endg) = 0._r8 From d06c3a564a9588e9f886695c69b6a841a5e4c674 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Tue, 28 Nov 2023 08:21:37 -0700 Subject: [PATCH 113/153] move g --- src/main/atm2lndMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index 7ebfff202e..b35c6ae865 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -782,8 +782,8 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) sum_wtgcell(bounds%begg:bounds%endg) = 0._r8 illum_frac(bounds%begg:bounds%endg) = 0._r8 do c = bounds%begc,bounds%endc - g = col%gridcell(c) if (col%is_hillslope_column(c) .and. col%active(c)) then + g = col%gridcell(c) if (coszen_grc(g) > 0._r8) then forc_solad_col(c,1:numrad) = forc_solad_grc(g,1:numrad)*(coszen_col(c)/coszen_grc(g)) if (coszen_col(c) > 0._r8) then From 6efd50cce88f40db610800fc9a929d8524b7b75a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 1 Dec 2023 12:02:23 -0700 Subject: [PATCH 114/153] Update externals to work on Derecho. --- Externals.cfg | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Externals.cfg b/Externals.cfg index 02f64c0210..f5243f9166 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -8,7 +8,7 @@ required = True local_path = components/cism protocol = git repo_url = https://github.com/ESCOMP/CISM-wrapper -tag = cismwrap_2_1_95 +tag = cismwrap_2_1_96 externals = Externals_CISM.cfg required = True @@ -34,7 +34,7 @@ hash = 34723c2 required = True [ccs_config] -tag = ccs_config_cesm0.0.65 +tag = ccs_config_cesm0.0.82 protocol = git repo_url = https://github.com/ESMCI/ccs_config_cesm.git local_path = ccs_config @@ -44,26 +44,26 @@ required = True local_path = cime protocol = git repo_url = https://github.com/ESMCI/cime -tag = cime6.0.125 +tag = cime6.0.175 required = True [cmeps] -tag = cmeps0.14.21 +tag = cmeps0.14.43 protocol = git repo_url = https://github.com/ESCOMP/CMEPS.git local_path = components/cmeps required = True [cdeps] -tag = cdeps1.0.13 +tag = cdeps1.0.23 protocol = git repo_url = https://github.com/ESCOMP/CDEPS.git local_path = components/cdeps -externals = Externals_CDEPS.cfg +externals = Externals_CDEPS.cfg required = True [cpl7] -tag = cpl77.0.5 +tag = cpl77.0.7 protocol = git repo_url = https://github.com/ESCOMP/CESM_CPL7andDataComps local_path = components/cpl7 @@ -84,7 +84,7 @@ local_path = libraries/mct required = True [parallelio] -tag = pio2_5_10 +tag = pio2_6_2 protocol = git repo_url = https://github.com/NCAR/ParallelIO local_path = libraries/parallelio @@ -98,4 +98,4 @@ tag = v1.0.8 required = False [externals_description] -schema_version = 1.0.0 +schema_version = 1.0.0 \ No newline at end of file From c477363c3c6286214d4c57059d89cc4cdf763764 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 1 Dec 2023 13:38:47 -0700 Subject: [PATCH 115/153] Misc. whitespace fixes and reversions. --- src/biogeochem/DryDepVelocity.F90 | 12 +- src/biogeophys/HillslopeHydrologyMod.F90 | 196 +++++++++++------------ src/biogeophys/SoilHydrologyMod.F90 | 40 ++--- src/biogeophys/SurfaceRadiationMod.F90 | 6 +- src/biogeophys/WaterFluxType.F90 | 4 +- src/biogeophys/WaterStateType.F90 | 3 +- src/cpl/nuopc/lnd_import_export.F90 | 4 +- src/main/ColumnType.F90 | 20 +-- src/main/atm2lndMod.F90 | 38 ++--- src/main/clm_driver.F90 | 4 +- src/main/clm_initializeMod.F90 | 10 +- src/main/clm_instMod.F90 | 4 +- src/main/clm_varsur.F90 | 2 +- src/main/controlMod.F90 | 2 +- src/main/histFileMod.F90 | 4 +- src/main/initGridCellsMod.F90 | 4 +- src/main/initVerticalMod.F90 | 3 +- src/main/lnd2atmMod.F90 | 4 +- src/main/subgridMod.F90 | 2 +- src/main/surfrdMod.F90 | 16 +- 20 files changed, 186 insertions(+), 192 deletions(-) diff --git a/src/biogeochem/DryDepVelocity.F90 b/src/biogeochem/DryDepVelocity.F90 index 18423f9b13..1e1d0153b0 100644 --- a/src/biogeochem/DryDepVelocity.F90 +++ b/src/biogeochem/DryDepVelocity.F90 @@ -323,12 +323,12 @@ subroutine depvel_compute( bounds, & g = patch%gridcell(pi) pg = forc_pbot(c) spec_hum = forc_q(c) - rain = forc_rain(c) - sfc_temp = forc_t(c) - solar_flux = forc_solad(c,1) - lat = grc%latdeg(g) - lon = grc%londeg(g) - clmveg = patch%itype(pi) + rain = forc_rain(c) + sfc_temp = forc_t(c) + solar_flux = forc_solad(c,1) + lat = grc%latdeg(g) + lon = grc%londeg(g) + clmveg = patch%itype(pi) soilw = h2osoi_vol(c,1) !map CLM veg type into Wesely veg type diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index ed7e6fa547..868902db90 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -2,7 +2,7 @@ module HillslopeHydrologyMod !----------------------------------------------------------------------- ! !DESCRIPTION: - ! Read geomorphological parameters for hillslope columns + ! Read geomorphological parameters for hillslope columns ! ! !USES: #include "shr_assert.h" @@ -18,7 +18,7 @@ module HillslopeHydrologyMod ! !PUBLIC TYPES: implicit none - private + private save ! !PUBLIC MEMBER FUNCTIONS: @@ -31,10 +31,10 @@ module HillslopeHydrologyMod public HillslopePftFromFile public HillslopeStreamOutflow public HillslopeUpdateStreamWater - + integer, public :: pft_distribution_method ! Method for distributing pfts across hillslope columns integer, public :: soil_profile_method ! Method for varying soil thickness across hillslope columns - + ! Streamflow methods integer, public, parameter :: streamflow_manning = 0 ! Pft distribution methods @@ -44,12 +44,12 @@ module HillslopeHydrologyMod integer, public, parameter :: pft_lowland_dominant_pft = 3 integer, public, parameter :: pft_lowland_upland = 4 - ! PRIVATE + ! PRIVATE character(len=*), parameter, private :: sourcefile = & __FILE__ - integer, private, parameter :: soil_profile_uniform = 0 + integer, private, parameter :: soil_profile_uniform = 0 integer, private, parameter :: soil_profile_from_file = 1 - integer, private, parameter :: soil_profile_set_lowland_upland = 2 + integer, private, parameter :: soil_profile_set_lowland_upland = 2 integer, private, parameter :: soil_profile_linear = 3 !----------------------------------------------------------------------- @@ -87,7 +87,7 @@ subroutine hillslope_properties_init(NLFilename) namelist /hillslope_properties_inparm/ & hillslope_pft_distribution_method, & hillslope_soil_profile_method - + ! Read hillslope hydrology namelist if (masterproc) then nu_nml = getavu() @@ -157,7 +157,7 @@ subroutine check_aquifer_layer() ! !USES: use clm_varctl , only : use_hillslope use SoilWaterMovementMod , only : use_aquifer_layer - if(use_hillslope .and. use_aquifer_layer()) then + if (use_hillslope .and. use_aquifer_layer()) then write(iulog,*) ' ERROR: use_hillslope and use_aquifer_layer may not be used simultaneously' call endrun(msg=' ERROR: use_hillslope and use_aquifer_layer cannot both be set to true' // & errMsg(sourcefile, __LINE__)) @@ -173,17 +173,17 @@ subroutine InitHillslope(bounds,fsurdat) ! Initialize hillslope geomorphology from input dataset ! ! !USES: - use LandunitType , only : lun - use GridcellType , only : grc - use ColumnType , only : col + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col use clm_varctl , only : nhillslope, max_columns_hillslope use spmdMod , only : masterproc use fileutils , only : getfil - use clm_varcon , only : spval, ispval, grlnd + use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil use subgridWeightsMod , only : compute_higher_order_weights use ncdio_pio - + ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -208,15 +208,15 @@ subroutine InitHillslope(bounds,fsurdat) real(r8), pointer :: fstream_in(:) ! read in - 1D - float type(file_desc_t) :: ncid ! netcdf id - logical :: readvar ! check whether variable on file + logical :: readvar ! check whether variable on file character(len=256) :: locfn ! local filename integer :: ierr ! error code integer :: c, l, g, i, j, ci, nh ! indices - real(r8) :: ncol_per_hillslope(nhillslope) ! number of columns per hillslope + real(r8) :: ncol_per_hillslope(nhillslope) ! number of columns per hillslope real(r8) :: hillslope_area(nhillslope) ! area of hillslope real(r8) :: nhill_per_landunit(nhillslope) ! total number of each representative hillslope per landunit - + character(len=*), parameter :: subname = 'InitHillslope' !----------------------------------------------------------------------- @@ -224,11 +224,11 @@ subroutine InitHillslope(bounds,fsurdat) ! consistency check call check_aquifer_layer() - ! Open surface dataset to read in data below + ! Open surface dataset to read in data below call getfil (fsurdat, locfn, 0) call ncd_pio_openfile (ncid, locfn, 0) - + allocate( & ncolumns_hillslope(bounds%begl:bounds%endl), & pct_hillslope(bounds%begl:bounds%endl,nhillslope), & @@ -245,7 +245,7 @@ subroutine InitHillslope(bounds,fsurdat) stat=ierr) allocate(ncolumns_hillslope_in(bounds%begg:bounds%endg)) - + call ncd_io(ncid=ncid, varname='nhillcolumns', flag='read', data=ncolumns_hillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -265,7 +265,7 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(ncolumns_hillslope_in) allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) - + call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -277,9 +277,9 @@ subroutine InitHillslope(bounds,fsurdat) pct_hillslope(l,:) = fhillslope_in(g,:) enddo deallocate(fhillslope_in) - + allocate(ihillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) - + call ncd_io(ncid=ncid, varname='hillslope_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -290,7 +290,7 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) hill_ndx(l,:) = ihillslope_in(g,:) enddo - + call ncd_io(ncid=ncid, varname='column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -301,7 +301,7 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) col_ndx(l,:) = ihillslope_in(g,:) enddo - + call ncd_io(ncid=ncid, varname='downhill_column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -313,7 +313,7 @@ subroutine InitHillslope(bounds,fsurdat) col_dndx(l,:) = ihillslope_in(g,:) enddo deallocate(ihillslope_in) - + allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='h_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then @@ -321,24 +321,24 @@ subroutine InitHillslope(bounds,fsurdat) call endrun( 'ERROR:: h_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if end if - + do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_slope(l,:) = fhillslope_in(g,:) enddo - + call ncd_io(ncid=ncid, varname='h_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then call endrun( 'ERROR:: h_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if end if - + do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_aspect(l,:) = fhillslope_in(g,:) enddo - + call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -355,12 +355,12 @@ subroutine InitHillslope(bounds,fsurdat) call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if end if - + do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_length(l,:) = fhillslope_in(g,:) enddo - + call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -371,7 +371,7 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) hill_width(l,:) = fhillslope_in(g,:) enddo - + call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (.not. readvar) then if (masterproc) then @@ -384,7 +384,7 @@ subroutine InitHillslope(bounds,fsurdat) enddo deallocate(fhillslope_in) - + allocate(ihillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='h_pftndx', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (readvar) then @@ -400,7 +400,7 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(ihillslope_in) - if (use_hillslope_routing) then + if (use_hillslope_routing) then allocate(fstream_in(bounds%begg:bounds%endg)) call ncd_io(ncid=ncid, varname='h_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then @@ -447,7 +447,7 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(fstream_in) endif - + ! Set hillslope hydrology column level variables ! This needs to match how columns set up in subgridMod do l = bounds%begl,bounds%endl @@ -467,10 +467,10 @@ subroutine InitHillslope(bounds,fsurdat) col%cold(c) = c + (col_dndx(l,ci) - col_ndx(l,ci)) endif enddo - + do c = lun%coli(l), lun%colf(l) ci = c-lun%coli(l)+1 - + col%hillslope_ndx(c) = hill_ndx(l,ci) ! Find uphill neighbors (this may not actually be useful...) @@ -480,10 +480,10 @@ subroutine InitHillslope(bounds,fsurdat) col%colu(c) = i endif enddo - + ! distance of lower edge of column from hillslope bottom col%hill_distance(c) = hill_length(l,ci) - ! width of lower edge of column + ! width of lower edge of column col%hill_width(c) = hill_width(l,ci) ! mean elevation of column relative to gridcell mean elevation col%hill_elev(c) = hill_height(l,ci) @@ -497,7 +497,7 @@ subroutine InitHillslope(bounds,fsurdat) if ( allocated(hill_pftndx) ) then col_pftndx(c) = hill_pftndx(l,ci) endif - + enddo ! Calculate total hillslope area on landunit and @@ -512,8 +512,8 @@ subroutine InitHillslope(bounds,fsurdat) endif enddo - if (use_hillslope_routing) then - + if (use_hillslope_routing) then + ! Total area occupied by each hillslope (m2) is ! grc%area(g)*1.e6*lun%wtgcell(l)*pct_hillslope(l,nh)*0.01 ! Number of representative hillslopes per landunit @@ -530,10 +530,10 @@ subroutine InitHillslope(bounds,fsurdat) + 0.5_r8 * nhill_per_landunit(nh) endif enddo - + ! Calculate steam channel length ! Total length of stream banks is individual widths - ! times number of hillslopes per landunit + ! times number of hillslopes per landunit ! include factor of 0.5 because a channel is shared by ~2 hillslopes lun%stream_channel_length(l) = 0._r8 do c = lun%coli(l), lun%colf(l) @@ -543,7 +543,7 @@ subroutine InitHillslope(bounds,fsurdat) endif enddo endif - + ! if missing hillslope information on surface dataset, ! call endrun if (ncolumns_hillslope(l) > 0 .and. sum(hillslope_area) == 0._r8) then @@ -553,7 +553,7 @@ subroutine InitHillslope(bounds,fsurdat) call endrun( 'ERROR:: sum of hillslope areas is zero.'//errmsg(sourcefile, __LINE__) ) end if endif - + ! Recalculate column weights using input areas ! The higher order weights will be updated in a subsequent reweight_wrapup call do c = lun%coli(l), lun%colf(l) @@ -565,7 +565,7 @@ subroutine InitHillslope(bounds,fsurdat) enddo endif enddo ! end of landunit loop - + deallocate(ncolumns_hillslope,pct_hillslope,hill_ndx,col_ndx,col_dndx, & hill_slope,hill_area,hill_length, & hill_width,hill_height,hill_aspect) @@ -579,22 +579,22 @@ subroutine InitHillslope(bounds,fsurdat) ! Specify different pfts for uplands / lowlands call HillslopeDominantLowlandPft(bounds) else if (pft_distribution_method == pft_lowland_upland) then - ! example usage: + ! example usage: ! upland_ivt = 13 ! c3 non-arctic grass ! lowland_ivt = 7 ! broadleaf deciduous tree call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) endif - + if ( allocated(hill_pftndx) ) then deallocate(hill_pftndx) deallocate(col_pftndx) endif - + ! Update higher order weights and check that weights sum to 1 call compute_higher_order_weights(bounds) - + call ncd_pio_closefile(ncid) - + end subroutine InitHillslope !----------------------------------------------------------------------- @@ -707,14 +707,14 @@ subroutine HillslopeSoilThicknessProfile(bounds,& ! col%nbedrock ! ! !USES: - use LandunitType , only : lun - use GridcellType , only : grc - use ColumnType , only : col + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col use clm_varcon , only : zmin_bedrock, zisoi use clm_varpar , only : nlevsoi use spmdMod , only : masterproc use fileutils , only : getfil - use clm_varcon , only : spval, ispval, grlnd + use clm_varcon , only : spval, ispval, grlnd use ncdio_pio ! @@ -743,7 +743,7 @@ subroutine HillslopeSoilThicknessProfile(bounds,& else soil_depth_lowland = soil_depth_lowland_default endif - + if(present(soil_depth_upland_in)) then soil_depth_upland = soil_depth_upland_in else @@ -754,7 +754,7 @@ subroutine HillslopeSoilThicknessProfile(bounds,& if(soil_profile_method == soil_profile_set_lowland_upland) then do c = bounds%begc,bounds%endc if (col%is_hillslope_column(c) .and. col%active(c)) then - if(col%cold(c) /= ispval) then + if(col%cold(c) /= ispval) then do j = 1,nlevsoi if(zisoi(j-1) > zmin_bedrock) then if (zisoi(j-1) < soil_depth_upland .and. zisoi(j) >= soil_depth_upland) then @@ -762,8 +762,8 @@ subroutine HillslopeSoilThicknessProfile(bounds,& end if end if enddo - else - do j = 1,nlevsoi + else + do j = 1,nlevsoi if(zisoi(j-1) > zmin_bedrock) then if (zisoi(j-1) < soil_depth_lowland .and. zisoi(j) >= soil_depth_lowland) then col%nbedrock(c) = j @@ -786,7 +786,7 @@ subroutine HillslopeSoilThicknessProfile(bounds,& m = 0._r8 endif b = soil_depth_upland - + do c = lun%coli(l), lun%colf(l) if (col%is_hillslope_column(c) .and. col%active(c)) then soil_depth_col = m*(max_hill_dist - col%hill_distance(c)) + b @@ -804,23 +804,23 @@ subroutine HillslopeSoilThicknessProfile(bounds,& call endrun( 'ERROR:: invalid soil_profile_method.'//errmsg(sourcefile, __LINE__) ) end if endif - + end subroutine HillslopeSoilThicknessProfile !------------------------------------------------------------------------ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) ! - ! !DESCRIPTION: + ! !DESCRIPTION: ! Reassign patch type of each column based on whether a column ! is identified as a lowland or an upland. ! Assumes each column has a single pft. - ! In preparation for this reassignment of patch type, only the + ! In preparation for this reassignment of patch type, only the ! first patch was given a non-zero weight in surfrd_hillslope ! ! !USES - use LandunitType , only : lun - use ColumnType , only : col + use LandunitType , only : lun + use ColumnType , only : col use clm_varcon , only : ispval use clm_varpar , only : natpft_lb use PatchType , only : patch @@ -850,7 +850,7 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) endif ! update mxy as is done in initSubgridMod.add_patch patch%mxy(p) = patch%itype(p) + (1 - natpft_lb) - + npatches_per_column = npatches_per_column + 1 enddo if (check_npatches) then @@ -866,7 +866,7 @@ end subroutine HillslopeSetLowlandUplandPfts !------------------------------------------------------------------------ subroutine HillslopeDominantLowlandPft(bounds) ! - ! !DESCRIPTION: + ! !DESCRIPTION: ! Reassign patch weights of each column based on each gridcell's ! two most dominant pfts on the input dataset. ! HillslopeTwoLargestPftIndices is called in surfrd_hillslope to @@ -876,8 +876,8 @@ subroutine HillslopeDominantLowlandPft(bounds) ! ! !USES - use LandunitType , only : lun - use ColumnType , only : col + use LandunitType , only : lun + use ColumnType , only : col use decompMod , only : get_clump_bounds, get_proc_clumps use clm_varcon , only : ispval use PatchType , only : patch @@ -901,7 +901,7 @@ subroutine HillslopeDominantLowlandPft(bounds) if (col%is_hillslope_column(c)) then ! if only one pft exists, find dominant pft index and set 2nd index to the same value - + if (size(patch%wtcol(col%patchi(c):col%patchf(c))) == 1) then call find_k_max_indices(patch%wtcol(col%patchi(c):col%patchf(c)),1,1,max_index) max_indices(1) = max_index(1) + (col%patchi(c) - 1) @@ -918,7 +918,7 @@ subroutine HillslopeDominantLowlandPft(bounds) patch%wtcol(col%patchi(c):col%patchf(c)) = 0._r8 patch%wtlunit(col%patchi(c):col%patchf(c)) = 0._r8 patch%wtgcell(col%patchi(c):col%patchf(c)) = 0._r8 - + ! Put the highest stature vegetation on the lowland column ! non-tree and tree ; place tree on lowland ! grass and shrub ; place shrub on lowland @@ -937,16 +937,16 @@ subroutine HillslopeDominantLowlandPft(bounds) ! if NET/BDT assign BDT to lowland if ((patch%itype(max_indices(1)) == ndllf_evr_tmp_tree) .and. pftcon%is_tree(patch%itype(max_indices(2)))) then - plow = max_indices(2) + plow = max_indices(2) phigh = max_indices(1) endif ! if C3/C4 assign C4 to lowland if ((patch%itype(max_indices(1)) == nc4_grass) .and. (patch%itype(max_indices(2)) == nc3_nonarctic_grass)) then - plow = max_indices(1) + plow = max_indices(1) phigh = max_indices(2) endif if ((patch%itype(max_indices(1)) == nc3_nonarctic_grass) .and. (patch%itype(max_indices(2)) == nc4_grass)) then - plow = max_indices(2) + plow = max_indices(2) phigh = max_indices(1) endif @@ -964,20 +964,20 @@ subroutine HillslopeDominantLowlandPft(bounds) endif enddo ! end loop c deallocate(max_indices) - + end subroutine HillslopeDominantLowlandPft !------------------------------------------------------------------------ subroutine HillslopePftFromFile(bounds,col_pftndx) ! - ! !DESCRIPTION: + ! !DESCRIPTION: ! Reassign patch type using indices from surface data file ! Assumes one patch per hillslope column ! In preparation for this reassignment of patch type, only the ! first patch was given a non-zero weight in surfrd_hillslope. ! ! !USES - use ColumnType , only : col + use ColumnType , only : col use PatchType , only : patch use clm_varpar , only : natpft_lb @@ -990,7 +990,7 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) integer :: p,c ! indices integer :: npatches_per_column logical :: check_npatches = .true. - + !------------------------------------------------------------------------ do c = bounds%begc, bounds%endc @@ -1022,17 +1022,17 @@ subroutine HillslopeStreamOutflow(bounds, & ! Calculate discharge from stream channel ! ! !USES: - use LandunitType , only : lun - use GridcellType , only : grc - use ColumnType , only : col + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col use WaterFluxBulkType , only : waterfluxbulk_type use WaterStateBulkType , only : waterstatebulk_type use spmdMod , only : masterproc - use clm_varcon , only : spval, ispval, grlnd + use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil use ncdio_pio use clm_time_manager , only : get_step_size_real - + ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -1055,7 +1055,7 @@ subroutine HillslopeStreamOutflow(bounds, & character(len=*), parameter :: subname = 'HillslopeStreamOutflow' !----------------------------------------------------------------------- - associate( & + associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun & ! Input: [real(r8) (:) ] stream water discharge (m3/s) ) @@ -1101,7 +1101,7 @@ subroutine HillslopeStreamOutflow(bounds, & call endrun( 'ERROR:: invalid overbank_method.'//errmsg(sourcefile, __LINE__) ) end if endif - + else volumetric_streamflow(l) = cross_sectional_area * flow_velocity endif @@ -1122,7 +1122,7 @@ subroutine HillslopeStreamOutflow(bounds, & end associate end subroutine HillslopeStreamOutflow - + !----------------------------------------------------------------------- subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & waterfluxbulk_inst,waterdiagnosticbulk_inst) @@ -1131,14 +1131,14 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & ! Calculate discharge from stream channel ! ! !USES: - use LandunitType , only : lun - use GridcellType , only : grc - use ColumnType , only : col + use LandunitType , only : lun + use GridcellType , only : grc + use ColumnType , only : col use WaterFluxBulkType , only : waterfluxbulk_type use WaterStateBulkType , only : waterstatebulk_type use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type use spmdMod , only : masterproc - use clm_varcon , only : spval, ispval, grlnd + use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil use clm_time_manager, only : get_step_size_real @@ -1148,7 +1148,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst type(waterdiagnosticbulk_type), intent(out) :: waterdiagnosticbulk_inst - + integer :: c, l, g, i, j real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) real(r8) :: qflx_drain_perched_vol ! volumetric perched saturated drainage (m3/s) @@ -1158,7 +1158,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & character(len=*), parameter :: subname = 'HillslopeUpdateStreamWater' !----------------------------------------------------------------------- - associate( & + associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun, & ! Input/Output: [real(r8) (:) ] stream water volume (m3) volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) qflx_drain => waterfluxbulk_inst%qflx_drain_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) @@ -1175,7 +1175,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & g = lun%gridcell(l) ! the drainage terms are 'net' quantities, so summing over ! all columns in a hillslope is equivalent to the outflow - ! from the lowland column + ! from the lowland column do c = lun%coli(l), lun%colf(l) if (col%is_hillslope_column(c) .and. col%active(c)) then qflx_surf_vol = qflx_surf(c)*1.e-3_r8 & @@ -1192,7 +1192,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & enddo stream_water_volume(l) = stream_water_volume(l) & - volumetric_streamflow(l) * dtime - + ! account for negative drainage (via searchforwater in soilhydrology) if(stream_water_volume(l) < 0._r8) then volumetric_streamflow(l) = volumetric_streamflow(l) + stream_water_volume(l)/dtime @@ -1205,9 +1205,9 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & endif enddo - + end associate end subroutine HillslopeUpdateStreamWater - + end module HillslopeHydrologyMod diff --git a/src/biogeophys/SoilHydrologyMod.F90 b/src/biogeophys/SoilHydrologyMod.F90 index f2b2861cff..2e10c49ca3 100644 --- a/src/biogeophys/SoilHydrologyMod.F90 +++ b/src/biogeophys/SoilHydrologyMod.F90 @@ -1615,7 +1615,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & associate( & dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) - zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) + zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) t_soisno => temperature_inst%t_soisno_col , & ! Input: [real(r8) (:,:) ] soil temperature (Kelvin) h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Output: [real(r8) (:,:) ] liquid water (kg/m2) @@ -1633,14 +1633,14 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! define frost table as first frozen layer with unfrozen layer above it if(t_soisno(c,1) > tfrz) then - k_frz = nlevsoi + k_frz=nlevsoi else - k_frz = 1 + k_frz=1 endif - do k=2,nlevsoi + do k=2, nlevsoi if (t_soisno(c,k-1) > tfrz .and. t_soisno(c,k) <= tfrz) then - k_frz = k + k_frz=k exit endif enddo @@ -1660,7 +1660,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! frost table sat_lev is an arbitrary saturation level ! used to determine perched water table - k_perch=1 + k_perch = 1 do k=k_frz,1,-1 h2osoi_vol(c,k) = h2osoi_liq(c,k)/(dz(c,k)*denh2o) & + h2osoi_ice(c,k)/(dz(c,k)*denice) @@ -1673,7 +1673,7 @@ subroutine PerchedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! if frost_table = nlevsoi, check temperature of layer, ! and only compute perched water table if frozen - if (t_soisno(c,k_frz) > tfrz) k_perch = k_frz + if (t_soisno(c,k_frz) > tfrz) k_perch=k_frz ! if perched water table exists above frost table, ! interpolate between k_perch and k_perch+1 to find @@ -1748,7 +1748,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & real(r8) :: qflx_drain_perched_out(bounds%begc:bounds%endc) ! lateral subsurface flow through active layer [mm/s] associate( & - nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) + nbedrock => col%nbedrock , & ! Input: [real(r8) (:,:) ] depth to bedrock (m) z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) zi => col%zi , & ! Input: [real(r8) (:,:) ] interface level below a "z" level (m) dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m) @@ -1775,21 +1775,21 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & dtime = get_step_size_real() - ! locate frost table and perched water table + ! locate frost table and perched water table do fc = 1, num_hydrologyc c = filter_hydrologyc(fc) k_frost(c) = nbedrock(c) k_perch(c) = nbedrock(c) - do k=1,nbedrock(c) + do k = 1,nbedrock(c) if (frost_table(c) >= zi(c,k-1) .and. frost_table(c) < zi(c,k)) then - k_frost(c)=k + k_frost(c) = k exit endif enddo - - do k=1,nbedrock(c) + + do k = 1,nbedrock(c) if (zwt_perched(c) >= zi(c,k-1) .and. zwt_perched(c) < zi(c,k)) then - k_perch(c)=k + k_perch(c) = k exit endif enddo @@ -1806,7 +1806,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & if (frost_table(c) > zwt_perched(c)) then ! Hillslope columns - if (col%is_hillslope_column(c) .and. col%active(c)) then + if (col%is_hillslope_column(c) .and. col%active(c)) then ! calculate head gradient @@ -1820,7 +1820,7 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & - (col%hill_elev(col%cold(c))-zwt_perched(col%cold(c))) head_gradient = head_gradient / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else - if(use_hillslope_routing) then + if (use_hillslope_routing) then stream_water_depth = stream_water_volume(l) & /lun%stream_channel_length(l)/lun%stream_channel_width(l) stream_channel_depth = lun%stream_channel_depth(l) @@ -1977,8 +1977,8 @@ subroutine PerchedLateralFlow(bounds, num_hydrologyc, & enddo - ! if drainage_tot is greater than available water - ! (above frost table), then decrease qflx_drain_perched + ! if drainage_tot is greater than available water + ! (above frost table), then decrease qflx_drain_perched ! by residual amount for water balance qflx_drain_perched(c) = qflx_drain_perched(c) - drainage_tot/dtime enddo @@ -2044,7 +2044,7 @@ subroutine ThetaBasedWaterTable(bounds, num_hydrologyc, filter_hydrologyc, & ! locate water table from bottom up starting at bottom of soil column ! sat_lev is an arbitrary saturation level used to determine water table - sat_lev = 0.9 + sat_lev=0.9 k_zwt=nbedrock(c) sat_flag=1 !will remain unchanged if all layers at saturation @@ -2263,7 +2263,7 @@ subroutine SubsurfaceLateralFlow(bounds, & - (col%hill_elev(col%cold(c))-zwt(col%cold(c))) head_gradient = head_gradient / (col%hill_distance(c) - col%hill_distance(col%cold(c))) else - if(use_hillslope_routing) then + if (use_hillslope_routing) then stream_water_depth = stream_water_volume(l) & /lun%stream_channel_length(l)/lun%stream_channel_width(l) stream_channel_depth = lun%stream_channel_depth(l) diff --git a/src/biogeophys/SurfaceRadiationMod.F90 b/src/biogeophys/SurfaceRadiationMod.F90 index 10d0db94ae..1aa9545b7d 100644 --- a/src/biogeophys/SurfaceRadiationMod.F90 +++ b/src/biogeophys/SurfaceRadiationMod.F90 @@ -536,8 +536,8 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & associate( & snl => col%snl , & ! Input: [integer (:) ] negative number of snow layers [nbr] - forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col , & ! Input: [real(r8) (:,:) ] direct beam radiation, column (W/m**2) - forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (W/m**2) + forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col , & ! Input: [real(r8) (:,:) ] direct beam radiation, column (W/m**2) + forc_solai => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:,:) ] diffuse radiation (W/m**2) snow_depth => waterdiagnosticbulk_inst%snow_depth_col , & ! Input: [real(r8) (:) ] snow height (m) frac_sno => waterdiagnosticbulk_inst%frac_sno_col , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1) @@ -985,7 +985,7 @@ subroutine SurfaceRadiation(bounds, num_nourbanp, filter_nourbanp, & ! Solar incident fsds_vis_d(p) = forc_solad_col(c,1) - fsds_nir_d(p) = forc_solad_col(c,2) + fsds_nir_d(p) = forc_solad_col(c,2) fsds_vis_i(p) = forc_solai(g,1) fsds_nir_i(p) = forc_solai(g,2) diff --git a/src/biogeophys/WaterFluxType.F90 b/src/biogeophys/WaterFluxType.F90 index 8b2c4279ed..23980a21c9 100644 --- a/src/biogeophys/WaterFluxType.F90 +++ b/src/biogeophys/WaterFluxType.F90 @@ -72,8 +72,8 @@ module WaterFluxType real(r8), pointer :: qflx_infl_col (:) ! col infiltration (mm H2O /s) real(r8), pointer :: qflx_surf_col (:) ! col total surface runoff (mm H2O /s) real(r8), pointer :: qflx_drain_col (:) ! col sub-surface runoff (mm H2O /s) - real(r8), pointer :: qflx_latflow_in_col (:) ! col hillslope lateral flow input (mm/s) - real(r8), pointer :: qflx_latflow_out_col (:) ! col hillslope lateral flow output (mm/s) + real(r8), pointer :: qflx_latflow_in_col (:) ! col hillslope lateral flow input (mm/s) + real(r8), pointer :: qflx_latflow_out_col (:) ! col hillslope lateral flow output (mm/s) real(r8), pointer :: volumetric_discharge_col (:) ! col hillslope discharge (m3/s) real(r8), pointer :: volumetric_streamflow_lun(:) ! lun stream discharge (m3/s) real(r8), pointer :: qflx_drain_perched_col (:) ! col sub-surface runoff from perched wt (mm H2O /s) diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 67dc944ea3..6c24e8f41f 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -184,8 +184,7 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) ! !USES: use histFileMod , only : hist_addfld1d, hist_addfld2d, no_snow_normal use clm_varctl , only : use_soil_moisture_streams - use GridcellType , only : grc - + use GridcellType , only : grc ! ! !ARGUMENTS: class(waterstate_type), intent(in) :: this diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 518bdc329e..b90b1767a3 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -907,8 +907,8 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & ! subsurface runoff is the sum of qflx_drain and qflx_perched_drain do g = begg, endg data1d(g) = waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(g) + & - waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(g) - if(use_hillslope_routing) then + waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(g) + if (use_hillslope_routing) then data1d(g) = data1d(g) + & waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(g) endif diff --git a/src/main/ColumnType.F90 b/src/main/ColumnType.F90 index 7461032cad..ab7ee8e261 100644 --- a/src/main/ColumnType.F90 +++ b/src/main/ColumnType.F90 @@ -142,16 +142,16 @@ subroutine Init(this, begc, endc) allocate(this%lakedepth (begc:endc)) ; this%lakedepth (:) = spval allocate(this%dz_lake (begc:endc,nlevlak)) ; this%dz_lake (:,:) = nan allocate(this%z_lake (begc:endc,nlevlak)) ; this%z_lake (:,:) = nan - allocate(this%col_ndx (begc:endc)) ; this%col_ndx(:) = ispval - allocate(this%colu (begc:endc)) ; this%colu (:) = ispval - allocate(this%cold (begc:endc)) ; this%cold (:) = ispval - allocate(this%hillslope_ndx(begc:endc)) ; this%hillslope_ndx (:) = ispval - allocate(this%hill_elev(begc:endc)) ; this%hill_elev (:) = spval - allocate(this%hill_slope(begc:endc)) ; this%hill_slope (:) = spval - allocate(this%hill_area(begc:endc)) ; this%hill_area (:) = spval - allocate(this%hill_width(begc:endc)) ; this%hill_width (:) = spval - allocate(this%hill_distance(begc:endc)) ; this%hill_distance (:) = spval - allocate(this%hill_aspect(begc:endc)) ; this%hill_aspect (:) = spval + allocate(this%col_ndx (begc:endc)) ; this%col_ndx(:) = ispval + allocate(this%colu (begc:endc)) ; this%colu (:) = ispval + allocate(this%cold (begc:endc)) ; this%cold (:) = ispval + allocate(this%hillslope_ndx(begc:endc)) ; this%hillslope_ndx (:) = ispval + allocate(this%hill_elev(begc:endc)) ; this%hill_elev (:) = spval + allocate(this%hill_slope(begc:endc)) ; this%hill_slope (:) = spval + allocate(this%hill_area(begc:endc)) ; this%hill_area (:) = spval + allocate(this%hill_width(begc:endc)) ; this%hill_width (:) = spval + allocate(this%hill_distance(begc:endc)) ; this%hill_distance (:) = spval + allocate(this%hill_aspect(begc:endc)) ; this%hill_aspect (:) = spval allocate(this%nbedrock (begc:endc)) ; this%nbedrock (:) = ispval allocate(this%levgrnd_class(begc:endc,nlevmaxurbgrnd)) ; this%levgrnd_class(:,:) = ispval allocate(this%micro_sigma (begc:endc)) ; this%micro_sigma (:) = nan diff --git a/src/main/atm2lndMod.F90 b/src/main/atm2lndMod.F90 index b35c6ae865..5da4ff6333 100644 --- a/src/main/atm2lndMod.F90 +++ b/src/main/atm2lndMod.F90 @@ -267,7 +267,7 @@ subroutine downscale_forcings(bounds, & end do ! adjust hillslope precpitation before repartitioning rain/snow - if(use_hillslope .and. downscale_hillslope_meteorology) then + if (use_hillslope .and. downscale_hillslope_meteorology) then call downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) call downscale_hillslope_precipitation(bounds, topo_inst, atm2lnd_inst, wateratm2lndbulk_inst) endif @@ -749,7 +749,7 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) use clm_varpar , only : numrad ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds + type(bounds_type) , intent(in) :: bounds type(surfalb_type) , intent(in) :: surfalb_inst type(atm2lnd_type) , intent(inout) :: atm2lnd_inst ! @@ -764,19 +764,19 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) character(len=*), parameter :: subname = 'downscale_hillslope_solar' !----------------------------------------------------------------------- - + associate(& ! Gridcell-level fields: forc_solai_grc => atm2lnd_inst%forc_solai_grc , & ! Input: [real(r8) (:)] gridcell indirect incoming solar radiation forc_solad_grc => atm2lnd_inst%forc_solad_not_downscaled_grc , & ! Input: [real(r8) (:)] gridcell direct incoming solar radiation - coszen_grc => surfalb_inst%coszen_grc , & ! Input: [real(r8) (:)] cosine of solar zenith angle - + coszen_grc => surfalb_inst%coszen_grc , & ! Input: [real(r8) (:)] cosine of solar zenith angle + ! Column-level fields: - coszen_col => surfalb_inst%coszen_col , & ! Input: [real(r8) (:)] cosine of solar zenith angle + coszen_col => surfalb_inst%coszen_col , & ! Input: [real(r8) (:)] cosine of solar zenith angle forc_solar_col => atm2lnd_inst%forc_solar_downscaled_col , & ! Output: [real(r8) (:)] column total incoming solar radiation forc_solad_col => atm2lnd_inst%forc_solad_downscaled_col & ! Output: [real(r8) (:)] column direct incoming solar radiation ) - + ! Initialize column forcing sum_solar(bounds%begg:bounds%endg,1:numrad) = 0._r8 sum_wtgcell(bounds%begg:bounds%endg) = 0._r8 @@ -790,19 +790,19 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) illum_frac(g) = illum_frac(g) + col%wtgcell(c) endif endif - + sum_solar(g,1:numrad) = sum_solar(g,1:numrad) + col%wtgcell(c)*forc_solad_col(c,1:numrad) sum_wtgcell(g) = sum_wtgcell(g) + col%wtgcell(c) end if end do - + ! Calculate illuminated fraction of gridcell do g = bounds%begg,bounds%endg if (sum_wtgcell(g) > 0._r8) then illum_frac(g) = illum_frac(g)/sum_wtgcell(g) endif enddo - + ! Normalize column level solar do c = bounds%begc,bounds%endc if (col%is_hillslope_column(c) .and. col%active(c)) then @@ -818,7 +818,7 @@ subroutine downscale_hillslope_solar(bounds, atm2lnd_inst, surfalb_inst) enddo forc_solar_col(c) = sum(forc_solad_col(c,1:numrad))+sum(forc_solai_grc(g,1:numrad)) end if - + end do ! check conservation @@ -867,7 +867,7 @@ subroutine downscale_hillslope_precipitation(bounds, & use clm_varcon , only : rair, cpair, grav ! ! !ARGUMENTS: - type(bounds_type) , intent(in) :: bounds + type(bounds_type) , intent(in) :: bounds class(topo_type) , intent(in) :: topo_inst type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(wateratm2lndbulk_type) , intent(inout) :: wateratm2lndbulk_inst @@ -890,15 +890,15 @@ subroutine downscale_hillslope_precipitation(bounds, & ! Gridcell-level metadata: forc_topo_g => atm2lnd_inst%forc_topo_grc , & ! Input: [real(r8) (:)] atmospheric surface height (m) forc_rain_g => wateratm2lndbulk_inst%forc_rain_not_downscaled_grc , & ! Input: [real(r8) (:)] rain rate [mm/s] - forc_snow_g => wateratm2lndbulk_inst%forc_snow_not_downscaled_grc , & ! Input: [real(r8) (:)] snow rate [mm/s] + forc_snow_g => wateratm2lndbulk_inst%forc_snow_not_downscaled_grc , & ! Input: [real(r8) (:)] snow rate [mm/s] ! Column-level metadata: topo_c => topo_inst%topo_col , & ! Input: [real(r8) (:)] column surface height (m) - + ! Column-level downscaled fields: forc_rain_c => wateratm2lndbulk_inst%forc_rain_downscaled_col , & ! Output: [real(r8) (:)] rain rate [mm/s] forc_snow_c => wateratm2lndbulk_inst%forc_snow_downscaled_col & ! Output: [real(r8) (:)] snow rate [mm/s] ) - + ! Redistribute precipitation based on departure ! of column elevation from mean elevation @@ -938,16 +938,16 @@ subroutine downscale_hillslope_precipitation(bounds, & endif enddo - ! Normalize column precipitation to conserve gridcell average + ! Normalize column precipitation to conserve gridcell average do c = bounds%begc,bounds%endc g = col%gridcell(c) if (col%is_hillslope_column(c) .and. col%active(c)) then - if (norm_rain(g) > 0._r8) then + if (norm_rain(g) > 0._r8) then forc_rain_c(c) = forc_rain_c(c) * forc_rain_g(g) / norm_rain(g) else forc_rain_c(c) = forc_rain_g(g) endif - if (norm_snow(g) > 0._r8) then + if (norm_snow(g) > 0._r8) then forc_snow_c(c) = forc_snow_c(c) * forc_snow_g(g) / norm_snow(g) else forc_snow_c(c) = forc_snow_g(g) @@ -978,7 +978,7 @@ subroutine downscale_hillslope_precipitation(bounds, & endif enddo endif - + end associate end subroutine downscale_hillslope_precipitation diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 722eba5ab7..92b8cee0a4 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -1085,12 +1085,12 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro call t_startf('hydro2_drainage') - call HydrologyDrainage(bounds_clump, & + call HydrologyDrainage(bounds_clump, & filter(nc)%num_nolakec, filter(nc)%nolakec, & filter(nc)%num_hydrologyc, filter(nc)%hydrologyc, & filter(nc)%num_urbanc, filter(nc)%urbanc, & filter(nc)%num_do_smb_c, filter(nc)%do_smb_c, & - glc2lnd_inst, temperature_inst, & + glc2lnd_inst, temperature_inst, & soilhydrology_inst, soilstate_inst, water_inst%waterstatebulk_inst, & water_inst%waterdiagnosticbulk_inst, water_inst%waterbalancebulk_inst, & water_inst%waterfluxbulk_inst, water_inst%wateratm2lndbulk_inst, & diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index daf1011cab..b35b7f9279 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -67,7 +67,6 @@ subroutine initialize1(dtime) use SoilBiogeochemDecompCascadeConType , only : decomp_cascade_par_init use CropReprPoolsMod , only: crop_repr_pools_init use HillslopeHydrologyMod, only: hillslope_properties_init - ! ! !ARGUMENTS integer, intent(in) :: dtime ! model time step (seconds) @@ -118,7 +117,7 @@ subroutine initialize1(dtime) call dynSubgridControl_init(NLFilename) call crop_repr_pools_init() call hillslope_properties_init(NLFilename) - + call t_stopf('clm_init1') end subroutine initialize1 @@ -181,7 +180,6 @@ subroutine initialize2(ni,nj) use NutrientCompetitionFactoryMod , only : create_nutrient_competition_method use FATESFireFactoryMod , only : scalar_lightning use HillslopeHydrologyMod , only : InitHillslope - ! ! !ARGUMENTS integer, intent(in) :: ni, nj ! global grid sizes @@ -242,7 +240,7 @@ subroutine initialize2(ni,nj) allocate (wt_glc_mec (begg:endg, maxpatch_glc )) allocate (topo_glc_mec (begg:endg, maxpatch_glc )) allocate (haslake (begg:endg )) - if(use_hillslope) then + if (use_hillslope) then allocate (ncolumns_hillslope (begg:endg )) endif allocate (pct_urban_max(begg:endg, numurbl )) @@ -302,7 +300,7 @@ subroutine initialize2(ni,nj) ! Set global seg maps for gridcells, landlunits, columns and patches call decompInit_glcp(ni, nj, glc_behavior) - if(use_hillslope) then + if (use_hillslope) then ! Initialize hillslope properties call InitHillslope(bounds_proc, fsurdat) endif @@ -332,7 +330,7 @@ subroutine initialize2(ni,nj) ! end of the run for error checking, pct_urban_max is kept through the end of the run ! for reweighting in subgridWeights. deallocate (wt_lunit, wt_cft, wt_glc_mec, haslake) - if(use_hillslope) deallocate (ncolumns_hillslope) + if (use_hillslope) deallocate (ncolumns_hillslope) ! Determine processor bounds and clumps for this processor call get_proc_bounds(bounds_proc) diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index 7f2e3c1d18..43390ca8b7 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -200,11 +200,9 @@ subroutine clm_instInit(bounds) use SoilWaterRetentionCurveFactoryMod , only : create_soil_water_retention_curve use decompMod , only : get_proc_bounds use BalanceCheckMod , only : GetBalanceCheckSkipSteps - use clm_varctl , only : use_hillslope use HillslopeHydrologyMod , only : SetHillslopeSoilThickness use initVerticalMod , only : setSoilLayerClass - ! ! !ARGUMENTS type(bounds_type), intent(in) :: bounds ! processor bounds @@ -274,7 +272,7 @@ subroutine clm_instInit(bounds) urbanparams_inst%thick_roof(begl:endl)) ! Set hillslope column bedrock values - if(use_hillslope) then + if (use_hillslope) then call SetHillslopeSoilThickness(bounds,fsurdat, & soil_depth_lowland_in=8.5_r8,& soil_depth_upland_in =2.0_r8) diff --git a/src/main/clm_varsur.F90 b/src/main/clm_varsur.F90 index dfb9357482..c49c8bb052 100644 --- a/src/main/clm_varsur.F90 +++ b/src/main/clm_varsur.F90 @@ -50,7 +50,7 @@ module clm_instur logical , pointer :: haslake(:) ! subgrid hillslope hydrology constituents - integer, pointer :: ncolumns_hillslope(:) + integer, pointer :: ncolumns_hillslope(:) ! whether we have urban to initialize in each grid cell ! (second dimension goes 1:numurbl) diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 69129706f9..d3d69bc455 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -45,7 +45,7 @@ module controlMod use SoilBiogeochemLittVertTranspMod , only: som_adv_flux, max_depth_cryoturb use SoilBiogeochemVerticalProfileMod , only: surfprof_exp use SoilBiogeochemNitrifDenitrifMod , only: no_frozen_nitrif_denitrif - use SoilHydrologyMod , only: soilHydReadNML,hillslope_hydrology_ReadNML + use SoilHydrologyMod , only: soilHydReadNML, hillslope_hydrology_ReadNML use CNFireFactoryMod , only: CNFireReadNML use CanopyFluxesMod , only: CanopyFluxesReadNML use shr_drydep_mod , only: n_drydep diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 19591710b2..0c473d86ff 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -3134,7 +3134,7 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(varname='levdcmp', xtype=tape(t)%ncprec, dim1name='levdcmp', & long_name='coordinate levels for soil decomposition variables', units='m', ncid=nfid(t)) - if(use_hillslope .and. .not.tape(t)%dov2xy)then + if (use_hillslope .and. .not.tape(t)%dov2xy)then call ncd_defvar(varname='hslp_distance', xtype=ncd_double, & dim1name=namec, long_name='hillslope column distance', & units='m', ncid=nfid(t)) @@ -3251,7 +3251,7 @@ subroutine htape_timeconst(t, mode) call ncd_io(varname='levdcmp', data=zsoi_1d, ncid=nfid(t), flag='write') end if - if (use_hillslope .and. .not.tape(t)%dov2xy) then + if (use_hillslope .and. .not.tape(t)%dov2xy) then call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') diff --git a/src/main/initGridCellsMod.F90 b/src/main/initGridCellsMod.F90 index 987611f5fc..44bc9361b2 100644 --- a/src/main/initGridCellsMod.F90 +++ b/src/main/initGridCellsMod.F90 @@ -11,7 +11,7 @@ module initGridCellsMod ! these modules (or the two modules should be combined into one). ! ! !USES: -#include "shr_assert.h" +#include "shr_assert.h" use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg use spmdMod , only : masterproc,iam @@ -216,7 +216,7 @@ subroutine set_landunit_veg_compete (ltype, gi, li, ci, pi) integer , intent(inout) :: pi ! patch index ! ! !LOCAL VARIABLES: - integer :: m,ci2 ! index + integer :: m, ci2 ! index integer :: npatches ! number of patches in landunit integer :: ncols integer :: nlunits diff --git a/src/main/initVerticalMod.F90 b/src/main/initVerticalMod.F90 index 92788a4609..e88c4e1a18 100644 --- a/src/main/initVerticalMod.F90 +++ b/src/main/initVerticalMod.F90 @@ -145,7 +145,7 @@ subroutine setSoilLayerClass(bounds) end do end subroutine setSoilLayerClass - + !------------------------------------------------------------------------ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) use clm_varcon , only : zmin_bedrock @@ -730,7 +730,6 @@ subroutine initVertical(bounds, glc_behavior, thick_wall, thick_roof) slope0 = params_inst%slopemax**(1._r8/params_inst%slopebeta) if (col%is_hillslope_column(c)) then - col%micro_sigma(c) = (atan(col%hill_slope(c)) + slope0)**(params_inst%slopebeta) else col%micro_sigma(c) = (col%topo_slope(c) + slope0)**(params_inst%slopebeta) diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index 5d1b1086b3..1cda0cff91 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -340,7 +340,7 @@ subroutine lnd2atm(bounds, & ! lnd -> rof !---------------------------------------------------- - if(use_hillslope_routing) then + if (use_hillslope_routing) then ! streamflow is volume/time, so sum over landunits (do not weight) water_inst%waterlnd2atmbulk_inst%qflx_rofliq_stream_grc(bounds%begg:bounds%endg) = 0._r8 do l = bounds%begl, bounds%endl @@ -451,7 +451,7 @@ subroutine lnd2atm(bounds, & water_inst%waterlnd2atmbulk_inst%qflx_rofliq_grc(g) - & water_inst%waterfluxbulk_inst%qflx_liq_dynbal_grc(g) enddo - + call c2g( bounds, & water_inst%waterfluxbulk_inst%qflx_sfc_irrig_col (bounds%begc:bounds%endc), & water_inst%waterlnd2atmbulk_inst%qirrig_grc(bounds%begg:bounds%endg), & diff --git a/src/main/subgridMod.F90 b/src/main/subgridMod.F90 index 2116d9c5d8..4118ac73ed 100644 --- a/src/main/subgridMod.F90 +++ b/src/main/subgridMod.F90 @@ -162,7 +162,7 @@ subroutine subgrid_get_info_natveg(gi, npatches, ncols, nlunits) if (npatches > 0) then nlunits = 1 - if(use_hillslope) then + if (use_hillslope) then ! ensure ncols is > 0 ncols = max(ncolumns_hillslope(gi),1) else diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 3935b170d6..ddf8bbdc08 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -816,7 +816,7 @@ subroutine surfrd_veg_all(begg, endg, ncid, ns, actual_numcft) end if ! Obtain hillslope hydrology information and modify pft weights - if(use_hillslope) then + if (use_hillslope) then call surfrd_hillslope(begg, endg, ncid, ns) endif @@ -900,7 +900,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) use pftconMod , only : noveg use HillslopeHydrologyMod, only : pft_distribution_method, pft_from_file, pft_uniform_dominant_pft, pft_lowland_dominant_pft, pft_lowland_upland use array_utils, only: find_k_max_indices - + ! ! !ARGUMENTS: integer, intent(in) :: begg, endg @@ -910,7 +910,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! !LOCAL VARIABLES: integer :: g, nh, m, n ! index integer :: dimid,varid ! netCDF id's - integer :: ier ! error status + integer :: ier ! error status integer, allocatable :: max_indices(:) ! largest weight pft indices logical :: readvar ! is variable on dataset integer,pointer :: arrayl(:) ! local array (needed because ncd_io expects a pointer) @@ -918,7 +918,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) !----------------------------------------------------------------------- ! number of hillslopes per landunit - call ncd_inqdid(ncid,'nhillslope',dimid,readvar) + call ncd_inqdid(ncid,'nhillslope',dimid,readvar) if (.not. readvar) then call endrun( msg=' ERROR: nhillslope not on surface data file'//errMsg(sourcefile, __LINE__)) else @@ -926,7 +926,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) nhillslope = nh endif ! maximum number of columns per landunit - call ncd_inqdid(ncid,'nmaxhillcol',dimid,readvar) + call ncd_inqdid(ncid,'nmaxhillcol',dimid,readvar) if (.not. readvar) then call endrun( msg=' ERROR: nmaxhillcol not on surface data file'//errMsg(sourcefile, __LINE__)) else @@ -972,7 +972,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) call find_k_max_indices(wt_nat_patch(g,:),natpft_lb,1,max_indices) wt_nat_patch(g,:) = 0._r8 wt_nat_patch(g,max_indices(1)) = 100._r8 - + endif enddo deallocate(max_indices) @@ -985,7 +985,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) do g = begg, endg ! If hillslopes will be used in a gridcell, modify wt_nat_patch, otherwise use original patch distribution if(ncolumns_hillslope(g) > 0) then - + ! Preserve the relative weights of the largest and ! next largest weights using arbitrarily chosen values ! (i.e. 1 should be larger than 2) that sum to 100. @@ -1003,7 +1003,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) wt_nat_patch(g,:) = 0._r8 wt_nat_patch(g,max_indices(1)) = 100._r8 endif - + endif enddo deallocate(max_indices) From c7c8130c956705dcfcad9cde3f19a889e7673f31 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 1 Dec 2023 13:44:10 -0700 Subject: [PATCH 116/153] Remove a commented-out bit. --- src/biogeophys/SoilWaterMovementMod.F90 | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/biogeophys/SoilWaterMovementMod.F90 b/src/biogeophys/SoilWaterMovementMod.F90 index 8b6f953918..85bcf42c5e 100644 --- a/src/biogeophys/SoilWaterMovementMod.F90 +++ b/src/biogeophys/SoilWaterMovementMod.F90 @@ -1395,13 +1395,6 @@ subroutine soilwater_moisture_form(bounds, num_hydrologyc, & ! save number of adaptive substeps used during time step nsubsteps(c) = nsubstep -!!$ ! check for over-saturated layers -!!$ do j = nlayers,2,-1 -!!$ over_saturation = max(h2osoi_liq(c,j)-(watsat(c,j)*m_to_mm*dz(c,j)),0._r8) -!!$ h2osoi_liq(c,j) = min(watsat(c,j)*m_to_mm*dz(c,j), h2osoi_liq(c,j)) -!!$ h2osoi_liq(c,j-1) = h2osoi_liq(c,j-1) + over_saturation -!!$ end do - ! check for negative moisture values do j = 2, nlayers if(h2osoi_liq(c,j) < -1e-6_r8) then From 55124be74d4b81dc0b25f3615e2506fce5312fc8 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 4 Dec 2023 15:29:10 -0700 Subject: [PATCH 117/153] Use DIN_LOC_ROOT in Hillslope test. --- .../testdefs/testmods_dirs/clm/Hillslope/shell_commands | 3 ++- cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands index 56318395d1..6f3602d2e6 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands @@ -1,3 +1,4 @@ ./xmlchange CLM_BLDNML_OPTS="-bgc sp" -meshfile=/glade/work/samrabin/hillslope_inputs/ESMFmesh_10x15_synthetic_cosphill_1.0.nc +DIN_LOC_ROOT=$(./xmlquery --value DIN_LOC_ROOT) +meshfile=$DIN_LOC_ROOT/lnd/clm2/testdata/ESMFmesh_10x15_synthetic_cosphill_1.0.nc ./xmlchange ATM_DOMAIN_MESH=${meshfile},LND_DOMAIN_MESH=${meshfile} diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm index 069edfddbd..70970216a1 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -1,4 +1,4 @@ -fsurdat = '/glade/p/cesmdata/cseg/inputdata/lnd/clm2/surfdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.0.nc' +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.0.nc' use_hillslope = .true. use_hillslope_routing = .true. hillslope_pft_distribution_method = 'PftLowlandUpland' From ce9ed806acd2959afd8a37a8313d11fbd6283b5e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 4 Dec 2023 16:12:23 -0700 Subject: [PATCH 118/153] More whitespace fixes/reversions. --- src/biogeophys/BalanceCheckMod.F90 | 11 ++++++----- src/biogeophys/HillslopeHydrologyMod.F90 | 8 -------- src/biogeophys/HydrologyDrainageMod.F90 | 13 ++++--------- src/biogeophys/HydrologyNoDrainageMod.F90 | 6 ++---- src/biogeophys/IrrigationMod.F90 | 1 - 5 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/biogeophys/BalanceCheckMod.F90 b/src/biogeophys/BalanceCheckMod.F90 index 8e761b5d08..b3efe6e525 100644 --- a/src/biogeophys/BalanceCheckMod.F90 +++ b/src/biogeophys/BalanceCheckMod.F90 @@ -36,7 +36,6 @@ module BalanceCheckMod use column_varcon , only : icol_roof, icol_sunwall, icol_shadewall use column_varcon , only : icol_road_perv, icol_road_imperv use clm_varctl , only : use_hillslope_routing - ! ! !PUBLIC TYPES: implicit none @@ -217,7 +216,7 @@ subroutine WaterGridcellBalanceSingle(bounds, & ! ! !USES: use subgridAveMod, only: c2g - use LandunitType , only : lun + use LandunitType , only : lun ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -561,7 +560,7 @@ subroutine BalanceCheck( bounds, & qflx_qrgwl_grc => waterlnd2atm_inst%qflx_rofliq_qgwl_grc , & ! Input: [real(r8) (:) ] grid cell-level qflx_surf at glaciers, wetlands, lakes qflx_drain_col => waterflux_inst%qflx_drain_col , & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) qflx_drain_grc => waterlnd2atm_inst%qflx_rofliq_qsub_grc , & ! Input: [real(r8) (:) ] grid cell-level drainage (mm H20 /s) - qflx_streamflow_grc => waterlnd2atm_inst%qflx_rofliq_stream_grc, & ! Input: [real(r8) (:) ] streamflow [mm H2O/s] + qflx_streamflow_grc => waterlnd2atm_inst%qflx_rofliq_stream_grc, & ! Input: [real(r8) (:) ] streamflow [mm H2O/s] qflx_ice_runoff_col => waterlnd2atm_inst%qflx_ice_runoff_col , & ! Input: [real(r8) (:) ] column level solid runoff from snow capping and from excess ice in soil (mm H2O /s) qflx_ice_runoff_grc => waterlnd2atm_inst%qflx_rofice_grc , & ! Input: [real(r8) (:) ] grid cell-level solid runoff from snow capping and from excess ice in soil (mm H2O /s) qflx_sl_top_soil => waterflux_inst%qflx_sl_top_soil_col , & ! Input: [real(r8) (:) ] liquid water + ice from layer above soil to top soil layer or sent to qflx_qrgwl (mm H2O/s) @@ -651,6 +650,7 @@ subroutine BalanceCheck( bounds, & - qflx_ice_runoff_col(c) & - qflx_snwcp_discarded_liq_col(c) & - qflx_snwcp_discarded_ice_col(c)) * dtime + else errh2o_col(c) = 0.0_r8 @@ -670,7 +670,7 @@ subroutine BalanceCheck( bounds, & ' local indexc= ',indexc,& ' global indexc= ',global_index, & ' errh2o= ',errh2o_col(indexc) - if ((errh2o_max_val > error_thresh) .and. (DAnstep > skip_steps)) then + if ((errh2o_max_val > error_thresh) .and. (DAnstep > skip_steps)) then write(iulog,*)'CTSM is stopping because errh2o > ', error_thresh, ' mm' write(iulog,*)'nstep = ',nstep @@ -754,6 +754,7 @@ subroutine BalanceCheck( bounds, & ! BUG(rgk, 2021-04-13, ESCOMP/CTSM#1314) Temporarily bypassing gridcell-level check with use_fates_planthydro until issue 1314 is resolved if (errh2o_max_val > h2o_warning_thresh .and. .not.use_fates_planthydro) then + indexg = maxloc( abs(errh2o_grc(bounds%begg:bounds%endg)), 1 ) + bounds%begg - 1 write(iulog,*)'WARNING: grid cell-level water balance error ',& ' nstep= ',nstep, & @@ -828,7 +829,6 @@ subroutine BalanceCheck( bounds, & if (col%itype(c) == icol_road_perv .or. lun%itype(l) == istsoil .or. & lun%itype(l) == istcrop .or. lun%itype(l) == istwet .or. & lun%itype(l) == istice) then - snow_sources(c) = (qflx_snow_grnd_col(c) - qflx_snow_h2osfc(c) ) & + frac_sno_eff(c) * (qflx_liq_grnd_col(c) & + qflx_soliddew_to_top_layer(c) + qflx_liqdew_to_top_layer(c) ) & @@ -973,6 +973,7 @@ subroutine BalanceCheck( bounds, & write(iulog,*)'CTSM is stopping' call endrun(subgrid_index=indexp, subgrid_level=subgrid_level_patch, msg=errmsg(sourcefile, __LINE__)) end if + end if ! Longwave radiation energy balance check diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 868902db90..c9f2e2c6be 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -183,7 +183,6 @@ subroutine InitHillslope(bounds,fsurdat) use landunit_varcon , only : istsoil use subgridWeightsMod , only : compute_higher_order_weights use ncdio_pio - ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -615,7 +614,6 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d use fileutils , only : getfil use clm_varcon , only : spval, ispval, grlnd use ncdio_pio - ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -716,7 +714,6 @@ subroutine HillslopeSoilThicknessProfile(bounds,& use fileutils , only : getfil use clm_varcon , only : spval, ispval, grlnd use ncdio_pio - ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -816,7 +813,6 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) ! Assumes each column has a single pft. ! In preparation for this reassignment of patch type, only the ! first patch was given a non-zero weight in surfrd_hillslope - ! ! !USES use LandunitType , only : lun @@ -873,7 +869,6 @@ subroutine HillslopeDominantLowlandPft(bounds) ! prepare the patch weights for this routine. ! Assumes each column has a single pft. ! Use largest weight for lowland, 2nd largest weight for uplands - ! ! !USES use LandunitType , only : lun @@ -980,7 +975,6 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) use ColumnType , only : col use PatchType , only : patch use clm_varpar , only : natpft_lb - ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -1032,7 +1026,6 @@ subroutine HillslopeStreamOutflow(bounds, & use landunit_varcon , only : istsoil use ncdio_pio use clm_time_manager , only : get_step_size_real - ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds @@ -1141,7 +1134,6 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & use clm_varcon , only : spval, ispval, grlnd use landunit_varcon , only : istsoil use clm_time_manager, only : get_step_size_real - ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds diff --git a/src/biogeophys/HydrologyDrainageMod.F90 b/src/biogeophys/HydrologyDrainageMod.F90 index ec7c7c76e4..ce5b78e3ff 100644 --- a/src/biogeophys/HydrologyDrainageMod.F90 +++ b/src/biogeophys/HydrologyDrainageMod.F90 @@ -22,7 +22,7 @@ module HydrologyDrainageMod use GlacierSurfaceMassBalanceMod, only : glacier_smb_type use TotalWaterAndHeatMod, only : ComputeWaterMassNonLake use LandunitType , only : lun - use ColumnType , only : col + use ColumnType , only : col ! ! !PUBLIC TYPES: implicit none @@ -35,7 +35,6 @@ module HydrologyDrainageMod contains !----------------------------------------------------------------------- - subroutine HydrologyDrainage(bounds, & num_nolakec, filter_nolakec, & num_hydrologyc, filter_hydrologyc, & @@ -54,13 +53,11 @@ subroutine HydrologyDrainage(bounds, & use column_varcon , only : icol_roof, icol_road_imperv, icol_road_perv, icol_sunwall, icol_shadewall use clm_varcon , only : denh2o, denice use clm_varctl , only : use_vichydro, use_hillslope, use_hillslope_routing - use clm_varpar , only : nlevgrnd, nlevurb use clm_time_manager , only : get_step_size_real, get_nstep use SoilHydrologyMod , only : CLMVICMap, Drainage, PerchedLateralFlow, SubsurfaceLateralFlow use SoilWaterMovementMod , only : use_aquifer_layer use HillslopeHydrologyMod, only : streamflow_manning, HillslopeStreamOutflow, HillslopeUpdateStreamWater - ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds @@ -71,7 +68,7 @@ subroutine HydrologyDrainage(bounds, & integer , intent(in) :: num_urbanc ! number of column urban points in column filter integer , intent(in) :: filter_urbanc(:) ! column filter for urban points integer , intent(in) :: num_do_smb_c ! number of bareland columns in which SMB is calculated, in column filter - integer , intent(in) :: filter_do_smb_c(:) ! column filter for bare land SMB columns + integer , intent(in) :: filter_do_smb_c(:) ! column filter for bare land SMB columns type(glc2lnd_type) , intent(in) :: glc2lnd_inst type(temperature_type) , intent(in) :: temperature_inst @@ -87,7 +84,6 @@ subroutine HydrologyDrainage(bounds, & ! !LOCAL VARIABLES: integer :: g,l,c,j,fc ! indices real(r8) :: dtime ! land model time step (sec) - !----------------------------------------------------------------------- associate( & ! Input: layer thickness depth (m) @@ -151,11 +147,11 @@ subroutine HydrologyDrainage(bounds, & waterstatebulk_inst, waterfluxbulk_inst, & wateratm2lndbulk_inst) - if(use_hillslope_routing) then + if (use_hillslope_routing) then call HillslopeStreamOutflow(bounds,& waterstatebulk_inst, waterfluxbulk_inst, & streamflow_method=streamflow_manning) - + call HillslopeUpdateStreamWater(bounds, & waterstatebulk_inst, waterfluxbulk_inst, & waterdiagnosticbulk_inst) @@ -191,7 +187,6 @@ subroutine HydrologyDrainage(bounds, & ! Determine wetland and land ice hydrology (must be placed here ! since need snow updated from CombineSnowLayers) - do fc = 1,num_nolakec c = filter_nolakec(fc) l = col%landunit(c) diff --git a/src/biogeophys/HydrologyNoDrainageMod.F90 b/src/biogeophys/HydrologyNoDrainageMod.F90 index c7086d8473..8f294c652e 100644 --- a/src/biogeophys/HydrologyNoDrainageMod.F90 +++ b/src/biogeophys/HydrologyNoDrainageMod.F90 @@ -36,7 +36,7 @@ Module HydrologyNoDrainageMod ! ! !PUBLIC TYPES: implicit none - save + save ! ! !PUBLIC MEMBER FUNCTIONS: public :: CalcAndWithdrawIrrigationFluxes ! Calculates irrigation withdrawal fluxes and withdraws from groundwater @@ -131,7 +131,6 @@ subroutine HandleNewSnow(bounds, & end subroutine HandleNewSnow !----------------------------------------------------------------------- - subroutine HydrologyNoDrainage(bounds, & num_nolakec, filter_nolakec, & num_hydrologyc, filter_hydrologyc, & @@ -165,7 +164,7 @@ subroutine HydrologyNoDrainage(bounds, & use SoilWaterMovementMod , only : SoilWater use SoilWaterRetentionCurveMod, only : soil_water_retention_curve_type use SoilWaterMovementMod , only : use_aquifer_layer - use SoilWaterPlantSinkMod, only : Compute_EffecRootFrac_And_VertTranSink + use SoilWaterPlantSinkMod , only : Compute_EffecRootFrac_And_VertTranSink use SurfaceWaterMod , only : UpdateH2osfc ! @@ -182,7 +181,6 @@ subroutine HydrologyNoDrainage(bounds, & integer , intent(inout) :: num_nosnowc ! number of column non-snow points integer , intent(inout) :: filter_nosnowc(:) ! column filter for non-snow points type(hlm_fates_interface_type), intent(inout) :: clm_fates - type(atm2lnd_type) , intent(in) :: atm2lnd_inst type(soilstate_type) , intent(inout) :: soilstate_inst type(energyflux_type) , intent(in) :: energyflux_inst diff --git a/src/biogeophys/IrrigationMod.F90 b/src/biogeophys/IrrigationMod.F90 index faea425616..27cf050dd3 100644 --- a/src/biogeophys/IrrigationMod.F90 +++ b/src/biogeophys/IrrigationMod.F90 @@ -362,7 +362,6 @@ subroutine ReadNamelist(this, NLFilename, use_aquifer_layer) use spmdMod , only : masterproc, mpicom use shr_mpi_mod , only : shr_mpi_bcast use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) - ! ! !ARGUMENTS: class(irrigation_type) , intent(inout) :: this From c7c6602af375870d04e622a55ec8e37deff17b1b Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 29 Dec 2023 10:35:16 -0700 Subject: [PATCH 119/153] merge to main --- src/biogeophys/WaterStateType.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/biogeophys/WaterStateType.F90 b/src/biogeophys/WaterStateType.F90 index 2393e57056..6b6f59729e 100644 --- a/src/biogeophys/WaterStateType.F90 +++ b/src/biogeophys/WaterStateType.F90 @@ -300,6 +300,7 @@ subroutine InitHistory(this, bounds, use_aquifer_layer) avgflag='A', & long_name=this%info%lname('volume of water in stream channel (hillslope hydrology only)'), & ptr_lunit=this%stream_water_volume_lun, l2g_scale_type='natveg', default='inactive') + endif ! Add excess ice fields to history From 44d37e7e83d03644a2d491f80e4c5982f4c4c6f9 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Fri, 19 Jan 2024 10:29:20 -0700 Subject: [PATCH 120/153] add check for stream channel --- src/biogeophys/HillslopeHydrologyMod.F90 | 36 ++++++++++++++++++------ 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index ed7e6fa547..777b86eaae 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -1052,8 +1052,9 @@ subroutine HillslopeStreamOutflow(bounds, & real(r8), parameter :: manning_exponent = 0.667_r8 ! manning exponent integer, parameter :: overbank_method = 1 ! method to treat overbank stream storage; 1 = increase dynamic slope, 2 = increase flow area cross section, 3 = remove instantaneously + logical :: active_stream character(len=*), parameter :: subname = 'HillslopeStreamOutflow' - + !----------------------------------------------------------------------- associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) @@ -1065,7 +1066,16 @@ subroutine HillslopeStreamOutflow(bounds, & do l = bounds%begl,bounds%endl volumetric_streamflow(l) = 0._r8 - if(lun%itype(l) == istsoil .and. lun%active(l)) then + + ! Check for vegetated landunits having initialized stream channel properties + active_stream = .false. + if (lun%itype(l) == istsoil .and. & + lun%stream_channel_length(l) > 0._r8 .and. & + lun%stream_channel_width(l) > 0._r8) then + active_stream = .true. + endif + + if (lun%active(l) .and. active_stream) then ! Streamflow calculated from Manning equation if(streamflow_method == streamflow_manning) then cross_sectional_area = stream_water_volume(l) & @@ -1149,11 +1159,12 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst type(waterdiagnosticbulk_type), intent(out) :: waterdiagnosticbulk_inst - integer :: c, l, g, i, j - real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) - real(r8) :: qflx_drain_perched_vol ! volumetric perched saturated drainage (m3/s) - real(r8) :: qflx_drain_vol ! volumetric saturated drainage (m3/s) - real(r8) :: dtime ! land model time step (sec) + integer :: c, l, g, i, j + real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) + real(r8) :: qflx_drain_perched_vol ! volumetric perched saturated drainage (m3/s) + real(r8) :: qflx_drain_vol ! volumetric saturated drainage (m3/s) + real(r8) :: dtime ! land model time step (sec) + logical :: active_stream character(len=*), parameter :: subname = 'HillslopeUpdateStreamWater' @@ -1171,7 +1182,16 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & dtime = get_step_size_real() do l = bounds%begl,bounds%endl - if(lun%itype(l) == istsoil) then + + ! Check for vegetated landunits having initialized stream channel properties + active_stream = .false. + if (lun%itype(l) == istsoil .and. & + lun%stream_channel_length(l) > 0._r8 .and. & + lun%stream_channel_width(l) > 0._r8) then + active_stream = .true. + endif + + if (lun%active(l) .and. active_stream) then g = lun%gridcell(l) ! the drainage terms are 'net' quantities, so summing over ! all columns in a hillslope is equivalent to the outflow From 54f765af8161854371efb7048fdfa6bce1540686 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 19 Jan 2024 12:14:18 -0700 Subject: [PATCH 121/153] Hillslope test: Use fixed fsurdat. --- cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm index 70970216a1..a2d83ffe0d 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -1,4 +1,4 @@ -fsurdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.0.nc' +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.1.nc' use_hillslope = .true. use_hillslope_routing = .true. hillslope_pft_distribution_method = 'PftLowlandUpland' From 55e14ebf47e17730247bcfc990845252bf3ed3dd Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 19 Jan 2024 12:20:16 -0700 Subject: [PATCH 122/153] Remove EOL whitespace from HillslopeHydrologyMod. --- src/biogeophys/HillslopeHydrologyMod.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 0f8de1d235..5a7f11a114 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -1047,7 +1047,7 @@ subroutine HillslopeStreamOutflow(bounds, & integer, parameter :: overbank_method = 1 ! method to treat overbank stream storage; 1 = increase dynamic slope, 2 = increase flow area cross section, 3 = remove instantaneously logical :: active_stream character(len=*), parameter :: subname = 'HillslopeStreamOutflow' - + !----------------------------------------------------------------------- associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) @@ -1150,7 +1150,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst type(waterdiagnosticbulk_type), intent(out) :: waterdiagnosticbulk_inst - + integer :: c, l, g, i, j real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) real(r8) :: qflx_drain_perched_vol ! volumetric perched saturated drainage (m3/s) @@ -1174,7 +1174,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & dtime = get_step_size_real() do l = bounds%begl,bounds%endl - + ! Check for vegetated landunits having initialized stream channel properties active_stream = .false. if (lun%itype(l) == istsoil .and. & @@ -1182,7 +1182,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & lun%stream_channel_width(l) > 0._r8) then active_stream = .true. endif - + if (lun%active(l) .and. active_stream) then g = lun%gridcell(l) ! the drainage terms are 'net' quantities, so summing over From c5be402f83501ac5ee97f2a467b20f0d0e94c591 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 08:49:50 -0700 Subject: [PATCH 123/153] Alignment changes in HillslopeHydrologyMod. --- src/biogeophys/HillslopeHydrologyMod.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 5a7f11a114..bf24b25b52 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -1049,9 +1049,9 @@ subroutine HillslopeStreamOutflow(bounds, & character(len=*), parameter :: subname = 'HillslopeStreamOutflow' !----------------------------------------------------------------------- - associate( & - stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) - volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun & ! Input: [real(r8) (:) ] stream water discharge (m3/s) + associate( & + stream_water_volume => waterstatebulk_inst%stream_water_volume_lun , & ! Input: [real(r8) (:) ] stream water volume (m3) + volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun & ! Input: [real(r8) (:) ] stream water discharge (m3/s) ) ! Get time step @@ -1163,10 +1163,10 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & !----------------------------------------------------------------------- associate( & stream_water_volume => waterstatebulk_inst%stream_water_volume_lun, & ! Input/Output: [real(r8) (:) ] stream water volume (m3) - volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun , & ! Input: [real(r8) (:) ] stream water discharge (m3/s) + volumetric_streamflow => waterfluxbulk_inst%volumetric_streamflow_lun,& ! Input: [real(r8) (:) ] stream water discharge (m3/s) qflx_drain => waterfluxbulk_inst%qflx_drain_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) qflx_drain_perched => waterfluxbulk_inst%qflx_drain_perched_col, & ! Input: [real(r8) (:) ] column level sub-surface runoff (mm H2O /s) - qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) + qflx_surf => waterfluxbulk_inst%qflx_surf_col, & ! Input: [real(r8) (:) ] total surface runoff (mm H2O /s) stream_water_depth => waterdiagnosticbulk_inst%stream_water_depth_lun & ! Output: [real(r8) (:) ] stream water depth (m) ) From 51c95e51d79d9b941eaa060cebe8d448b8fc4294 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 09:01:51 -0700 Subject: [PATCH 124/153] Check for unrecognized pft_distribution_method in surfrd_hillslope(). This ensures that any methods added in the future are handled here. --- src/main/surfrdMod.F90 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 03d3813c96..42534d418c 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -899,7 +899,7 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) use clm_varpar, only : natpft_size, natpft_lb use ncdio_pio, only : ncd_inqdid, ncd_inqdlen use pftconMod , only : noveg - use HillslopeHydrologyMod, only : pft_distribution_method, pft_from_file, pft_uniform_dominant_pft, pft_lowland_dominant_pft, pft_lowland_upland + use HillslopeHydrologyMod, only : pft_distribution_method, pft_standard, pft_from_file, pft_uniform_dominant_pft, pft_lowland_dominant_pft, pft_lowland_upland use array_utils, only: find_k_max_indices ! @@ -959,11 +959,10 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) wt_nat_patch(g,natpft_lb) = 100._r8 endif enddo - endif ! pft_uniform_dominant_pft uses the patch with the ! largest weight for all hillslope columns in the gridcell - if (pft_distribution_method == pft_uniform_dominant_pft) then + else if (pft_distribution_method == pft_uniform_dominant_pft) then allocate(max_indices(1)) do g = begg, endg ! If hillslopes will be used in a gridcell, modify wt_nat_patch, @@ -977,11 +976,10 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) endif enddo deallocate(max_indices) - endif ! pft_lowland_dominant_pft uses the two patches with the ! largest weights for the hillslope columns in the gridcell - if (pft_distribution_method == pft_lowland_dominant_pft) then + else if (pft_distribution_method == pft_lowland_dominant_pft) then allocate(max_indices(2)) do g = begg, endg ! If hillslopes will be used in a gridcell, modify wt_nat_patch, otherwise use original patch distribution @@ -1008,6 +1006,9 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) endif enddo deallocate(max_indices) + + else if (pft_distribution_method /= pft_standard) then + call endrun( msg=' ERROR: unrecognized hillslope_pft_distribution_method'//errMsg(sourcefile, __LINE__)) endif end subroutine surfrd_hillslope From 41a7e0de72d78b40e2476e743afbd63f54268fb0 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 09:07:59 -0700 Subject: [PATCH 125/153] Error on unhandled soil_profile_method in SetHillslopeSoilThickness(). --- src/biogeophys/HillslopeHydrologyMod.F90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index bf24b25b52..6e24358738 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -692,6 +692,10 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d soil_profile_method=soil_profile_method,& soil_depth_lowland_in=soil_depth_lowland,& soil_depth_upland_in=soil_depth_upland) + + else if (soil_profile_method /= soil_profile_uniform .and. masterproc) then + call endrun( msg=' ERROR: unrecognized hillslope_soil_profile_method'//errMsg(sourcefile, __LINE__)) + endif end subroutine SetHillslopeSoilThickness From b1433a08b80fbdf039fdc01f5538df249ace27ce Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 09:10:04 -0700 Subject: [PATCH 126/153] Fix logic for missing h_bedrock error check. --- src/biogeophys/HillslopeHydrologyMod.F90 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 6e24358738..063057d440 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -647,10 +647,6 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d if (readvar) then if (masterproc) then write(iulog,*) 'h_bedrock found on surface data set' - else - if (masterproc) then - call endrun( 'ERROR:: soil_profile_method = "FromFile", but h_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -669,6 +665,8 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d enddo enddo deallocate(fhillslope_in) + else if (masterproc) then + call endrun( 'ERROR:: soil_profile_method = "FromFile", but h_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if call ncd_pio_closefile(ncid) From 8abcb5500a23a9fa81905db7115a6fb69f62aba3 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 09:12:37 -0700 Subject: [PATCH 127/153] Remove check_npatches, which was hard-coded true. --- src/biogeophys/HillslopeHydrologyMod.F90 | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 063057d440..73f3dfd387 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -831,7 +831,6 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) ! !LOCAL VARIABLES: integer :: p,c ! indices integer :: npatches_per_column - logical :: check_npatches = .true. !------------------------------------------------------------------------ @@ -851,11 +850,9 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) npatches_per_column = npatches_per_column + 1 enddo - if (check_npatches) then - if ((npatches_per_column /= 1) .and. masterproc) then - call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) - end if - endif + if ((npatches_per_column /= 1) .and. masterproc) then + call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) + end if endif enddo @@ -985,7 +982,6 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) ! !LOCAL VARIABLES: integer :: p,c ! indices integer :: npatches_per_column - logical :: check_npatches = .true. !------------------------------------------------------------------------ @@ -1000,11 +996,9 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) patch%mxy(p) = patch%itype(p) + (1 - natpft_lb) npatches_per_column = npatches_per_column + 1 enddo - if (check_npatches) then - if ((npatches_per_column /= 1) .and. masterproc) then - call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) - end if - endif + if ((npatches_per_column /= 1) .and. masterproc) then + call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) + end if endif enddo From 00d2b1e536f593d00a6460357a0e7db5389e232a Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 09:17:14 -0700 Subject: [PATCH 128/153] Un-nest "if (masterproc)" in HillslopeHydrologyMod. --- src/biogeophys/HillslopeHydrologyMod.F90 | 112 ++++++++--------------- 1 file changed, 38 insertions(+), 74 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 73f3dfd387..807f5bd808 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -246,10 +246,8 @@ subroutine InitHillslope(bounds,fsurdat) allocate(ncolumns_hillslope_in(bounds%begg:bounds%endg)) call ncd_io(ncid=ncid, varname='nhillcolumns', flag='read', data=ncolumns_hillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: nhillcolumns not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: nhillcolumns not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -266,10 +264,8 @@ subroutine InitHillslope(bounds,fsurdat) allocate(fhillslope_in(bounds%begg:bounds%endg,nhillslope)) call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -280,10 +276,8 @@ subroutine InitHillslope(bounds,fsurdat) allocate(ihillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='hillslope_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: hillslope_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: hillslope_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -291,10 +285,8 @@ subroutine InitHillslope(bounds,fsurdat) enddo call ncd_io(ncid=ncid, varname='column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -302,10 +294,8 @@ subroutine InitHillslope(bounds,fsurdat) enddo call ncd_io(ncid=ncid, varname='downhill_column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: downhill_column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: downhill_column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -315,10 +305,8 @@ subroutine InitHillslope(bounds,fsurdat) allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='h_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: h_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -327,10 +315,8 @@ subroutine InitHillslope(bounds,fsurdat) enddo call ncd_io(ncid=ncid, varname='h_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: h_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -339,20 +325,16 @@ subroutine InitHillslope(bounds,fsurdat) enddo call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: h_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_area(l,:) = fhillslope_in(g,:) enddo call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -361,10 +343,8 @@ subroutine InitHillslope(bounds,fsurdat) enddo call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -372,10 +352,8 @@ subroutine InitHillslope(bounds,fsurdat) enddo call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (.not. readvar) then - if (masterproc) then - call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + if (masterproc .and. .not. readvar) then + call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -410,10 +388,8 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) lun%stream_channel_depth(l) = fstream_in(g) enddo - else - if (masterproc) then - call endrun( 'ERROR:: h_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + else if (masterproc) then + call endrun( 'ERROR:: h_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) endif call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then @@ -424,10 +400,8 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) lun%stream_channel_width(l) = fstream_in(g) enddo - else - if (masterproc) then - call endrun( 'ERROR:: h_stream_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + else if (masterproc) then + call endrun( 'ERROR:: h_stream_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then @@ -438,10 +412,8 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) lun%stream_channel_slope(l) = fstream_in(g) enddo - else - if (masterproc) then - call endrun( 'ERROR:: h_stream_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - end if + else if (masterproc) then + call endrun( 'ERROR:: h_stream_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if deallocate(fstream_in) @@ -545,12 +517,10 @@ subroutine InitHillslope(bounds,fsurdat) ! if missing hillslope information on surface dataset, ! call endrun - if (ncolumns_hillslope(l) > 0 .and. sum(hillslope_area) == 0._r8) then - if (masterproc) then - write(iulog,*) 'Problem with input data: nhillcolumns is non-zero, but hillslope area is zero' - write(iulog,*) 'Check surface data for gridcell at (lon/lat): ', grc%londeg(g),grc%latdeg(g) - call endrun( 'ERROR:: sum of hillslope areas is zero.'//errmsg(sourcefile, __LINE__) ) - end if + if (ncolumns_hillslope(l) > 0 .and. sum(hillslope_area) == 0._r8 .and. masterproc) then + write(iulog,*) 'Problem with input data: nhillcolumns is non-zero, but hillslope area is zero' + write(iulog,*) 'Check surface data for gridcell at (lon/lat): ', grc%londeg(g),grc%latdeg(g) + call endrun( 'ERROR:: sum of hillslope areas is zero.'//errmsg(sourcefile, __LINE__) ) endif ! Recalculate column weights using input areas @@ -798,10 +768,8 @@ subroutine HillslopeSoilThicknessProfile(bounds,& endif enddo enddo - else - if (masterproc) then - call endrun( 'ERROR:: invalid soil_profile_method.'//errmsg(sourcefile, __LINE__) ) - end if + else if (masterproc) then + call endrun( 'ERROR:: invalid soil_profile_method.'//errmsg(sourcefile, __LINE__) ) endif end subroutine HillslopeSoilThicknessProfile @@ -1095,10 +1063,8 @@ subroutine HillslopeStreamOutflow(bounds, & volumetric_streamflow(l) = cross_sectional_area * flow_velocity & + (stream_depth-lun%stream_channel_depth(l)) & *lun%stream_channel_width(l)*lun%stream_channel_length(l)/dtime - else - if (masterproc) then - call endrun( 'ERROR:: invalid overbank_method.'//errmsg(sourcefile, __LINE__) ) - end if + else if (masterproc) then + call endrun( 'ERROR:: invalid overbank_method.'//errmsg(sourcefile, __LINE__) ) endif else @@ -1110,10 +1076,8 @@ subroutine HillslopeStreamOutflow(bounds, & volumetric_streamflow(l) = max(0._r8,min(volumetric_streamflow(l),stream_water_volume(l)/dtime)) endif - else - if (masterproc) then - call endrun( 'ERROR:: invalid streamflow_method'//errmsg(sourcefile, __LINE__) ) - end if + else if (masterproc) then + call endrun( 'ERROR:: invalid streamflow_method'//errmsg(sourcefile, __LINE__) ) endif endif ! end of istsoil enddo ! end of loop over landunits From 8f3d6ab2fd6a593a62cd405b2a7faa4aac1cf8e2 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 09:26:28 -0700 Subject: [PATCH 129/153] HillslopeHydrologyMod: Consistent whitespace in if statements. --- src/biogeophys/HillslopeHydrologyMod.F90 | 142 +++++++++++------------ 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 807f5bd808..4da0337e72 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -130,7 +130,7 @@ subroutine hillslope_properties_init(NLFilename) call endrun(msg="ERROR bad value for hillslope_soil_profile_method in "//nmlname//"namelist"//errmsg(sourcefile, __LINE__)) end if - endif + end if call shr_mpi_bcast(pft_distribution_method, mpicom) call shr_mpi_bcast(soil_profile_method, mpicom) @@ -142,7 +142,7 @@ subroutine hillslope_properties_init(NLFilename) write(iulog,*) ' hillslope_pft_distribution_method = ',hillslope_pft_distribution_method write(iulog,*) ' hillslope_soil_profile_method = ',hillslope_soil_profile_method - endif + end if end subroutine hillslope_properties_init @@ -253,11 +253,11 @@ subroutine InitHillslope(bounds,fsurdat) g = lun%gridcell(l) ncolumns_hillslope(l) = ncolumns_hillslope_in(g) ! vegetated landunits having nonzero hillslope columns and nonzero weight - if(lun%wtgcell(l) > 0._r8 .and. lun%itype(l) == istsoil .and. ncolumns_hillslope_in(g) > 0) then + if (lun%wtgcell(l) > 0._r8 .and. lun%itype(l) == istsoil .and. ncolumns_hillslope_in(g) > 0) then do c = lun%coli(l), lun%colf(l) col%is_hillslope_column(c) = .true. enddo - endif + end if enddo deallocate(ncolumns_hillslope_in) @@ -390,7 +390,7 @@ subroutine InitHillslope(bounds,fsurdat) enddo else if (masterproc) then call endrun( 'ERROR:: h_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) - endif + end if call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then if (masterproc) then @@ -417,13 +417,13 @@ subroutine InitHillslope(bounds,fsurdat) end if deallocate(fstream_in) - endif + end if ! Set hillslope hydrology column level variables ! This needs to match how columns set up in subgridMod do l = bounds%begl,bounds%endl g = lun%gridcell(l) - if(lun%itype(l) == istsoil) then + if (lun%itype(l) == istsoil) then ! map external column index to internal column index do c = lun%coli(l), lun%colf(l) @@ -436,7 +436,7 @@ subroutine InitHillslope(bounds,fsurdat) else ! relative separation should be the same col%cold(c) = c + (col_dndx(l,ci) - col_ndx(l,ci)) - endif + end if enddo do c = lun%coli(l), lun%colf(l) @@ -447,9 +447,9 @@ subroutine InitHillslope(bounds,fsurdat) ! Find uphill neighbors (this may not actually be useful...) col%colu(c) = ispval do i = lun%coli(l), lun%colf(l) - if(c == col%cold(i)) then + if (c == col%cold(i)) then col%colu(c) = i - endif + end if enddo ! distance of lower edge of column from hillslope bottom @@ -467,7 +467,7 @@ subroutine InitHillslope(bounds,fsurdat) ! pft index of column if ( allocated(hill_pftndx) ) then col_pftndx(c) = hill_pftndx(l,ci) - endif + end if enddo @@ -480,7 +480,7 @@ subroutine InitHillslope(bounds,fsurdat) if (nh > 0) then ncol_per_hillslope(nh) = ncol_per_hillslope(nh) + 1 hillslope_area(nh) = hillslope_area(nh) + col%hill_area(c) - endif + end if enddo if (use_hillslope_routing) then @@ -493,13 +493,13 @@ subroutine InitHillslope(bounds,fsurdat) lun%stream_channel_number(l) = 0._r8 do nh = 1, nhillslope - if(hillslope_area(nh) > 0._r8) then + if (hillslope_area(nh) > 0._r8) then nhill_per_landunit(nh) = grc%area(g)*1.e6_r8*lun%wtgcell(l) & *pct_hillslope(l,nh)*0.01/hillslope_area(nh) lun%stream_channel_number(l) = lun%stream_channel_number(l) & + 0.5_r8 * nhill_per_landunit(nh) - endif + end if enddo ! Calculate steam channel length @@ -508,12 +508,12 @@ subroutine InitHillslope(bounds,fsurdat) ! include factor of 0.5 because a channel is shared by ~2 hillslopes lun%stream_channel_length(l) = 0._r8 do c = lun%coli(l), lun%colf(l) - if(col%cold(c) == ispval) then + if (col%cold(c) == ispval) then lun%stream_channel_length(l) = lun%stream_channel_length(l) & + col%hill_width(c) * 0.5_r8 * nhill_per_landunit(col%hillslope_ndx(c)) - endif + end if enddo - endif + end if ! if missing hillslope information on surface dataset, ! call endrun @@ -521,7 +521,7 @@ subroutine InitHillslope(bounds,fsurdat) write(iulog,*) 'Problem with input data: nhillcolumns is non-zero, but hillslope area is zero' write(iulog,*) 'Check surface data for gridcell at (lon/lat): ', grc%londeg(g),grc%latdeg(g) call endrun( 'ERROR:: sum of hillslope areas is zero.'//errmsg(sourcefile, __LINE__) ) - endif + end if ! Recalculate column weights using input areas ! The higher order weights will be updated in a subsequent reweight_wrapup call @@ -530,9 +530,9 @@ subroutine InitHillslope(bounds,fsurdat) if (col%is_hillslope_column(c)) then col%wtlunit(c) = (col%hill_area(c)/hillslope_area(nh)) & * (pct_hillslope(l,nh)*0.01_r8) - endif + end if enddo - endif + end if enddo ! end of landunit loop deallocate(ncolumns_hillslope,pct_hillslope,hill_ndx,col_ndx,col_dndx, & @@ -552,12 +552,12 @@ subroutine InitHillslope(bounds,fsurdat) ! upland_ivt = 13 ! c3 non-arctic grass ! lowland_ivt = 7 ! broadleaf deciduous tree call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) - endif + end if if ( allocated(hill_pftndx) ) then deallocate(hill_pftndx) deallocate(col_pftndx) - endif + end if ! Update higher order weights and check that weights sum to 1 call compute_higher_order_weights(bounds) @@ -606,7 +606,7 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d !----------------------------------------------------------------------- - if(soil_profile_method==soil_profile_from_file) then + if (soil_profile_method==soil_profile_from_file) then ! Open surface dataset to read in data below call getfil (fsurdat, locfn, 0) @@ -624,14 +624,14 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d if (col%is_hillslope_column(c) .and. col%active(c)) then ci = c-lun%coli(l)+1 do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) > zmin_bedrock) then if (zisoi(j-1) < fhillslope_in(g,ci) & .and. zisoi(j) >= fhillslope_in(g,ci)) then col%nbedrock(c) = j end if - endif + end if enddo - endif + end if enddo enddo deallocate(fhillslope_in) @@ -643,17 +643,17 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d else if (soil_profile_method==soil_profile_set_lowland_upland & .or. soil_profile_method==soil_profile_linear) then - if(present(soil_depth_lowland_in)) then + if (present(soil_depth_lowland_in)) then soil_depth_lowland = soil_depth_lowland_in else soil_depth_lowland = soil_depth_lowland_default - endif + end if - if(present(soil_depth_upland_in)) then + if (present(soil_depth_upland_in)) then soil_depth_upland = soil_depth_upland_in else soil_depth_upland = soil_depth_upland_default - endif + end if ! Modify hillslope soil thickness profile call HillslopeSoilThicknessProfile(bounds,& @@ -664,7 +664,7 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d else if (soil_profile_method /= soil_profile_uniform .and. masterproc) then call endrun( msg=' ERROR: unrecognized hillslope_soil_profile_method'//errMsg(sourcefile, __LINE__)) - endif + end if end subroutine SetHillslopeSoilThickness @@ -707,25 +707,25 @@ subroutine HillslopeSoilThicknessProfile(bounds,& !----------------------------------------------------------------------- - if(present(soil_depth_lowland_in)) then + if (present(soil_depth_lowland_in)) then soil_depth_lowland = soil_depth_lowland_in else soil_depth_lowland = soil_depth_lowland_default - endif + end if - if(present(soil_depth_upland_in)) then + if (present(soil_depth_upland_in)) then soil_depth_upland = soil_depth_upland_in else soil_depth_upland = soil_depth_upland_default - endif + end if ! Specify lowland/upland soil thicknesses separately - if(soil_profile_method == soil_profile_set_lowland_upland) then + if (soil_profile_method == soil_profile_set_lowland_upland) then do c = bounds%begc,bounds%endc if (col%is_hillslope_column(c) .and. col%active(c)) then - if(col%cold(c) /= ispval) then + if (col%cold(c) /= ispval) then do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) > zmin_bedrock) then if (zisoi(j-1) < soil_depth_upland .and. zisoi(j) >= soil_depth_upland) then col%nbedrock(c) = j end if @@ -733,27 +733,27 @@ subroutine HillslopeSoilThicknessProfile(bounds,& enddo else do j = 1,nlevsoi - if(zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) > zmin_bedrock) then if (zisoi(j-1) < soil_depth_lowland .and. zisoi(j) >= soil_depth_lowland) then col%nbedrock(c) = j end if end if enddo - endif - endif + end if + end if end do ! Linear soil thickness profile - else if(soil_profile_method == soil_profile_linear) then + else if (soil_profile_method == soil_profile_linear) then do l = bounds%begl,bounds%endl min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) - if(abs(max_hill_dist - min_hill_dist) > toosmall_distance) then + if (abs(max_hill_dist - min_hill_dist) > toosmall_distance) then m = (soil_depth_lowland - soil_depth_upland)/ & (max_hill_dist - min_hill_dist) else m = 0._r8 - endif + end if b = soil_depth_upland do c = lun%coli(l), lun%colf(l) @@ -765,12 +765,12 @@ subroutine HillslopeSoilThicknessProfile(bounds,& col%nbedrock(c) = j end if enddo - endif + end if enddo enddo else if (masterproc) then call endrun( 'ERROR:: invalid soil_profile_method.'//errmsg(sourcefile, __LINE__) ) - endif + end if end subroutine HillslopeSoilThicknessProfile @@ -806,13 +806,13 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) if (col%is_hillslope_column(c)) then npatches_per_column = 0 do p = col%patchi(c), col%patchf(c) - if(col%cold(c) == ispval) then + if (col%cold(c) == ispval) then ! lowland patch%itype(p) = lowland_ivt else ! upland patch%itype(p) = upland_ivt - endif + end if ! update mxy as is done in initSubgridMod.add_patch patch%mxy(p) = patch%itype(p) + (1 - natpft_lb) @@ -821,7 +821,7 @@ subroutine HillslopeSetLowlandUplandPfts(bounds,lowland_ivt,upland_ivt) if ((npatches_per_column /= 1) .and. masterproc) then call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) end if - endif + end if enddo end subroutine HillslopeSetLowlandUplandPfts @@ -871,7 +871,7 @@ subroutine HillslopeDominantLowlandPft(bounds) else call find_k_max_indices(patch%wtcol(col%patchi(c):col%patchf(c)),1,2,max_indices) max_indices = max_indices + (col%patchi(c) - 1) - endif + end if sum_wtcol = sum(patch%wtcol(col%patchi(c):col%patchf(c))) sum_wtlun = sum(patch%wtlunit(col%patchi(c):col%patchf(c))) @@ -893,7 +893,7 @@ subroutine HillslopeDominantLowlandPft(bounds) else plow = max_indices(1) phigh = max_indices(2) - endif + end if ! Special cases (subjective) @@ -901,18 +901,18 @@ subroutine HillslopeDominantLowlandPft(bounds) if ((patch%itype(max_indices(1)) == ndllf_evr_tmp_tree) .and. pftcon%is_tree(patch%itype(max_indices(2)))) then plow = max_indices(2) phigh = max_indices(1) - endif + end if ! if C3/C4 assign C4 to lowland if ((patch%itype(max_indices(1)) == nc4_grass) .and. (patch%itype(max_indices(2)) == nc3_nonarctic_grass)) then plow = max_indices(1) phigh = max_indices(2) - endif + end if if ((patch%itype(max_indices(1)) == nc3_nonarctic_grass) .and. (patch%itype(max_indices(2)) == nc4_grass)) then plow = max_indices(2) phigh = max_indices(1) - endif + end if - if(col%cold(c) == ispval) then + if (col%cold(c) == ispval) then ! lowland column patch%wtcol(plow) = sum_wtcol patch%wtlunit(plow) = sum_wtlun @@ -922,8 +922,8 @@ subroutine HillslopeDominantLowlandPft(bounds) patch%wtcol(phigh) = sum_wtcol patch%wtlunit(phigh) = sum_wtlun patch%wtgcell(phigh) = sum_wtgrc - endif - endif + end if + end if enddo ! end loop c deallocate(max_indices) @@ -967,7 +967,7 @@ subroutine HillslopePftFromFile(bounds,col_pftndx) if ((npatches_per_column /= 1) .and. masterproc) then call endrun( 'ERROR:: number of patches per hillslope column not equal to 1'//errmsg(sourcefile, __LINE__) ) end if - endif + end if enddo end subroutine HillslopePftFromFile @@ -1030,11 +1030,11 @@ subroutine HillslopeStreamOutflow(bounds, & lun%stream_channel_length(l) > 0._r8 .and. & lun%stream_channel_width(l) > 0._r8) then active_stream = .true. - endif + end if if (lun%active(l) .and. active_stream) then ! Streamflow calculated from Manning equation - if(streamflow_method == streamflow_manning) then + if (streamflow_method == streamflow_manning) then cross_sectional_area = stream_water_volume(l) & /lun%stream_channel_length(l) stream_depth = cross_sectional_area & @@ -1042,7 +1042,7 @@ subroutine HillslopeStreamOutflow(bounds, & hydraulic_radius = cross_sectional_area & /(lun%stream_channel_width(l) + 2*stream_depth) - if(hydraulic_radius <= 0._r8) then + if (hydraulic_radius <= 0._r8) then volumetric_streamflow(l) = 0._r8 else flow_velocity = (hydraulic_radius)**manning_exponent & @@ -1065,21 +1065,21 @@ subroutine HillslopeStreamOutflow(bounds, & *lun%stream_channel_width(l)*lun%stream_channel_length(l)/dtime else if (masterproc) then call endrun( 'ERROR:: invalid overbank_method.'//errmsg(sourcefile, __LINE__) ) - endif + end if else volumetric_streamflow(l) = cross_sectional_area * flow_velocity - endif + end if ! scale streamflow by number of channel reaches volumetric_streamflow(l) = volumetric_streamflow(l) * lun%stream_channel_number(l) volumetric_streamflow(l) = max(0._r8,min(volumetric_streamflow(l),stream_water_volume(l)/dtime)) - endif + end if else if (masterproc) then call endrun( 'ERROR:: invalid streamflow_method'//errmsg(sourcefile, __LINE__) ) - endif - endif ! end of istsoil + end if + end if ! end of istsoil enddo ! end of loop over landunits end associate @@ -1141,7 +1141,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & lun%stream_channel_length(l) > 0._r8 .and. & lun%stream_channel_width(l) > 0._r8) then active_stream = .true. - endif + end if if (lun%active(l) .and. active_stream) then g = lun%gridcell(l) @@ -1160,22 +1160,22 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & stream_water_volume(l) = stream_water_volume(l) & + (qflx_drain_perched_vol & + qflx_drain_vol + qflx_surf_vol) * dtime - endif + end if enddo stream_water_volume(l) = stream_water_volume(l) & - volumetric_streamflow(l) * dtime ! account for negative drainage (via searchforwater in soilhydrology) - if(stream_water_volume(l) < 0._r8) then + if (stream_water_volume(l) < 0._r8) then volumetric_streamflow(l) = volumetric_streamflow(l) + stream_water_volume(l)/dtime stream_water_volume(l) = 0._r8 - endif + end if stream_water_depth(l) = stream_water_volume(l) & /lun%stream_channel_length(l) & /lun%stream_channel_width(l) - endif + end if enddo end associate From 04bceb057873bbb6bdf72799ad3eec9eaf0a131b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 12:39:29 -0700 Subject: [PATCH 130/153] Check for unrecognized pft_distribution_method in InitHillslope(). This ensures that any methods added in the future are handled here. --- src/biogeophys/HillslopeHydrologyMod.F90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 4da0337e72..4c5a27728c 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -552,6 +552,8 @@ subroutine InitHillslope(bounds,fsurdat) ! upland_ivt = 13 ! c3 non-arctic grass ! lowland_ivt = 7 ! broadleaf deciduous tree call HillslopeSetLowlandUplandPfts(bounds,lowland_ivt=7,upland_ivt=13) + else if (masterproc .and. .not. (pft_distribution_method == pft_standard .or. pft_distribution_method ==pft_uniform_dominant_pft)) then + call endrun( 'ERROR:: unrecognized hillslope_pft_distribution_method'//errmsg(sourcefile, __LINE__) ) end if if ( allocated(hill_pftndx) ) then From 12721d4157551f8340e9ad8ccfb8dfce289ce47b Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jan 2024 09:32:33 -0700 Subject: [PATCH 131/153] Point Hillslope test at testdata/ instead of surfdata/. --- cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm index a2d83ffe0d..ab6c7b464b 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -1,4 +1,4 @@ -fsurdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.1.nc' +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.1.nc' use_hillslope = .true. use_hillslope_routing = .true. hillslope_pft_distribution_method = 'PftLowlandUpland' From 4d0da3d4d2706f9da5b2d04a9294e83a6e560288 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jan 2024 15:39:59 -0700 Subject: [PATCH 132/153] Add Hillslope_DominantPftUniform and Hillslope_SoilProfileLinear testmods. --- .../clm/Hillslope_DominantPftUniform/include_user_mods | 1 + .../testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm | 1 + .../clm/Hillslope_SoilProfileLinear/include_user_mods | 1 + .../testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm | 1 + 4 files changed, 4 insertions(+) create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods new file mode 100644 index 0000000000..fa2e50a80d --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods @@ -0,0 +1 @@ +../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm new file mode 100644 index 0000000000..e85c64b9ff --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm @@ -0,0 +1 @@ +hillslope_pft_distribution_method = 'DominantPftUniform' diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods new file mode 100644 index 0000000000..fa2e50a80d --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods @@ -0,0 +1 @@ +../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm new file mode 100644 index 0000000000..ab07c64239 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm @@ -0,0 +1 @@ +hillslope_soil_profile_method = 'Linear' From 03cc0f215d06d29cc5dd96962f1fa11e6722db40 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 22 Jan 2024 18:33:14 -0700 Subject: [PATCH 133/153] Add optional do_not_collapse arg to collapse_to_dominant(). This logical array, where .true. will prevent individual gridcells from being collapsed. Includes unit testing. --- src/main/surfrdUtilsMod.F90 | 12 +++- .../test/surfrdUtils_test/test_surfrdUtils.pf | 66 +++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/main/surfrdUtilsMod.F90 b/src/main/surfrdUtilsMod.F90 index 6b581a59c1..97f5b7d80f 100644 --- a/src/main/surfrdUtilsMod.F90 +++ b/src/main/surfrdUtilsMod.F90 @@ -235,7 +235,7 @@ subroutine collapse_individual_lunits(wt_lunit, begg, endg, toosmall_soil, & end subroutine collapse_individual_lunits !----------------------------------------------------------------------- - subroutine collapse_to_dominant(weight, lower_bound, upper_bound, begg, endg, n_dominant) + subroutine collapse_to_dominant(weight, lower_bound, upper_bound, begg, endg, n_dominant, do_not_collapse) ! ! DESCRIPTION ! Collapse to the top N dominant pfts or landunits (n_dominant) @@ -251,6 +251,7 @@ subroutine collapse_to_dominant(weight, lower_bound, upper_bound, begg, endg, n_ integer, intent(in) :: lower_bound ! lower bound of pft or landunit indices integer, intent(in) :: upper_bound ! upper bound of pft or landunit indices integer, intent(in) :: n_dominant ! # dominant pfts or landunits + logical, intent(in), optional :: do_not_collapse(begg:endg) ! This array modified in-place ! Weights of pfts or landunits per grid cell ! Dimensioned [g, lower_bound:upper_bound] @@ -277,6 +278,14 @@ subroutine collapse_to_dominant(weight, lower_bound, upper_bound, begg, endg, n_ if (n_dominant > 0 .and. n_dominant < upper_bound) then allocate(max_indices(n_dominant)) do g = begg, endg + + ! original sum of all the weights + wt_sum(g) = sum(weight(g,:)) + + if (present(do_not_collapse) .and. do_not_collapse(g)) then + cycle + end if + max_indices = 0 ! initialize call find_k_max_indices(weight(g,:), lower_bound, n_dominant, & max_indices) @@ -286,7 +295,6 @@ subroutine collapse_to_dominant(weight, lower_bound, upper_bound, begg, endg, n_ ! Typically the original sum of weights = 1, but if ! collapse_urban = .true., it equals the sum of the urban landunits. ! Also set the remaining weights to 0. - wt_sum(g) = sum(weight(g,:)) ! original sum of all the weights wt_dom_sum = 0._r8 ! initialize the dominant pft or landunit sum do n = 1, n_dominant m = max_indices(n) diff --git a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf index 98191fbe99..53cc1c975e 100644 --- a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf +++ b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf @@ -570,6 +570,72 @@ contains end subroutine test_collapse_to_dom_pfts + + @Test + subroutine test_collapse_with_dont() + ! Tests subroutine collapse_to_dominant when used with an optional logical array indicating which gridcells should actually be collapsed + ! + use pftconMod, only: pftcon + use clm_instur, only: wt_nat_patch + use clm_varpar, only: natpft_lb, natpft_ub + + implicit none + integer, parameter :: begg = 2, endg = 4, natpft_size = 15 + real(r8), allocatable :: wt_nat_patch_expected(:,:) + real(r8), allocatable :: wt_nat_patch_in_out(:,:) ! used in subr. call + real(r8) :: expctd(9) + logical, allocatable :: do_not_collapse(:) + + ! Set relevant pftcon values to defaults; override where necessary + call pftcon%InitForTesting() + natpft_ub = natpft_size - 1 + allocate( wt_nat_patch(begg:endg,natpft_lb:natpft_ub) ) + allocate( wt_nat_patch_expected(begg:endg,natpft_lb:natpft_ub) ) + allocate( wt_nat_patch_in_out(begg:endg,natpft_lb:natpft_ub) ) + allocate( do_not_collapse(begg:endg) ) + + ! INPUT VALUES + wt_nat_patch(begg:,:) = 0._r8 ! initialize + wt_nat_patch(begg:,0) = (/ 30._r8, 40._r8, 0._r8/) ! pft0 + wt_nat_patch(begg:,1) = (/ 15._r8, 11._r8, 15._r8/) ! pft1 + wt_nat_patch(begg:,2) = (/ 5._r8, 5._r8, 5._r8/) ! pft2 + wt_nat_patch(begg:,3) = (/ 0._r8, 4._r8, 35._r8/) ! pft3 + wt_nat_patch(begg:,4) = (/ 10._r8, 10._r8, 35._r8/) ! pft4 + wt_nat_patch(begg:,5) = (/ 40._r8, 30._r8, 10._r8/) ! pft5 + wt_nat_patch(:,:) = wt_nat_patch(:,:) / 100._r8 + call check_sums_equal_1( wt_nat_patch, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + do_not_collapse(begg:) = .true. + + ! OUTPUT VALUES EXPECTED + wt_nat_patch_expected = wt_nat_patch + + call check_sums_equal_1( wt_nat_patch_expected, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + + ! Collapse pfts + wt_nat_patch_in_out = wt_nat_patch ! reset argument for next call + call collapse_to_dominant(wt_nat_patch_in_out(begg:endg,:), & + natpft_lb, natpft_ub, begg, endg, & + 1, & + do_not_collapse(begg:endg)) + + ! Now check that are correct + call check_sums_equal_1( wt_nat_patch_in_out, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + + @assertEqual(wt_nat_patch_in_out(begg:,:), wt_nat_patch_expected(begg:,:), tolerance=0._r8) + + deallocate( wt_nat_patch_expected ) + deallocate( wt_nat_patch_in_out ) + deallocate( wt_nat_patch ) + deallocate( do_not_collapse ) + + call pftcon%clean() + + end subroutine test_collapse_with_dont + + @Test subroutine test_collapse_crop_types_none() ! This test sets cftsize = 0, ie crops are lumped together with unmanaged From 02d2cf7927327bf703a88247ddc99cbc85bbdd9c Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 24 Jan 2024 15:44:32 -0700 Subject: [PATCH 134/153] Use collapse_to_dominant() in surfrd_hillslope(). For the Uniform and DominantPftLowland values of hillslope_pft_distribution_method --- .../include_user_mods | 1 + .../Hillslope_DominantPftLowland/user_nl_clm | 1 + src/main/surfrdMod.F90 | 70 +++++++------------ 3 files changed, 29 insertions(+), 43 deletions(-) create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods new file mode 100644 index 0000000000..fa2e50a80d --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods @@ -0,0 +1 @@ +../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm new file mode 100644 index 0000000000..4ab5c6cd56 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm @@ -0,0 +1 @@ +hillslope_pft_distribution_method = 'DominantPftLowland' diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 42534d418c..03a0082e97 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -896,11 +896,12 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) ! !USES: use clm_instur, only : ncolumns_hillslope, wt_nat_patch use clm_varctl, only : nhillslope,max_columns_hillslope - use clm_varpar, only : natpft_size, natpft_lb + use clm_varpar, only : natpft_size, natpft_lb, natpft_ub use ncdio_pio, only : ncd_inqdid, ncd_inqdlen use pftconMod , only : noveg use HillslopeHydrologyMod, only : pft_distribution_method, pft_standard, pft_from_file, pft_uniform_dominant_pft, pft_lowland_dominant_pft, pft_lowland_upland use array_utils, only: find_k_max_indices + use surfrdUtilsMod, only: collapse_to_dominant ! ! !ARGUMENTS: @@ -916,6 +917,8 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) logical :: readvar ! is variable on dataset integer,pointer :: arrayl(:) ! local array (needed because ncd_io expects a pointer) character(len=32) :: subname = 'surfrd_hillslope' ! subroutine name + logical, allocatable :: do_not_collapse(:) + integer :: n_dominant !----------------------------------------------------------------------- ! number of hillslopes per landunit @@ -960,52 +963,33 @@ subroutine surfrd_hillslope(begg, endg, ncid, ns) endif enddo - ! pft_uniform_dominant_pft uses the patch with the - ! largest weight for all hillslope columns in the gridcell - else if (pft_distribution_method == pft_uniform_dominant_pft) then - allocate(max_indices(1)) - do g = begg, endg - ! If hillslopes will be used in a gridcell, modify wt_nat_patch, - ! otherwise use original patch distribution - if(ncolumns_hillslope(g) > 0) then - - call find_k_max_indices(wt_nat_patch(g,:),natpft_lb,1,max_indices) - wt_nat_patch(g,:) = 0._r8 - wt_nat_patch(g,max_indices(1)) = 100._r8 + else if (pft_distribution_method == pft_uniform_dominant_pft & + .or. pft_distribution_method == pft_lowland_dominant_pft) then - endif - enddo - deallocate(max_indices) - - ! pft_lowland_dominant_pft uses the two patches with the - ! largest weights for the hillslope columns in the gridcell - else if (pft_distribution_method == pft_lowland_dominant_pft) then - allocate(max_indices(2)) + ! If hillslopes will be used in a gridcell, modify wt_nat_patch, + ! otherwise use original patch distribution + allocate(do_not_collapse(begg:endg)) + do_not_collapse(begg:endg) = .false. do g = begg, endg - ! If hillslopes will be used in a gridcell, modify wt_nat_patch, otherwise use original patch distribution - if(ncolumns_hillslope(g) > 0) then + if (ncolumns_hillslope(g) == 0) then + do_not_collapse(g) = .true. + end if + end do - ! Preserve the relative weights of the largest and - ! next largest weights using arbitrarily chosen values - ! (i.e. 1 should be larger than 2) that sum to 100. - ! This will minimize memory usage while still allowing - ! HillslopeDominantLowlandPft to pick out the two largest patch types. - - call find_k_max_indices(wt_nat_patch(g,:),natpft_lb,2,max_indices) - ! check that 2nd index weight is non-zero - if (wt_nat_patch(g,max_indices(2)) > 0._r8) then - wt_nat_patch(g,:) = 0._r8 - wt_nat_patch(g,max_indices(1)) = 75._r8 - wt_nat_patch(g,max_indices(2)) = 25._r8 - else - ! if only one pft exists, set its weight to 100 per cent - wt_nat_patch(g,:) = 0._r8 - wt_nat_patch(g,max_indices(1)) = 100._r8 - endif + if (pft_distribution_method == pft_uniform_dominant_pft) then + ! pft_uniform_dominant_pft uses the patch with the + ! largest weight for all hillslope columns in the gridcell + n_dominant = 1 + else if (pft_distribution_method == pft_lowland_dominant_pft) then + ! pft_lowland_dominant_pft uses the two patches with the + ! largest weights for the hillslope columns in the gridcell + n_dominant = 2 + else + call endrun( msg=' ERROR: unrecognized hillslope_pft_distribution_method'//errMsg(sourcefile, __LINE__)) + end if - endif - enddo - deallocate(max_indices) + call collapse_to_dominant(wt_nat_patch(begg:endg,:), natpft_lb, natpft_ub, begg, endg, n_dominant, do_not_collapse) + deallocate(do_not_collapse) else if (pft_distribution_method /= pft_standard) then call endrun( msg=' ERROR: unrecognized hillslope_pft_distribution_method'//errMsg(sourcefile, __LINE__)) From fd5ed375faab006d62979f5123de57f85137474d Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 13:30:36 -0700 Subject: [PATCH 135/153] Functionize & unit-test HillslopeSoilThicknessProfile_linear(). Squash-"merge" of hillslope_hydrology-functionize_linear into hillslope_hydrology-ssr3 --- src/biogeophys/CMakeLists.txt | 1 + src/biogeophys/HillslopeHydrologyMod.F90 | 27 +-- src/biogeophys/HillslopeHydrologyUtilsMod.F90 | 76 ++++++++ src/biogeophys/test/CMakeLists.txt | 1 + .../HillslopeHydrology_test/CMakeLists.txt | 6 + .../test_hillslopehydrologyUtils.pf | 168 ++++++++++++++++++ 6 files changed, 254 insertions(+), 25 deletions(-) create mode 100644 src/biogeophys/HillslopeHydrologyUtilsMod.F90 create mode 100644 src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt create mode 100644 src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf diff --git a/src/biogeophys/CMakeLists.txt b/src/biogeophys/CMakeLists.txt index 3cf5e0eaf0..2ffc346670 100644 --- a/src/biogeophys/CMakeLists.txt +++ b/src/biogeophys/CMakeLists.txt @@ -8,6 +8,7 @@ list(APPEND clm_sources CanopyStateType.F90 EnergyFluxType.F90 GlacierSurfaceMassBalanceMod.F90 + HillslopeHydrologyUtilsMod.F90 HumanIndexMod.F90 InfiltrationExcessRunoffMod.F90 IrrigationMod.F90 diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 4c5a27728c..42a144d4fd 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -14,6 +14,7 @@ module HillslopeHydrologyMod use clm_varctl , only : use_hillslope_routing use decompMod , only : bounds_type use clm_varcon , only : rpi + use HillslopeHydrologyUtilsMod, only : HillslopeSoilThicknessProfile_linear ! !PUBLIC TYPES: implicit none @@ -703,7 +704,6 @@ subroutine HillslopeSoilThicknessProfile(bounds,& real(r8) :: soil_depth_upland real(r8), parameter :: soil_depth_lowland_default = 8.0 real(r8), parameter :: soil_depth_upland_default = 8.0 - real(r8), parameter :: toosmall_distance = 1e-6 character(len=*), parameter :: subname = 'HillslopeSoilThicknessProfile' @@ -746,30 +746,7 @@ subroutine HillslopeSoilThicknessProfile(bounds,& end do ! Linear soil thickness profile else if (soil_profile_method == soil_profile_linear) then - do l = bounds%begl,bounds%endl - min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) - max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) - - if (abs(max_hill_dist - min_hill_dist) > toosmall_distance) then - m = (soil_depth_lowland - soil_depth_upland)/ & - (max_hill_dist - min_hill_dist) - else - m = 0._r8 - end if - b = soil_depth_upland - - do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c) .and. col%active(c)) then - soil_depth_col = m*(max_hill_dist - col%hill_distance(c)) + b - - do j = 1,nlevsoi - if ((zisoi(j-1) < soil_depth_col) .and. (zisoi(j) >= soil_depth_col)) then - col%nbedrock(c) = j - end if - enddo - end if - enddo - enddo + call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) else if (masterproc) then call endrun( 'ERROR:: invalid soil_profile_method.'//errmsg(sourcefile, __LINE__) ) end if diff --git a/src/biogeophys/HillslopeHydrologyUtilsMod.F90 b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 new file mode 100644 index 0000000000..07b123c4b9 --- /dev/null +++ b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 @@ -0,0 +1,76 @@ +module HillslopeHydrologyUtilsMod + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Utilities used in HillslopeHydrologyMod + ! + ! !USES: +#include "shr_assert.h" + use decompMod , only : bounds_type + use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc, iam + use abortutils , only : endrun + use clm_varctl , only : iulog + + ! !PUBLIC TYPES: + implicit none + + private + save + + ! !PUBLIC MEMBER FUNCTIONS: + public HillslopeSoilThicknessProfile_linear + +contains + + !------------------------------------------------------------------------ + subroutine HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) + ! + ! !DESCRIPTION: + ! Modify soil thickness across hillslope by changing + ! nbedrock according to the "Linear" method + ! + ! !USES: + use LandunitType , only : lun + use ColumnType , only : col + use clm_varpar , only : nlevsoi + use clm_varcon , only : zisoi + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds + real(r8), intent(in) :: soil_depth_lowland, soil_depth_upland + ! + ! !LOCAL VARIABLES + real(r8) :: min_hill_dist, max_hill_dist + real(r8) :: soil_depth_col + real(r8) :: m, b + integer :: c, j, l + real(r8), parameter :: toosmall_distance = 1e-6 + + do l = bounds%begl,bounds%endl + min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) + max_hill_dist = maxval(col%hill_distance(lun%coli(l):lun%colf(l))) + + if (abs(max_hill_dist - min_hill_dist) > toosmall_distance) then + m = (soil_depth_lowland - soil_depth_upland)/ & + (max_hill_dist - min_hill_dist) + else + m = 0._r8 + end if + b = soil_depth_upland + + do c = lun%coli(l), lun%colf(l) + write(iulog, *) 'c = ',c + if (col%is_hillslope_column(c) .and. col%active(c)) then + soil_depth_col = m*(max_hill_dist - col%hill_distance(c)) + b + do j = 1,nlevsoi + if ((zisoi(j-1) < soil_depth_col) .and. (zisoi(j) >= soil_depth_col)) then + col%nbedrock(c) = j + end if + enddo + end if + enddo + enddo + end subroutine HillslopeSoilThicknessProfile_linear +end module HillslopeHydrologyUtilsMod \ No newline at end of file diff --git a/src/biogeophys/test/CMakeLists.txt b/src/biogeophys/test/CMakeLists.txt index 49f80533de..5c15858210 100644 --- a/src/biogeophys/test/CMakeLists.txt +++ b/src/biogeophys/test/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(Daylength_test) add_subdirectory(Irrigation_test) add_subdirectory(HumanStress_test) +add_subdirectory(HillslopeHydrology_test) add_subdirectory(SnowHydrology_test) add_subdirectory(Photosynthesis_test) add_subdirectory(Balance_test) diff --git a/src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt b/src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt new file mode 100644 index 0000000000..f40baf96ed --- /dev/null +++ b/src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt @@ -0,0 +1,6 @@ +set (pfunit_sources + test_hillslopehydrologyUtils.pf) + +add_pfunit_ctest(HillslopeHydrologyUtils + TEST_SOURCES "${pfunit_sources}" + LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) diff --git a/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf b/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf new file mode 100644 index 0000000000..d870c98489 --- /dev/null +++ b/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf @@ -0,0 +1,168 @@ +module test_hillslopehydrologyUtils + + ! Tests of the HillslopeHydrologyUtils module + + use funit + use unittestSubgridMod + use ColumnType , only : col + use LandunitType , only : lun + use landunit_varcon , only : istwet + use decompMod , only : bounds_type + use clm_varpar , only : nlevgrnd + use shr_kind_mod , only : r8 => shr_kind_r8 + use HillslopeHydrologyUtilsMod, only : HillslopeSoilThicknessProfile_linear + + implicit none + + ! From clm_instInit + real(r8), parameter :: soil_depth_lowland = 8.5_r8 + real(r8), parameter :: soil_depth_upland = 2._r8 + + integer, parameter :: nbedrock_dummy_value = 9999 + + @TestCase + type, extends(TestCase) :: TestInit + contains + procedure :: setUp + procedure :: tearDown + end type TestInit + +contains + + subroutine setUp(this) + ! Set up variables needed for tests: various subgrid type variables, along with + ! bounds. + ! + use clm_varcon, only: clm_varcon_init, zisoi + use clm_varpar, only: nlevsoi, nlevgrnd + class(TestInit), intent(inout) :: this + integer :: g, l, c + real(r8), allocatable :: my_zisoi(:) + + ! Set up subgrid structure + ! The weights (of both landunits and columns) and column types in the following are + ! arbitrary, since they are not important for these tests + + call unittest_subgrid_setup_start() + + ! Set up gridcell with one landunit and two columns + call unittest_add_gridcell() + call unittest_add_landunit(my_gi=gi, ltype=istwet, wtgcell=0.25_r8) + call unittest_add_column(my_li=li, ctype=1, wtlunit=0.5_r8) + call unittest_add_column(my_li=li, ctype=1, wtlunit=0.5_r8) + + call unittest_subgrid_setup_end() + + ! These will be enabled by specific tests + col%active(begc:endc) = .false. + col%is_hillslope_column(begc:endc) = .false. + + ! Set up ground/soil structure + nlevsoi = 5 + allocate(my_zisoi(1:nlevsoi)) + my_zisoi = [0.01_r8, 0.02_r8, 2._r8, 4._r8, 6._r8] + nlevgrnd = size(my_zisoi) + call clm_varcon_init( is_simple_buildtemp = .true.) + zisoi(0) = 0._r8 + zisoi(1:nlevgrnd) = my_zisoi(:) + col%nbedrock(bounds%begc:bounds%endc) = nbedrock_dummy_value + + ! Set up hill_distance + l = bounds%begl + do c = lun%coli(l), lun%colf(l) + col%hill_distance(c) = real(c, kind=r8) + end do + + deallocate(my_zisoi) + + end subroutine setUp + + subroutine tearDown(this) + ! clean up stuff set up in setup() + use clm_varcon, only: clm_varcon_clean + class(TestInit), intent(inout) :: this + + call unittest_subgrid_teardown() + call clm_varcon_clean() + + end subroutine tearDown + + @Test + subroutine test_HillslopeSoilThicknessProfile_linear(this) + class(TestInit), intent(inout) :: this + integer, allocatable :: nbedrock_expected(:) + integer :: l, c + + l = bounds%begl + + col%active(bounds%begc:bounds%endc) = .true. + col%is_hillslope_column(bounds%begc:bounds%endc) = .true. + + ! Get expected values + ! Layer 1 soil_depth_col = 8.5 + ! Layer 2 soil_depth_col = 2.0 + allocate(nbedrock_expected(bounds%begc:bounds%endc)) + nbedrock_expected(lun%coli(l)) = 9999 + nbedrock_expected(lun%coli(l) + 1) = 3 + + call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) + + @assertEqual(nbedrock_expected(lun%coli(l):lun%colf(l)), col%nbedrock(lun%coli(l):lun%colf(l))) + + deallocate(nbedrock_expected) + + end subroutine test_HillslopeSoilThicknessProfile_linear + + @Test + subroutine test_HillslopeSoilThicknessProfile_linear_inactive(this) + class(TestInit), intent(inout) :: this + integer, allocatable :: nbedrock_expected(:) + integer :: l, c + + l = bounds%begl + + col%active(bounds%begc:bounds%endc) = .false. + col%is_hillslope_column(bounds%begc:bounds%endc) = .true. + + ! Get expected values + ! Layer 1 soil_depth_col = 8.5 + ! Layer 2 soil_depth_col = 2.0, but not active + allocate(nbedrock_expected(bounds%begc:bounds%endc)) + nbedrock_expected(lun%coli(l)) = 9999 + nbedrock_expected(lun%coli(l) + 1) = 9999 + + call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) + + @assertEqual(nbedrock_expected(lun%coli(l):lun%colf(l)), col%nbedrock(lun%coli(l):lun%colf(l))) + + deallocate(nbedrock_expected) + + end subroutine test_HillslopeSoilThicknessProfile_linear_inactive + + @Test + subroutine test_HillslopeSoilThicknessProfile_linear_nohillslope(this) + class(TestInit), intent(inout) :: this + integer, allocatable :: nbedrock_expected(:) + integer :: l, c + + l = bounds%begl + + col%active(bounds%begc:bounds%endc) = .true. + col%is_hillslope_column(bounds%begc:bounds%endc) = .false. + + ! Get expected values + ! Layer 1 soil_depth_col = 8.5 + ! Layer 2 soil_depth_col = 2.0, but not is_hillslope_column + allocate(nbedrock_expected(bounds%begc:bounds%endc)) + nbedrock_expected(lun%coli(l)) = 9999 + nbedrock_expected(lun%coli(l) + 1) = 9999 + + call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) + + @assertEqual(nbedrock_expected(lun%coli(l):lun%colf(l)), col%nbedrock(lun%coli(l):lun%colf(l))) + + deallocate(nbedrock_expected) + + end subroutine test_HillslopeSoilThicknessProfile_linear_nohillslope + +end module test_hillslopehydrologyUtils From 6513894996f1f2fc75393c897f527ec821e11bce Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 15:53:16 -0700 Subject: [PATCH 136/153] Remove a leftover troubleshooting write(). --- src/biogeophys/HillslopeHydrologyUtilsMod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/biogeophys/HillslopeHydrologyUtilsMod.F90 b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 index 07b123c4b9..89bf1418f4 100644 --- a/src/biogeophys/HillslopeHydrologyUtilsMod.F90 +++ b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 @@ -61,7 +61,6 @@ subroutine HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil b = soil_depth_upland do c = lun%coli(l), lun%colf(l) - write(iulog, *) 'c = ',c if (col%is_hillslope_column(c) .and. col%active(c)) then soil_depth_col = m*(max_hill_dist - col%hill_distance(c)) + b do j = 1,nlevsoi From b84720c787b80143d7140db4a6c877bee6f4db44 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 15:54:40 -0700 Subject: [PATCH 137/153] Exit early from loop in HillslopeSoilThicknessProfile_linear(). --- src/biogeophys/HillslopeHydrologyUtilsMod.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/biogeophys/HillslopeHydrologyUtilsMod.F90 b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 index 89bf1418f4..7c78f7d53f 100644 --- a/src/biogeophys/HillslopeHydrologyUtilsMod.F90 +++ b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 @@ -66,6 +66,7 @@ subroutine HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil do j = 1,nlevsoi if ((zisoi(j-1) < soil_depth_col) .and. (zisoi(j) >= soil_depth_col)) then col%nbedrock(c) = j + exit end if enddo end if From b426ce1e65d30e13042e6744780c78d9baeaa52e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 16:10:28 -0700 Subject: [PATCH 138/153] Better unit testing of HillslopeSoilThicknessProfile_linear(). --- src/biogeophys/HillslopeHydrologyUtilsMod.F90 | 13 +- .../test_hillslopehydrologyUtils.pf | 111 +++++++++++++++--- 2 files changed, 107 insertions(+), 17 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyUtilsMod.F90 b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 index 7c78f7d53f..299971055c 100644 --- a/src/biogeophys/HillslopeHydrologyUtilsMod.F90 +++ b/src/biogeophys/HillslopeHydrologyUtilsMod.F90 @@ -19,13 +19,15 @@ module HillslopeHydrologyUtilsMod private save + real(r8), parameter :: toosmall_distance_default = 1e-6 + ! !PUBLIC MEMBER FUNCTIONS: public HillslopeSoilThicknessProfile_linear contains !------------------------------------------------------------------------ - subroutine HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) + subroutine HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland, toosmall_distance_in) ! ! !DESCRIPTION: ! Modify soil thickness across hillslope by changing @@ -40,13 +42,20 @@ subroutine HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds real(r8), intent(in) :: soil_depth_lowland, soil_depth_upland + real(r8), intent(in), optional :: toosmall_distance_in ! ! !LOCAL VARIABLES real(r8) :: min_hill_dist, max_hill_dist + real(r8) :: toosmall_distance real(r8) :: soil_depth_col real(r8) :: m, b integer :: c, j, l - real(r8), parameter :: toosmall_distance = 1e-6 + + if (present(toosmall_distance_in)) then + toosmall_distance = toosmall_distance_in + else + toosmall_distance = toosmall_distance_default + end if do l = bounds%begl,bounds%endl min_hill_dist = minval(col%hill_distance(lun%coli(l):lun%colf(l))) diff --git a/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf b/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf index d870c98489..3f626e1fa2 100644 --- a/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf +++ b/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf @@ -8,7 +8,7 @@ module test_hillslopehydrologyUtils use LandunitType , only : lun use landunit_varcon , only : istwet use decompMod , only : bounds_type - use clm_varpar , only : nlevgrnd + use clm_varpar , only : nlevsoi, nlevgrnd use shr_kind_mod , only : r8 => shr_kind_r8 use HillslopeHydrologyUtilsMod, only : HillslopeSoilThicknessProfile_linear @@ -33,11 +33,8 @@ contains ! Set up variables needed for tests: various subgrid type variables, along with ! bounds. ! - use clm_varcon, only: clm_varcon_init, zisoi - use clm_varpar, only: nlevsoi, nlevgrnd class(TestInit), intent(inout) :: this integer :: g, l, c - real(r8), allocatable :: my_zisoi(:) ! Set up subgrid structure ! The weights (of both landunits and columns) and column types in the following are @@ -57,23 +54,12 @@ contains col%active(begc:endc) = .false. col%is_hillslope_column(begc:endc) = .false. - ! Set up ground/soil structure - nlevsoi = 5 - allocate(my_zisoi(1:nlevsoi)) - my_zisoi = [0.01_r8, 0.02_r8, 2._r8, 4._r8, 6._r8] - nlevgrnd = size(my_zisoi) - call clm_varcon_init( is_simple_buildtemp = .true.) - zisoi(0) = 0._r8 - zisoi(1:nlevgrnd) = my_zisoi(:) - col%nbedrock(bounds%begc:bounds%endc) = nbedrock_dummy_value - ! Set up hill_distance l = bounds%begl do c = lun%coli(l), lun%colf(l) col%hill_distance(c) = real(c, kind=r8) end do - deallocate(my_zisoi) end subroutine setUp @@ -87,6 +73,42 @@ contains end subroutine tearDown + ! Set up ground/soil structure + subroutine ground_a(bounds) + use clm_varcon, only: clm_varcon_init, zisoi + type(bounds_type), intent(in) :: bounds + real(r8), allocatable :: my_zisoi(:) + + nlevsoi = 5 + allocate(my_zisoi(1:nlevsoi)) + my_zisoi = [0.01_r8, 0.02_r8, 2._r8, 4._r8, 6._r8] + nlevgrnd = size(my_zisoi) + call clm_varcon_init( is_simple_buildtemp = .true.) + zisoi(0) = 0._r8 + zisoi(1:nlevgrnd) = my_zisoi(:) + col%nbedrock(bounds%begc:bounds%endc) = nbedrock_dummy_value + + deallocate(my_zisoi) + end subroutine ground_a + + ! Set up ground/soil structure + subroutine ground_b(bounds) + use clm_varcon, only: clm_varcon_init, zisoi + type(bounds_type), intent(in) :: bounds + real(r8), allocatable :: my_zisoi(:) + + nlevsoi = 3 + allocate(my_zisoi(1:nlevsoi)) + my_zisoi = [0.01_r8, 0.02_r8, 1._r8] + nlevgrnd = size(my_zisoi) + call clm_varcon_init( is_simple_buildtemp = .true.) + zisoi(0) = 0._r8 + zisoi(1:nlevgrnd) = my_zisoi(:) + col%nbedrock(bounds%begc:bounds%endc) = nbedrock_dummy_value + + deallocate(my_zisoi) + end subroutine ground_b + @Test subroutine test_HillslopeSoilThicknessProfile_linear(this) class(TestInit), intent(inout) :: this @@ -95,6 +117,7 @@ contains l = bounds%begl + call ground_a(bounds) col%active(bounds%begc:bounds%endc) = .true. col%is_hillslope_column(bounds%begc:bounds%endc) = .true. @@ -113,6 +136,62 @@ contains end subroutine test_HillslopeSoilThicknessProfile_linear + @Test + subroutine test_HillslopeSoilThicknessProfile_linear_tooshallow(this) + class(TestInit), intent(inout) :: this + integer, allocatable :: nbedrock_expected(:) + integer :: l, c + + l = bounds%begl + + call ground_b(bounds) + col%active(bounds%begc:bounds%endc) = .true. + col%is_hillslope_column(bounds%begc:bounds%endc) = .true. + + ! Get expected values + ! Layer 1 soil_depth_col = 8.5 + ! Layer 2 soil_depth_col = 2.0; still too deep for ground_b() + allocate(nbedrock_expected(bounds%begc:bounds%endc)) + nbedrock_expected(lun%coli(l)) = 9999 + nbedrock_expected(lun%coli(l) + 1) = 9999 + + call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) + + @assertEqual(nbedrock_expected(lun%coli(l):lun%colf(l)), col%nbedrock(lun%coli(l):lun%colf(l))) + + deallocate(nbedrock_expected) + + end subroutine test_HillslopeSoilThicknessProfile_linear_tooshallow + + @Test + subroutine test_HillslopeSoilThicknessProfile_linear_noslope(this) + class(TestInit), intent(inout) :: this + integer, allocatable :: nbedrock_expected(:) + integer :: l, c + real(r8) :: toosmall_distance + + l = bounds%begl + + call ground_a(bounds) + col%active(bounds%begc:bounds%endc) = .true. + col%is_hillslope_column(bounds%begc:bounds%endc) = .true. + + ! Get expected values, setting toosmall_distance to something high enough that the (abs(max_hill_dist - min_hill_dist) > toosmall_distance) conditional will fail, causing m = 0.0 + toosmall_distance = 100._r8 + ! Layer 1 soil_depth_col = 2.0 + ! Layer 2 soil_depth_col = 2.0 + allocate(nbedrock_expected(bounds%begc:bounds%endc)) + nbedrock_expected(lun%coli(l)) = 3 + nbedrock_expected(lun%coli(l) + 1) = 3 + + call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland, toosmall_distance_in=toosmall_distance) + + @assertEqual(nbedrock_expected(lun%coli(l):lun%colf(l)), col%nbedrock(lun%coli(l):lun%colf(l))) + + deallocate(nbedrock_expected) + + end subroutine test_HillslopeSoilThicknessProfile_linear_noslope + @Test subroutine test_HillslopeSoilThicknessProfile_linear_inactive(this) class(TestInit), intent(inout) :: this @@ -121,6 +200,7 @@ contains l = bounds%begl + call ground_a(bounds) col%active(bounds%begc:bounds%endc) = .false. col%is_hillslope_column(bounds%begc:bounds%endc) = .true. @@ -147,6 +227,7 @@ contains l = bounds%begl + call ground_a(bounds) col%active(bounds%begc:bounds%endc) = .true. col%is_hillslope_column(bounds%begc:bounds%endc) = .false. From 65ac6155442559a98a9eb51d242991f116fd7a36 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 16:29:09 -0700 Subject: [PATCH 139/153] Cleanup in HillslopeHydrologyUtils test. --- .../test_hillslopehydrologyUtils.pf | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf b/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf index 3f626e1fa2..63db42cffd 100644 --- a/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf +++ b/src/biogeophys/test/HillslopeHydrology_test/test_hillslopehydrologyUtils.pf @@ -122,10 +122,10 @@ contains col%is_hillslope_column(bounds%begc:bounds%endc) = .true. ! Get expected values - ! Layer 1 soil_depth_col = 8.5 - ! Layer 2 soil_depth_col = 2.0 + ! Column 1 soil_depth_col = 8.5 + ! Column 2 soil_depth_col = 2.0 allocate(nbedrock_expected(bounds%begc:bounds%endc)) - nbedrock_expected(lun%coli(l)) = 9999 + nbedrock_expected(lun%coli(l)) = nbedrock_dummy_value nbedrock_expected(lun%coli(l) + 1) = 3 call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) @@ -149,11 +149,11 @@ contains col%is_hillslope_column(bounds%begc:bounds%endc) = .true. ! Get expected values - ! Layer 1 soil_depth_col = 8.5 - ! Layer 2 soil_depth_col = 2.0; still too deep for ground_b() + ! Column 1 soil_depth_col = 8.5 + ! Column 2 soil_depth_col = 2.0; still too deep for ground_b() allocate(nbedrock_expected(bounds%begc:bounds%endc)) - nbedrock_expected(lun%coli(l)) = 9999 - nbedrock_expected(lun%coli(l) + 1) = 9999 + nbedrock_expected(lun%coli(l)) = nbedrock_dummy_value + nbedrock_expected(lun%coli(l) + 1) = nbedrock_dummy_value call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) @@ -178,8 +178,8 @@ contains ! Get expected values, setting toosmall_distance to something high enough that the (abs(max_hill_dist - min_hill_dist) > toosmall_distance) conditional will fail, causing m = 0.0 toosmall_distance = 100._r8 - ! Layer 1 soil_depth_col = 2.0 - ! Layer 2 soil_depth_col = 2.0 + ! Column 1 soil_depth_col = 2.0 + ! Column 2 soil_depth_col = 2.0 allocate(nbedrock_expected(bounds%begc:bounds%endc)) nbedrock_expected(lun%coli(l)) = 3 nbedrock_expected(lun%coli(l) + 1) = 3 @@ -205,11 +205,11 @@ contains col%is_hillslope_column(bounds%begc:bounds%endc) = .true. ! Get expected values - ! Layer 1 soil_depth_col = 8.5 - ! Layer 2 soil_depth_col = 2.0, but not active + ! Column 1 soil_depth_col = 8.5 + ! Column 2 soil_depth_col = 2.0, but not active allocate(nbedrock_expected(bounds%begc:bounds%endc)) - nbedrock_expected(lun%coli(l)) = 9999 - nbedrock_expected(lun%coli(l) + 1) = 9999 + nbedrock_expected(lun%coli(l)) = nbedrock_dummy_value + nbedrock_expected(lun%coli(l) + 1) = nbedrock_dummy_value call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) @@ -232,11 +232,11 @@ contains col%is_hillslope_column(bounds%begc:bounds%endc) = .false. ! Get expected values - ! Layer 1 soil_depth_col = 8.5 - ! Layer 2 soil_depth_col = 2.0, but not is_hillslope_column + ! Column 1 soil_depth_col = 8.5 + ! Column 2 soil_depth_col = 2.0, but not is_hillslope_column allocate(nbedrock_expected(bounds%begc:bounds%endc)) - nbedrock_expected(lun%coli(l)) = 9999 - nbedrock_expected(lun%coli(l) + 1) = 9999 + nbedrock_expected(lun%coli(l)) = nbedrock_dummy_value + nbedrock_expected(lun%coli(l) + 1) = nbedrock_dummy_value call HillslopeSoilThicknessProfile_linear(bounds, soil_depth_lowland, soil_depth_upland) From 689a5508f0e0a237e006ffcd64d1b7e1112255ff Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 16:32:21 -0700 Subject: [PATCH 140/153] Rename to test_collapse_to_dom_do_not_collapse. --- src/main/test/surfrdUtils_test/test_surfrdUtils.pf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf index 53cc1c975e..542ceeddbd 100644 --- a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf +++ b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf @@ -572,7 +572,7 @@ contains @Test - subroutine test_collapse_with_dont() + subroutine test_collapse_to_dom_do_not_collapse() ! Tests subroutine collapse_to_dominant when used with an optional logical array indicating which gridcells should actually be collapsed ! use pftconMod, only: pftcon @@ -633,7 +633,7 @@ contains call pftcon%clean() - end subroutine test_collapse_with_dont + end subroutine test_collapse_to_dom_do_not_collapse @Test From 1c8b468d184d42f3a7d7560887f6ae96e204868f Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 16:37:02 -0700 Subject: [PATCH 141/153] Add test_collapse_to_dom_do_not_collapse_present_false. --- .../test/surfrdUtils_test/test_surfrdUtils.pf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf index 542ceeddbd..ae5685c87b 100644 --- a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf +++ b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf @@ -636,6 +636,77 @@ contains end subroutine test_collapse_to_dom_do_not_collapse + @Test + subroutine test_collapse_to_dom_do_not_collapse_present_false() + ! Tests subroutine collapse_to_dominant when used with an optional logical array indicating which gridcells should actually be collapsed + ! + use pftconMod, only: pftcon + use clm_instur, only: wt_nat_patch + use clm_varpar, only: natpft_lb, natpft_ub + + implicit none + integer, parameter :: begg = 2, endg = 4, natpft_size = 15 + real(r8), allocatable :: wt_nat_patch_expected(:,:) + real(r8), allocatable :: wt_nat_patch_in_out(:,:) ! used in subr. call + real(r8) :: expctd(9) + logical, allocatable :: do_not_collapse(:) + + ! Set relevant pftcon values to defaults; override where necessary + call pftcon%InitForTesting() + natpft_ub = natpft_size - 1 + allocate( wt_nat_patch(begg:endg,natpft_lb:natpft_ub) ) + allocate( wt_nat_patch_expected(begg:endg,natpft_lb:natpft_ub) ) + allocate( wt_nat_patch_in_out(begg:endg,natpft_lb:natpft_ub) ) + allocate( do_not_collapse(begg:endg) ) + + ! INPUT VALUES + wt_nat_patch(begg:,:) = 0._r8 ! initialize + wt_nat_patch(begg:,0) = (/ 30._r8, 40._r8, 0._r8/) ! pft0 + wt_nat_patch(begg:,1) = (/ 15._r8, 11._r8, 15._r8/) ! pft1 + wt_nat_patch(begg:,2) = (/ 5._r8, 5._r8, 5._r8/) ! pft2 + wt_nat_patch(begg:,3) = (/ 0._r8, 4._r8, 35._r8/) ! pft3 + wt_nat_patch(begg:,4) = (/ 10._r8, 10._r8, 35._r8/) ! pft4 + wt_nat_patch(begg:,5) = (/ 40._r8, 30._r8, 10._r8/) ! pft5 + wt_nat_patch(:,:) = wt_nat_patch(:,:) / 100._r8 + call check_sums_equal_1( wt_nat_patch, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + do_not_collapse(begg:) = .false. + + ! OUTPUT VALUES EXPECTED + expctd(1) = 40._r8 / 40._r8 + expctd(2) = 35._r8 / 35._r8 + wt_nat_patch_expected(begg:,:) = 0._r8 ! initialize + wt_nat_patch_expected(begg:,0) = (/ 0._r8, expctd(1), 0._r8 /) ! pft 0 + wt_nat_patch_expected(begg:,3) = (/ 0._r8, 0._r8, expctd(2) /) ! pft 3 + wt_nat_patch_expected(begg:,5) = (/ expctd(1), 0._r8, 0._r8 /) ! pft 5 + + + call check_sums_equal_1( wt_nat_patch_expected, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + + ! Collapse pfts + wt_nat_patch_in_out = wt_nat_patch ! reset argument for next call + call collapse_to_dominant(wt_nat_patch_in_out(begg:endg,:), & + natpft_lb, natpft_ub, begg, endg, & + 1, & + do_not_collapse(begg:endg)) + + ! Now check that are correct + call check_sums_equal_1( wt_nat_patch_in_out, begg, "test_check_sums_add_to_1", & + "should not trigger an error") + + @assertEqual(wt_nat_patch_in_out(begg:,:), wt_nat_patch_expected(begg:,:), tolerance=0._r8) + + deallocate( wt_nat_patch_expected ) + deallocate( wt_nat_patch_in_out ) + deallocate( wt_nat_patch ) + deallocate( do_not_collapse ) + + call pftcon%clean() + + end subroutine test_collapse_to_dom_do_not_collapse_present_false + + @Test subroutine test_collapse_crop_types_none() ! This test sets cftsize = 0, ie crops are lumped together with unmanaged From 0ce76f0526de9b80143bf2c5656b6aff034db2a0 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 16:48:51 -0700 Subject: [PATCH 142/153] Fix expected vs. actual in assertEqual() in test_surfrdUtils. --- .../test/surfrdUtils_test/test_surfrdUtils.pf | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf index ae5685c87b..f2fcae7af9 100644 --- a/src/main/test/surfrdUtils_test/test_surfrdUtils.pf +++ b/src/main/test/surfrdUtils_test/test_surfrdUtils.pf @@ -129,7 +129,7 @@ contains call check_sums_equal_1( wt_in_out, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_in_out(begg:,:), wt_expected(begg:,:), tolerance=tol) + @assertEqual(wt_expected(begg:,:), wt_in_out(begg:,:), tolerance=tol) deallocate( wt_expected ) deallocate( wt_in_out ) @@ -249,7 +249,7 @@ contains call check_sums_equal_1( wt_in_out, begg, "test_check_sums_add_to_1", & "should not trigger an error for wt_in_out") - @assertEqual(wt_in_out(begg:,:), wt_expected(begg:,:), tolerance=tol) + @assertEqual(wt_expected(begg:,:), wt_in_out(begg:,:), tolerance=tol) end do @@ -318,7 +318,7 @@ contains isturb_MIN, isturb_MAX, begg, endg, & n_dom_urban) - @assertEqual(wt_in_out(begg:,:), wt_expected(begg:,:), tolerance=tol) + @assertEqual(wt_expected(begg:,:), wt_in_out(begg:,:), tolerance=tol) deallocate( wt_expected ) deallocate( wt_in_out ) @@ -444,7 +444,7 @@ contains call check_sums_equal_1( wt_in_out, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_in_out(begg:,:), wt_expected(begg:,:), tolerance=tol) + @assertEqual(wt_expected(begg:,:), wt_in_out(begg:,:), tolerance=tol) end do ! loop of tests @@ -558,7 +558,7 @@ contains call check_sums_equal_1( wt_nat_patch_in_out, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_nat_patch_in_out(begg:,:), wt_nat_patch_expected(begg:,:), tolerance=tol) + @assertEqual(wt_nat_patch_expected(begg:,:), wt_nat_patch_in_out(begg:,:), tolerance=tol) end do ! loop of tests @@ -624,7 +624,7 @@ contains call check_sums_equal_1( wt_nat_patch_in_out, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_nat_patch_in_out(begg:,:), wt_nat_patch_expected(begg:,:), tolerance=0._r8) + @assertEqual(wt_nat_patch_expected(begg:,:), wt_nat_patch_in_out(begg:,:), tolerance=0._r8) deallocate( wt_nat_patch_expected ) deallocate( wt_nat_patch_in_out ) @@ -695,7 +695,7 @@ contains call check_sums_equal_1( wt_nat_patch_in_out, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_nat_patch_in_out(begg:,:), wt_nat_patch_expected(begg:,:), tolerance=0._r8) + @assertEqual(wt_nat_patch_expected(begg:,:), wt_nat_patch_in_out(begg:,:), tolerance=0._r8) deallocate( wt_nat_patch_expected ) deallocate( wt_nat_patch_in_out ) @@ -735,8 +735,8 @@ contains call collapse_crop_types( wt_cft, fert_cft, cftsize, begg, endg, verbose = .true.) ! Now check that are correct - @assertEqual(wt_cft(begg:,:), wt_cft_expected(begg:,:)) - @assertEqual(fert_cft(begg:,:), fert_cft_expected(begg:,:)) + @assertEqual(wt_cft_expected(begg:,:), wt_cft(begg:,:)) + @assertEqual(fert_cft_expected(begg:,:), fert_cft(begg:,:)) call pftcon%clean() end subroutine test_collapse_crop_types_none @@ -782,11 +782,11 @@ contains ! Now check that are correct call check_sums_equal_1( wt_cft/100.0_r8, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_cft(begg:,:), wt_cft_expected(begg:,:)) + @assertEqual(wt_cft_expected(begg:,:), wt_cft(begg:,:)) ! INTENTIONAL? As written, subr. collapse_crop_types does NOT take ! ----------- the avg fert_cft of the irrigated and unirrigated when ! irrigate = .false.. Assuming intentional for now. - @assertEqual(fert_cft(begg:,:), fert_cft_expected(begg:,:)) + @assertEqual(fert_cft_expected(begg:,:), fert_cft(begg:,:)) call pftcon%clean() end subroutine test_collapse_crop_types_16_to_15 @@ -831,8 +831,8 @@ contains ! Now check that are correct call check_sums_equal_1( wt_cft/100.0_r8, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_cft(begg:,:), wt_cft_expected(begg:,:)) - @assertEqual(fert_cft(begg:,:), fert_cft_expected(begg:,:)) + @assertEqual(wt_cft_expected(begg:,:), wt_cft(begg:,:)) + @assertEqual(fert_cft_expected(begg:,:), fert_cft(begg:,:)) call pftcon%clean() end subroutine test_collapse_crop_types_16_to_16 @@ -887,8 +887,8 @@ contains ! Now check that are correct call check_sums_equal_1( wt_cft/100.0_r8, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_cft(begg:,:2), wt_cft_expected(begg:,:2)) - @assertEqual(fert_cft(begg:,:2), fert_cft_expected(begg:,:2)) + @assertEqual(wt_cft_expected(begg:,:2), wt_cft(begg:,:2)) + @assertEqual(fert_cft_expected(begg:,:2), fert_cft(begg:,:2)) call pftcon%clean() end subroutine test_collapse_crop_types_18_to_16 @@ -943,8 +943,8 @@ contains ! Now check that are correct call check_sums_equal_1( wt_cft/100.0_r8, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_cft(begg:,:2), wt_cft_expected(begg:,:2)) - @assertEqual(fert_cft(begg:,1), fert_cft_expected(begg:,1)) + @assertEqual(wt_cft_expected(begg:,:2), wt_cft(begg:,:2)) + @assertEqual(fert_cft_expected(begg:,1), fert_cft(begg:,1)) call pftcon%clean() end subroutine test_collapse_crop_types_18_to_15 @@ -992,8 +992,8 @@ contains ! Now check that are correct call check_sums_equal_1( wt_cft/100.0_r8, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_cft(begg:,:), wt_cft_expected(begg:,:)) - @assertEqual(fert_cft(begg:,:), fert_cft_expected(begg:,:)) + @assertEqual(wt_cft_expected(begg:,:), wt_cft(begg:,:)) + @assertEqual(fert_cft_expected(begg:,:), fert_cft(begg:,:)) call pftcon%clean() end subroutine test_collapse_crop_types_18_to_18 @@ -1051,8 +1051,8 @@ contains ! Now check that are correct call check_sums_equal_1( wt_cft/100.0_r8, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_cft(begg:,:), wt_cft_expected(begg:,:)) - @assertEqual(fert_cft(begg:,:), fert_cft_expected(begg:,:)) + @assertEqual(wt_cft_expected(begg:,:), wt_cft(begg:,:)) + @assertEqual(fert_cft_expected(begg:,:), fert_cft(begg:,:)) call pftcon%clean() end subroutine test_collapse_crop_types_20_to_18 @@ -1109,7 +1109,7 @@ contains call check_sums_equal_1( wt_nat_patch, begg, "test_check_sums_add_to_1", & "should not trigger an error") @assertEqual(wtpft,wt_nat_patch) - @assertEqual(wt_lunit(begg:,istsoil),(/1.00_r8,1.00_r8/)) + @assertEqual((/1.00_r8,1.00_r8/), wt_lunit(begg:,istsoil)) deallocate( wt_nat_patch ) deallocate( wtpft ) @@ -1160,10 +1160,10 @@ contains "should not trigger an error") call check_sums_equal_1( wt_nat_patch, begg, "test_check_sums_add_to_1", & "should not trigger an error") - @assertEqual(wt_lunit(begg:,istsoil), (/1.00_r8,1.00_r8/)) - @assertEqual(wt_nat_patch(begg:,ndllf_evr_tmp_tree),(/0.25_r8,0.25_r8/)) - @assertEqual(wt_nat_patch(begg:,nc3crop), (/0.1875_r8,0.1875_r8/)) - @assertEqual(wt_nat_patch(begg:,nc3irrig), (/0.5625_r8,0.5625_r8/)) + @assertEqual((/1.00_r8,1.00_r8/), wt_lunit(begg:,istsoil)) + @assertEqual((/0.25_r8,0.25_r8/), wt_nat_patch(begg:,ndllf_evr_tmp_tree)) + @assertEqual((/0.1875_r8,0.1875_r8/), wt_nat_patch(begg:,nc3crop)) + @assertEqual((/0.5625_r8,0.5625_r8/), wt_nat_patch(begg:,nc3irrig)) call pftcon%clean() end subroutine test_convert_cft_to_pft @@ -1208,7 +1208,7 @@ contains array(lb+1,lb2+2) = array(lb+1,lb2+2) + eps call check_sums_equal_1( array, lb, "test_check_sums_add_to_1_fail", & "should trigger an error", ier) - @assertEqual(ier,-10) + @assertEqual(-10, ier) end subroutine test_check_sums_add_to_1_fail @Test subroutine test_renormalize @@ -1233,7 +1233,7 @@ contains ! Make the normalized result 100, so multiply the expected result by 100 expected(:,:) = expected(:,:)*100.0d00 call renormalize(array, lb, 100.0d00) - @assertEqual(array, expected, tolerance=tol) + @assertEqual(expected, array, tolerance=tol) ! divide by 100 and should add to one array = array / 100.0d00 call check_sums_equal_1( array, lb, "test_check_sums_add_to_1", & @@ -1241,7 +1241,7 @@ contains ! Call again returning error code, make sure error code is zero call check_sums_equal_1( array, lb, "test_check_sums_add_to_1", & "should not trigger an error", ier) - @assertEqual(ier,0) + @assertEqual(0, ier) end subroutine test_renormalize @Test @@ -1255,7 +1255,7 @@ contains array(:,:) = 0.0d00 expected(:,:) = array call renormalize(array, lb, 100.0d00) - @assertEqual(array, expected, tolerance=tol) + @assertEqual(expected, array, tolerance=tol) end subroutine test_renormalize_zero end module test_surfrdUtils From c36280c38be7eb9c3cd639f1cd96bd10d1a29ccd Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 17:55:02 -0700 Subject: [PATCH 143/153] Delete 'found on surface data set' msgs from HillslopeHydrologyMod. --- src/biogeophys/HillslopeHydrologyMod.F90 | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 42a144d4fd..11208e7228 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -367,9 +367,6 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='h_pftndx', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (readvar) then allocate(hill_pftndx (bounds%begl:bounds%endl,max_columns_hillslope), stat=ierr) - if (masterproc) then - write(iulog,*) 'h_pftndx found on surface data set' - end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_pftndx(l,:) = ihillslope_in(g,:) @@ -382,9 +379,6 @@ subroutine InitHillslope(bounds,fsurdat) allocate(fstream_in(bounds%begg:bounds%endg)) call ncd_io(ncid=ncid, varname='h_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then - if (masterproc) then - write(iulog,*) 'h_stream_depth found on surface data set' - end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) lun%stream_channel_depth(l) = fstream_in(g) @@ -394,9 +388,6 @@ subroutine InitHillslope(bounds,fsurdat) end if call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then - if (masterproc) then - write(iulog,*) 'h_stream_width found on surface data set' - end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) lun%stream_channel_width(l) = fstream_in(g) @@ -406,9 +397,6 @@ subroutine InitHillslope(bounds,fsurdat) end if call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (readvar) then - if (masterproc) then - write(iulog,*) 'h_stream_slope found on surface data set' - end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) lun%stream_channel_slope(l) = fstream_in(g) @@ -618,9 +606,6 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='h_bedrock', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (readvar) then - if (masterproc) then - write(iulog,*) 'h_bedrock found on surface data set' - end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) do c = lun%coli(l), lun%colf(l) From 0df44c944fb0df7a8d518d12aa6c1d24af6ce53d Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 18:00:39 -0700 Subject: [PATCH 144/153] Reduce nesting in HillslopeHydrologyMod. --- src/biogeophys/HillslopeHydrologyMod.F90 | 73 ++++++++++++------------ 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 11208e7228..1ab154f683 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -377,33 +377,33 @@ subroutine InitHillslope(bounds,fsurdat) if (use_hillslope_routing) then allocate(fstream_in(bounds%begg:bounds%endg)) + call ncd_io(ncid=ncid, varname='h_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - lun%stream_channel_depth(l) = fstream_in(g) - enddo - else if (masterproc) then + if (masterproc .and. .not. readvar) then call endrun( 'ERROR:: h_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_depth(l) = fstream_in(g) + enddo + call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - lun%stream_channel_width(l) = fstream_in(g) - enddo - else if (masterproc) then + if (masterproc .and. .not. readvar) then call endrun( 'ERROR:: h_stream_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_width(l) = fstream_in(g) + enddo + call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - lun%stream_channel_slope(l) = fstream_in(g) - enddo - else if (masterproc) then + if (masterproc .and. .not. readvar) then call endrun( 'ERROR:: h_stream_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + lun%stream_channel_slope(l) = fstream_in(g) + enddo deallocate(fstream_in) end if @@ -605,27 +605,26 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='h_bedrock', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) - if (readvar) then - do l = bounds%begl,bounds%endl - g = lun%gridcell(l) - do c = lun%coli(l), lun%colf(l) - if (col%is_hillslope_column(c) .and. col%active(c)) then - ci = c-lun%coli(l)+1 - do j = 1,nlevsoi - if (zisoi(j-1) > zmin_bedrock) then - if (zisoi(j-1) < fhillslope_in(g,ci) & - .and. zisoi(j) >= fhillslope_in(g,ci)) then - col%nbedrock(c) = j - end if - end if - enddo - end if - enddo - enddo - deallocate(fhillslope_in) - else if (masterproc) then + if (masterproc .and. .not. readvar) then call endrun( 'ERROR:: soil_profile_method = "FromFile", but h_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if + do l = bounds%begl,bounds%endl + g = lun%gridcell(l) + do c = lun%coli(l), lun%colf(l) + if (col%is_hillslope_column(c) .and. col%active(c)) then + ci = c-lun%coli(l)+1 + do j = 1,nlevsoi + if (zisoi(j-1) > zmin_bedrock) then + if (zisoi(j-1) < fhillslope_in(g,ci) & + .and. zisoi(j) >= fhillslope_in(g,ci)) then + col%nbedrock(c) = j + end if + end if + enddo + end if + enddo + enddo + deallocate(fhillslope_in) call ncd_pio_closefile(ncid) else if (soil_profile_method==soil_profile_set_lowland_upland & From 9c0123c954229e73ead4628e48cfeafe0811c03f Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Fri, 26 Jan 2024 18:04:02 -0700 Subject: [PATCH 145/153] Remove if (masterproc) conditions on error checks outside initialization. --- src/biogeophys/HillslopeHydrologyMod.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 1ab154f683..277a80803f 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -1026,7 +1026,7 @@ subroutine HillslopeStreamOutflow(bounds, & volumetric_streamflow(l) = cross_sectional_area * flow_velocity & + (stream_depth-lun%stream_channel_depth(l)) & *lun%stream_channel_width(l)*lun%stream_channel_length(l)/dtime - else if (masterproc) then + else call endrun( 'ERROR:: invalid overbank_method.'//errmsg(sourcefile, __LINE__) ) end if @@ -1039,7 +1039,7 @@ subroutine HillslopeStreamOutflow(bounds, & volumetric_streamflow(l) = max(0._r8,min(volumetric_streamflow(l),stream_water_volume(l)/dtime)) end if - else if (masterproc) then + else call endrun( 'ERROR:: invalid streamflow_method'//errmsg(sourcefile, __LINE__) ) end if end if ! end of istsoil From a2b578873816322f1828eea44cc2a7565d2bfa13 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 29 Jan 2024 10:55:41 -0700 Subject: [PATCH 146/153] Delete development testmods --- .../clm/Hillslope_DominantPftLowland/include_user_mods | 1 - .../testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm | 1 - .../clm/Hillslope_DominantPftUniform/include_user_mods | 1 - .../testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm | 1 - .../clm/Hillslope_SoilProfileLinear/include_user_mods | 1 - .../testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm | 1 - 6 files changed, 6 deletions(-) delete mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm delete mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm delete mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods delete mode 100644 cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods deleted file mode 100644 index fa2e50a80d..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm deleted file mode 100644 index 4ab5c6cd56..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftLowland/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -hillslope_pft_distribution_method = 'DominantPftLowland' diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods deleted file mode 100644 index fa2e50a80d..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm deleted file mode 100644 index e85c64b9ff..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope_DominantPftUniform/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -hillslope_pft_distribution_method = 'DominantPftUniform' diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods deleted file mode 100644 index fa2e50a80d..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm deleted file mode 100644 index ab07c64239..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope_SoilProfileLinear/user_nl_clm +++ /dev/null @@ -1 +0,0 @@ -hillslope_soil_profile_method = 'Linear' From 83e0becdc065d6d485ebc29ded2f70766543332e Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 29 Jan 2024 10:58:14 -0700 Subject: [PATCH 147/153] Fully specify namelist settings for Hillslope test. --- .../testdefs/testmods_dirs/clm/Hillslope/user_nl_clm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm index ab6c7b464b..812d11e688 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -1,5 +1,11 @@ -fsurdat = '$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.1.nc' use_hillslope = .true. use_hillslope_routing = .true. +downscale_hillslope_meteorology = .false. +hillslope_head_gradient_method = 'Darcy' +hillslope_transmissivity_method = 'LayerSum' hillslope_pft_distribution_method = 'PftLowlandUpland' -use_ssre = .false. +hillslope_soil_profile_method = 'Uniform' + +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.1.nc' + +use_ssre = .false. \ No newline at end of file From b026e2ef9651d3dda916217eb4d8dc2615c05b20 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 29 Jan 2024 11:05:34 -0700 Subject: [PATCH 148/153] Add 3 new hillslope testmods: (The latter 2 have no theme; they are intended to exercise all options.) * HillslopeFromFile * HillslopeC * HillslopeD --- .../testdefs/testmods_dirs/clm/Hillslope/user_nl_clm | 2 +- .../testmods_dirs/clm/HillslopeC/include_user_mods | 1 + .../testdefs/testmods_dirs/clm/HillslopeC/user_nl_clm | 7 +++++++ .../testmods_dirs/clm/HillslopeD/include_user_mods | 1 + .../testdefs/testmods_dirs/clm/HillslopeD/user_nl_clm | 3 +++ .../testmods_dirs/clm/HillslopeFromFile/include_user_mods | 1 + .../testmods_dirs/clm/HillslopeFromFile/user_nl_clm | 2 ++ 7 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 cime_config/testdefs/testmods_dirs/clm/HillslopeC/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/HillslopeC/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/HillslopeD/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/HillslopeD/user_nl_clm create mode 100644 cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/include_user_mods create mode 100644 cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm index 812d11e688..e6d726c860 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -6,6 +6,6 @@ hillslope_transmissivity_method = 'LayerSum' hillslope_pft_distribution_method = 'PftLowlandUpland' hillslope_soil_profile_method = 'Uniform' -fsurdat = '$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.1.nc' +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.2.nc' use_ssre = .false. \ No newline at end of file diff --git a/cime_config/testdefs/testmods_dirs/clm/HillslopeC/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/HillslopeC/include_user_mods new file mode 100644 index 0000000000..fa2e50a80d --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/HillslopeC/include_user_mods @@ -0,0 +1 @@ +../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/HillslopeC/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/HillslopeC/user_nl_clm new file mode 100644 index 0000000000..10450766d0 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/HillslopeC/user_nl_clm @@ -0,0 +1,7 @@ +! Various hillslope options not exercised by other testmods +use_hillslope_routing = .false. +downscale_hillslope_meteorology = .true. +hillslope_head_gradient_method = 'Kinematic' +hillslope_transmissivity_method = 'Uniform' +hillslope_pft_distribution_method = 'DominantPftUniform' +hillslope_soil_profile_method = 'SetLowlandUpland' diff --git a/cime_config/testdefs/testmods_dirs/clm/HillslopeD/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/HillslopeD/include_user_mods new file mode 100644 index 0000000000..fa2e50a80d --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/HillslopeD/include_user_mods @@ -0,0 +1 @@ +../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/HillslopeD/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/HillslopeD/user_nl_clm new file mode 100644 index 0000000000..04a2332df7 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/HillslopeD/user_nl_clm @@ -0,0 +1,3 @@ +! Various hillslope options not exercised by other testmods +hillslope_pft_distribution_method = 'DominantPftLowland' +hillslope_soil_profile_method = 'Linear' diff --git a/cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/include_user_mods new file mode 100644 index 0000000000..fa2e50a80d --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/include_user_mods @@ -0,0 +1 @@ +../Hillslope diff --git a/cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/user_nl_clm new file mode 100644 index 0000000000..7be761eccc --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/HillslopeFromFile/user_nl_clm @@ -0,0 +1,2 @@ +hillslope_pft_distribution_method = 'FromFile' +hillslope_soil_profile_method = 'FromFile' From ed5e0ae1275b43f35ebb10a857790dcb52651d52 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 29 Jan 2024 11:20:37 -0700 Subject: [PATCH 149/153] Add 4 hillslope tests to testlist_clm.xml: Suites aux_clm and hillslope: * ERP_D_P64x2_Ld10.f10_f10_mg37.I2000Clm51Bgc.derecho_intel.clm-Hillslope * SMS_D_Mmpi-serial_Ld5.5x5_amazon.I1850Clm51Bgc.derecho_gnu.clm-HillslopeC * SMS_D_Ld3.f10_f10_mg37.I2000Clm51Bgc.izumi_nag.clm-HillslopeD Suite hillslope: * SMS_D_Ld3.f10_f10_mg37.I1850Clm51Bgc.derecho_intel.clm-HillslopeFromFile --- cime_config/testdefs/testlist_clm.xml | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index c915552748..2f7326dd78 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -3450,4 +3450,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From dbae8b61618ecf1e544d9bb17543b78a3a768c21 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Mon, 29 Jan 2024 13:27:16 -0700 Subject: [PATCH 150/153] Change an intent(out) to inout, satisfying nag test. --- src/biogeophys/HillslopeHydrologyMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index 277a80803f..ad8712e67e 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -1072,7 +1072,7 @@ subroutine HillslopeUpdateStreamWater(bounds, waterstatebulk_inst, & type(bounds_type), intent(in) :: bounds type(waterstatebulk_type), intent(inout) :: waterstatebulk_inst type(waterfluxbulk_type), intent(inout) :: waterfluxbulk_inst - type(waterdiagnosticbulk_type), intent(out) :: waterdiagnosticbulk_inst + type(waterdiagnosticbulk_type), intent(inout) :: waterdiagnosticbulk_inst integer :: c, l, g, i, j real(r8) :: qflx_surf_vol ! volumetric surface runoff (m3/s) From 14f86afb937df6d8f09ae9b139d329ac3b41d082 Mon Sep 17 00:00:00 2001 From: Sean Swenson Date: Wed, 7 Feb 2024 13:28:07 -0700 Subject: [PATCH 151/153] make variable names consistent --- src/biogeophys/HillslopeHydrologyMod.F90 | 70 ++++++++++++------------ src/main/histFileMod.F90 | 36 ++++++------ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index ad8712e67e..b2866df679 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -201,9 +201,9 @@ subroutine InitHillslope(bounds,fsurdat) real(r8), allocatable :: hill_slope(:,:) ! hillslope slope [m/m] real(r8), allocatable :: hill_aspect(:,:) ! hillslope azimuth [radians] real(r8), allocatable :: hill_area(:,:) ! hillslope area [m2] - real(r8), allocatable :: hill_length(:,:) ! hillslope length [m] + real(r8), allocatable :: hill_dist(:,:) ! hillslope length [m] real(r8), allocatable :: hill_width(:,:) ! hillslope width [m] - real(r8), allocatable :: hill_height(:,:) ! hillslope height [m] + real(r8), allocatable :: hill_elev(:,:) ! hillslope height [m] real(r8), allocatable :: hill_bedrock(:,:) ! hillslope bedrock depth [m] real(r8), pointer :: fstream_in(:) ! read in - 1D - float @@ -238,9 +238,9 @@ subroutine InitHillslope(bounds,fsurdat) hill_slope (bounds%begl:bounds%endl,max_columns_hillslope), & hill_aspect (bounds%begl:bounds%endl,max_columns_hillslope), & hill_area (bounds%begl:bounds%endl,max_columns_hillslope), & - hill_length (bounds%begl:bounds%endl,max_columns_hillslope), & + hill_dist (bounds%begl:bounds%endl,max_columns_hillslope), & hill_width (bounds%begl:bounds%endl,max_columns_hillslope), & - hill_height (bounds%begl:bounds%endl,max_columns_hillslope), & + hill_elev (bounds%begl:bounds%endl,max_columns_hillslope), & col_pftndx (bounds%begc:bounds%endc), & stat=ierr) @@ -305,9 +305,9 @@ subroutine InitHillslope(bounds,fsurdat) deallocate(ihillslope_in) allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) - call ncd_io(ncid=ncid, varname='h_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -315,9 +315,9 @@ subroutine InitHillslope(bounds,fsurdat) hill_slope(l,:) = fhillslope_in(g,:) enddo - call ncd_io(ncid=ncid, varname='h_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -325,46 +325,46 @@ subroutine InitHillslope(bounds,fsurdat) hill_aspect(l,:) = fhillslope_in(g,:) enddo - call ncd_io(ncid=ncid, varname='h_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_area(l,:) = fhillslope_in(g,:) enddo - call ncd_io(ncid=ncid, varname='h_length', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_distance', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) - hill_length(l,:) = fhillslope_in(g,:) + hill_dist(l,:) = fhillslope_in(g,:) enddo - call ncd_io(ncid=ncid, varname='h_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) hill_width(l,:) = fhillslope_in(g,:) enddo - call ncd_io(ncid=ncid, varname='h_height', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_elevation', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) - hill_height(l,:) = fhillslope_in(g,:) + hill_elev(l,:) = fhillslope_in(g,:) enddo deallocate(fhillslope_in) allocate(ihillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) - call ncd_io(ncid=ncid, varname='h_pftndx', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_pftndx', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (readvar) then allocate(hill_pftndx (bounds%begl:bounds%endl,max_columns_hillslope), stat=ierr) do l = bounds%begl,bounds%endl @@ -378,27 +378,27 @@ subroutine InitHillslope(bounds,fsurdat) if (use_hillslope_routing) then allocate(fstream_in(bounds%begg:bounds%endg)) - call ncd_io(ncid=ncid, varname='h_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) lun%stream_channel_depth(l) = fstream_in(g) enddo - call ncd_io(ncid=ncid, varname='h_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_stream_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_stream_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) lun%stream_channel_width(l) = fstream_in(g) enddo - call ncd_io(ncid=ncid, varname='h_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: h_stream_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_stream_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -442,17 +442,17 @@ subroutine InitHillslope(bounds,fsurdat) enddo ! distance of lower edge of column from hillslope bottom - col%hill_distance(c) = hill_length(l,ci) + col%hill_distance(c) = hill_dist(l,ci) ! width of lower edge of column - col%hill_width(c) = hill_width(l,ci) + col%hill_width(c) = hill_width(l,ci) ! mean elevation of column relative to gridcell mean elevation - col%hill_elev(c) = hill_height(l,ci) + col%hill_elev(c) = hill_elev(l,ci) ! mean along-hill slope of column - col%hill_slope(c) = hill_slope(l,ci) + col%hill_slope(c) = hill_slope(l,ci) ! area of column - col%hill_area(c) = hill_area(l,ci) + col%hill_area(c) = hill_area(l,ci) ! azimuth of column - col%hill_aspect(c) = hill_aspect(l,ci) + col%hill_aspect(c) = hill_aspect(l,ci) ! pft index of column if ( allocated(hill_pftndx) ) then col_pftndx(c) = hill_pftndx(l,ci) @@ -525,8 +525,8 @@ subroutine InitHillslope(bounds,fsurdat) enddo ! end of landunit loop deallocate(ncolumns_hillslope,pct_hillslope,hill_ndx,col_ndx,col_dndx, & - hill_slope,hill_area,hill_length, & - hill_width,hill_height,hill_aspect) + hill_slope,hill_area,hill_dist, & + hill_width,hill_elev,hill_aspect) ! Modify pft distributions ! this may require modifying subgridMod/natveg_patch_exists @@ -604,9 +604,9 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d call ncd_pio_openfile (ncid, locfn, 0) allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) - call ncd_io(ncid=ncid, varname='h_bedrock', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) + call ncd_io(ncid=ncid, varname='hillslope_bedrock_depth', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: soil_profile_method = "FromFile", but h_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: soil_profile_method = "FromFile", but hillslope_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 8997a73c9b..d419f97630 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -3139,31 +3139,31 @@ subroutine htape_timeconst(t, mode) long_name='coordinate levels for soil decomposition variables', units='m', ncid=nfid(t)) if (use_hillslope .and. .not.tape(t)%dov2xy)then - call ncd_defvar(varname='hslp_distance', xtype=ncd_double, & + call ncd_defvar(varname='hillslope_distance', xtype=ncd_double, & dim1name=namec, long_name='hillslope column distance', & units='m', ncid=nfid(t)) - call ncd_defvar(varname='hslp_width', xtype=ncd_double, & + call ncd_defvar(varname='hillslope_width', xtype=ncd_double, & dim1name=namec, long_name='hillslope column width', & units='m', ncid=nfid(t)) - call ncd_defvar(varname='hslp_area', xtype=ncd_double, & + call ncd_defvar(varname='hillslope_area', xtype=ncd_double, & dim1name=namec, long_name='hillslope column area', & units='m', ncid=nfid(t)) - call ncd_defvar(varname='hslp_elev', xtype=ncd_double, & + call ncd_defvar(varname='hillslope_elev', xtype=ncd_double, & dim1name=namec, long_name='hillslope column elevation', & units='m', ncid=nfid(t)) - call ncd_defvar(varname='hslp_slope', xtype=ncd_double, & + call ncd_defvar(varname='hillslope_slope', xtype=ncd_double, & dim1name=namec, long_name='hillslope column slope', & units='m', ncid=nfid(t)) - call ncd_defvar(varname='hslp_aspect', xtype=ncd_double, & + call ncd_defvar(varname='hillslope_aspect', xtype=ncd_double, & dim1name=namec, long_name='hillslope column aspect', & units='m', ncid=nfid(t)) - call ncd_defvar(varname='hslp_index', xtype=ncd_int, & + call ncd_defvar(varname='hillslope_index', xtype=ncd_int, & dim1name=namec, long_name='hillslope index', & ncid=nfid(t)) - call ncd_defvar(varname='hslp_cold', xtype=ncd_int, & + call ncd_defvar(varname='hillslope_cold', xtype=ncd_int, & dim1name=namec, long_name='hillslope downhill column index', & ncid=nfid(t)) - call ncd_defvar(varname='hslp_colu', xtype=ncd_int, & + call ncd_defvar(varname='hillslope_colu', xtype=ncd_int, & dim1name=namec, long_name='hillslope uphill column index', & ncid=nfid(t)) end if @@ -3258,13 +3258,13 @@ subroutine htape_timeconst(t, mode) end if if (use_hillslope .and. .not.tape(t)%dov2xy) then - call ncd_io(varname='hslp_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_elev' , data=col%hill_elev, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_aspect' , data=col%hill_aspect, dim1name=namec, ncid=nfid(t), flag='write') - call ncd_io(varname='hslp_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_distance' , data=col%hill_distance, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_width' , data=col%hill_width, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_area' , data=col%hill_area, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_elev' , data=col%hill_elev, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_slope' , data=col%hill_slope, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_aspect' , data=col%hill_aspect, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_index' , data=col%hillslope_ndx, dim1name=namec, ncid=nfid(t), flag='write') ! write global indices rather than local indices allocate(icarr(bounds%begc:bounds%endc),stat=ier) @@ -3280,7 +3280,7 @@ subroutine htape_timeconst(t, mode) endif enddo - call ncd_io(varname='hslp_cold' , data=icarr, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_cold' , data=icarr, dim1name=namec, ncid=nfid(t), flag='write') do c = bounds%begc,bounds%endc if (col%colu(c) /= ispval) then @@ -3290,7 +3290,7 @@ subroutine htape_timeconst(t, mode) endif enddo - call ncd_io(varname='hslp_colu' , data=icarr, dim1name=namec, ncid=nfid(t), flag='write') + call ncd_io(varname='hillslope_colu' , data=icarr, dim1name=namec, ncid=nfid(t), flag='write') deallocate(icarr) endif From 9f46462d83fc9c1d61495080e4053cb02a2cc258 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 28 Feb 2024 10:28:24 -0700 Subject: [PATCH 152/153] Hillslope tests now use v1.3 surface dataset. --- cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm index e6d726c860..afdcf4d1fc 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -6,6 +6,6 @@ hillslope_transmissivity_method = 'LayerSum' hillslope_pft_distribution_method = 'PftLowlandUpland' hillslope_soil_profile_method = 'Uniform' -fsurdat = '$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.2.nc' +fsurdat = '$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_78pfts_simyr2000_synthetic_cosphill_1.3.nc' -use_ssre = .false. \ No newline at end of file +use_ssre = .false. From c222737b8b813dada9858408f13322404fc53604 Mon Sep 17 00:00:00 2001 From: Sam Rabin Date: Wed, 28 Feb 2024 11:27:34 -0700 Subject: [PATCH 153/153] Update ChangeLog and ChangeSum. --- doc/ChangeLog | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ChangeSum | 1 + 2 files changed, 74 insertions(+) diff --git a/doc/ChangeLog b/doc/ChangeLog index d26715f699..98bb43b1a5 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,77 @@ =============================================================== +Tag name: ctsm5.1.dev170 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Wed Feb 28 11:01:43 MST 2024 +One-line Summary: Add hillslope hydrology + +Purpose and description of changes +---------------------------------- + +Changes include multiple soil columns per vegetated landunit, additional meteorological downscaling, new subsurface lateral flow equations, and a hillslope routing parameterization. + +Described in: +Swenson, S. C., Clark, M., Fan, Y., Lawrence, D. M., & Perket, J. (2019). Representing intra-hillslope lateral subsurface flow in the community land model. Journal of Advances in Modeling Earth Systems, 11, 4044–4065. https://doi.org/10.1029/2019MS001833 + + +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 + + +Notes of particular relevance for developers: +--------------------------------------------- + +Changes to tests or testing: +* oldhyd test changes answers due to removal of origflag parameter +* Adds several hillslope-specific tests + + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- DIFF + izumi ------- DIFF + + +Answer changes +-------------- + + Summarize any changes to answers, i.e., + - what code configurations: all + - what platforms/compilers: all + - nature of change: roundoff + + If bitwise differences were observed, how did you show they were no worse + than roundoff? Roundoff differences means one or more lines of code change results + only by roundoff level (because order of operation changes for example). Roundoff + changes to state fields usually grow to greater than roundoff as the simulation progresses. + * FSDS answers change due to rounding differences, since the history field now uses a column-level variable instead of a gridcell-level one. Note that this is JUST the history field that's affected, which is why there are no diffs in any other variable. (Confirmed using branch at https://github.com/samsrabin/CTSM/tree/hillslope-revert-fsds-diffs.) + * The origflag parameter (used to reproduce CLM4 behavior) was removed, so anything using that will break. This includes the oldhyd test. + + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +* ESCOMP/CTSM#1715: Hillslope hydrology (https://github.com/ESCOMP/CTSM/pull/1715) +* ESCOMP/CTSM#2390: Hillslope merge (https://github.com/ESCOMP/CTSM/pull/2390) + +=============================================================== +=============================================================== Tag name: ctsm5.1.dev169 Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) Date: Thu 22 Feb 2024 09:42:57 AM MST diff --git a/doc/ChangeSum b/doc/ChangeSum index 18ae34626f..821bb1f92d 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.1.dev170 samrabin 02/28/2024 Add hillslope hydrology ctsm5.1.dev169 samrabin 02/22/2024 Merge b4b-dev ctsm5.1.dev168 slevis 02/16/2024 Remove a source of negative snocan in CanopyFluxesMod ctsm5.1.dev167 samrabin 02/08/2024 Delete _FillValue and history from parameter files