diff --git a/doc/ChangeLog b/doc/ChangeLog index 6f3183ed94..045c26ec2f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,120 @@ =============================================================== +Tag name: ctsm1.0.dev103 +Originator(s): slevis (Samuel Levis, SLevis Consulting LLC,303-665-1310) +Date: Mon Jun 29 17:16:29 MDT 2020 +One-line Summary: Gridcell-level balance-check for methane (CH4) + +Purpose of changes +------------------ + + Bracket the model time-step loop to calculate balance checks at the + gridcell level, as detailed in issue #315. The column-level check + remains unchanged. + + Subroutine ch4_init_balance_check is replaced with + ch4_init_column_balance_check. Subroutine + ch4_init_gridcell_balance_check is added. + + The implementation is similar to the one for carbon and nitrogen (see + tag ctsm1.0.dev096). + +Bugs fixed or introduced +------------------------ + +Issues fixed (include CTSM Issue #): #315 + + +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_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + +Notes of particular relevance for users +--------------------------------------- + +Caveats for users (e.g., need to interpolate initial conditions): + None + +Changes to CTSM'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: + No + +Notes of particular relevance for developers: (including Code reviews and testing) +--------------------------------------------- +NOTE: Be sure to review the steps in README.CHECKLIST.master_tags as well as the coding style in the Developers Guide + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + None + +Changes to tests or testing: + None + +Code reviewed by: + @billsacks + + +CTSM testing: + + [PASS means all tests PASS and OK means tests PASS other than expected fails.] + + build-namelist tests: + + cheyenne - + + tools-tests (test/tools): + + cheyenne - + + PTCLM testing (tools/shared/PTCLM/test): + + cheyenne - + + python testing (see instructions in python/README.md; document testing done): + + (any machine) - + + regular tests (aux_clm): + + cheyenne ---- PASS + izumi ------- PASS + +If the tag used for baseline comparisons was NOT the previous tag, note that here: + + +Answer changes +-------------- + +Changes answers relative to baseline: + No + +Detailed list of changes +------------------------ + +List any externals directories updated (cime, rtm, mosart, cism, fates, etc.): + None + +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/CTSM/pull/1022 + +=============================================================== +=============================================================== Tag name: ctsm1.0.dev102 Originator(s): erik (Erik Kluzek,UCAR/TSS,303-497-1326) Date: Fri Jun 26 01:32:04 MDT 2020 diff --git a/doc/ChangeSum b/doc/ChangeSum index 655832d263..9af125f5b9 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,6 @@ Tag Who Date Summary ============================================================================================================================ + ctsm1.0.dev103 slevis 06/29/2020 Gridcell-level error-check for methane (CH4) ctsm1.0.dev102 erik/ole 06/26/2020 Some important fixes for LUNA in clm5_0, and small urban issue in clm5_0 ctsm1.0.dev101 ole/erik 06/17/2020 Changes from Keith to bring a list of variables to the parameter file ctsm1.0.dev100 sacks 06/09/2020 Deallocate memory after running init_interp diff --git a/src/biogeochem/ch4Mod.F90 b/src/biogeochem/ch4Mod.F90 index 8e90f730d4..2432b85cf4 100644 --- a/src/biogeochem/ch4Mod.F90 +++ b/src/biogeochem/ch4Mod.F90 @@ -49,7 +49,8 @@ module ch4Mod ! !PUBLIC MEMBER FUNCTIONS: public :: readParams - public :: ch4_init_balance_check + public :: ch4_init_column_balance_check + public :: ch4_init_gridcell_balance_check public :: ch4 ! !PRIVATE MEMBER FUNCTIONS: @@ -155,7 +156,9 @@ module ch4Mod real(r8), pointer, private :: zwt_ch4_unsat_col (:) ! col depth of water table for unsaturated fraction (m) real(r8), pointer, private :: lake_soilc_col (:,:) ! col total soil organic matter found in level (g C / m^3) (nlevsoi) real(r8), pointer, private :: totcolch4_col (:) ! col total methane found in soil col (g C / m^2) + real(r8), pointer, private :: totcolch4_grc (:) ! grc total methane found in soil col (g C / m^2) real(r8), pointer, private :: totcolch4_bef_col (:) ! col total methane found in soil col, start of timestep (g C / m^2) + real(r8), pointer, private :: totcolch4_bef_grc (:) ! grc total methane found in soil col, start of timestep (g C / m^2) real(r8), pointer, private :: annsum_counter_col (:) ! col seconds since last annual accumulator turnover real(r8), pointer, private :: tempavg_somhr_col (:) ! col temporary average SOM heterotrophic resp. (gC/m2/s) real(r8), pointer, private :: annavg_somhr_col (:) ! col annual average SOM heterotrophic resp. (gC/m2/s) @@ -187,7 +190,7 @@ module ch4Mod ! false. This could be a scalar, but scalars cause problems with threading, so we use ! a column-level array (column-level for convenience, because it is referenced in ! column-level loops). - logical , pointer, private :: ch4_first_time_col (:) ! col whether this is the first time step that includes ch4 + logical , pointer, private :: ch4_first_time_grc (:) ! grc whether this is the first time step that includes ch4 ! real(r8), pointer, public :: finundated_col (:) ! col fractional inundated area (excluding dedicated wetland cols) real(r8), pointer, public :: finundated_pre_snow_col (:) ! col fractional inundated area (excluding dedicated wetland cols) before snow @@ -302,7 +305,9 @@ subroutine InitAllocate(this, bounds) allocate(this%zwt_ch4_unsat_col (begc:endc)) ; this%zwt_ch4_unsat_col (:) = nan allocate(this%lake_soilc_col (begc:endc,1:nlevgrnd)) ; this%lake_soilc_col (:,:) = spval !first time-step allocate(this%totcolch4_col (begc:endc)) ; this%totcolch4_col (:) = nan + allocate(this%totcolch4_grc (begg:endg)) ; this%totcolch4_grc (:) = nan allocate(this%totcolch4_bef_col (begc:endc)) ; this%totcolch4_bef_col (:) = nan + allocate(this%totcolch4_bef_grc (begg:endg)) ; this%totcolch4_bef_grc (:) = nan allocate(this%annsum_counter_col (begc:endc)) ; this%annsum_counter_col (:) = nan allocate(this%tempavg_somhr_col (begc:endc)) ; this%tempavg_somhr_col (:) = nan allocate(this%annavg_somhr_col (begc:endc)) ; this%annavg_somhr_col (:) = nan @@ -327,7 +332,7 @@ subroutine InitAllocate(this, bounds) allocate(this%annavg_agnpp_patch (begp:endp)) ; this%annavg_agnpp_patch (:) = spval ! To detect first year allocate(this%annavg_bgnpp_patch (begp:endp)) ; this%annavg_bgnpp_patch (:) = spval ! To detect first year - allocate(this%ch4_first_time_col (begc:endc)) ; this%ch4_first_time_col (:) = .true. + allocate(this%ch4_first_time_grc (begg:endg)) ; this%ch4_first_time_grc (:) = .true. allocate(this%finundated_col (begc:endc)) ; this%finundated_col (:) = nan allocate(this%finundated_pre_snow_col (begc:endc)) ; this%finundated_pre_snow_col (:) = nan @@ -337,7 +342,6 @@ subroutine InitAllocate(this, bounds) allocate(this%conc_o2_unsat_col (begc:endc,1:nlevgrnd)) ; this%conc_o2_unsat_col (:,:) = nan allocate(this%o2_decomp_depth_sat_col (begc:endc,1:nlevgrnd)) ; this%o2_decomp_depth_sat_col (:,:) = nan allocate(this%o2_decomp_depth_unsat_col (begc:endc,1:nlevgrnd)) ; this%o2_decomp_depth_unsat_col (:,:) = nan - allocate(this%ch4_surf_flux_tot_col (begc:endc)) ; this%ch4_surf_flux_tot_col (:) = nan allocate(this%grnd_ch4_cond_patch (begp:endp)) ; this%grnd_ch4_cond_patch (:) = nan allocate(this%grnd_ch4_cond_col (begc:endc)) ; this%grnd_ch4_cond_col (:) = nan @@ -1144,7 +1148,7 @@ subroutine Restart( this, bounds, ncid, flag ) ! restart file based on whether FINUNDATED is present on the restart file. We ! could use any methane variable, but FINUNDATED is a good choice because this ! "first time" variable is used in connection with FINUNDATED. - this%ch4_first_time_col(bounds%begc:bounds%endc) = .false. + this%ch4_first_time_grc(bounds%begg:bounds%endg) = .false. ! BACKWARDS_COMPATIBILITY(wjs, 2016-02-11) The following is needed for backwards ! compatibility with restart files generated from older versions of the code, where @@ -1554,13 +1558,68 @@ subroutine readParams ( ncid ) end subroutine readParams !----------------------------------------------------------------------- - subroutine ch4_init_balance_check(bounds, num_nolakec, filter_nolakec, num_lakec, filter_lakec, & + subroutine ch4_init_gridcell_balance_check(bounds, num_nolakec, & + filter_nolakec, num_lakec, filter_lakec, ch4_inst) + ! + ! !DESCRIPTION: + ! Calculate beginning gridcell-level ch4 balance for mass conservation + ! check + ! + ! This sets ch4_inst%totcolch4_bef_grc + ! + ! Called before the weight updates done for dynamic landunits and the + ! associated filter updates + ! + ! !USES: + use subgridAveMod, only: c2g + ! + ! !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 lake points in column filter + integer , intent(in) :: filter_lakec(:) ! column filter for lake points + type(ch4_type) , intent(inout) :: ch4_inst + ! + ! !LOCAL VARIABLES: + + integer :: begc, endc, begg, endg + real(r8), allocatable :: totcolch4_bef_col(:) ! col total methane found in soil col, start of timestep (g C / m^2) NB: this variable appears with the same name in ch4_type but the one here is local and for temporary use + character(len=*), parameter :: subname = 'ch4_init_gridcell_balance_check' + !----------------------------------------------------------------------- + + begc = bounds%begc + endc = bounds%endc + begg = bounds%begg + endg = bounds%endg + + allocate(totcolch4_bef_col(begc:endc)) + + ! This is only really needed for soilc and lakec, but we use nolakec rather + ! than just soilc for consistency with the other call to ch4_totcolch4 + ! (which computes ch4_inst%totcolch4 over all columns for diagnostic + ! purposes). + call ch4_totcolch4(bounds, num_nolakec, filter_nolakec, num_lakec, & + filter_lakec, ch4_inst, & + totcolch4_bef_col(begc:endc)) + + call c2g( bounds, & + totcolch4_bef_col(begc:endc), & + ch4_inst%totcolch4_bef_grc(begg:endg), & + c2l_scale_type= 'unity', l2g_scale_type='unity' ) + + deallocate(totcolch4_bef_col) + + end subroutine ch4_init_gridcell_balance_check + + !----------------------------------------------------------------------- + subroutine ch4_init_column_balance_check(bounds, num_nolakec, filter_nolakec, num_lakec, filter_lakec, & ch4_inst) ! ! !DESCRIPTION: ! Calculate beginning column-level ch4 balance, for mass conservation check ! - ! This sets ch4_inst%totcolch4_bef + ! This sets ch4_inst%totcolch4_bef_col ! ! This should be called after the weight updates due to dynamic landunits, and the ! associated filter updates - i.e., using the new version of the filters. @@ -1576,9 +1635,8 @@ subroutine ch4_init_balance_check(bounds, num_nolakec, filter_nolakec, num_lakec type(ch4_type) , intent(inout) :: ch4_inst ! ! !LOCAL VARIABLES: - integer :: fc, c - character(len=*), parameter :: subname = 'ch4_init_balance_check' + character(len=*), parameter :: subname = 'ch4_init_column_balance_check' !----------------------------------------------------------------------- ! This is only really needed for soilc and lakec, but we use nolakec rather than just @@ -1587,7 +1645,7 @@ subroutine ch4_init_balance_check(bounds, num_nolakec, filter_nolakec, num_lakec call ch4_totcolch4(bounds, num_nolakec, filter_nolakec, num_lakec, filter_lakec, & ch4_inst, ch4_inst%totcolch4_bef_col(bounds%begc:bounds%endc)) - end subroutine ch4_init_balance_check + end subroutine ch4_init_column_balance_check !----------------------------------------------------------------------- @@ -1698,7 +1756,8 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & qflx_surf => waterfluxbulk_inst%qflx_surf_col , & ! Input: [real(r8) (:) ] total 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) - totcolch4_bef => ch4_inst%totcolch4_bef_col , & ! Input: [real(r8) (:) ] total methane in soil column, start of timestep (g C / m^2) + totcolch4_bef_col => ch4_inst%totcolch4_bef_col , & ! Input: [real(r8) (:) ] column-level total methane in soil column, start of timestep (g C / m^2) + totcolch4_bef_grc => ch4_inst%totcolch4_bef_grc , & ! Input: [real(r8) (:) ] gridcell-level total methane in soil column, start of timestep (g C / m^2) grnd_ch4_cond_patch => ch4_inst%grnd_ch4_cond_patch , & ! Input: [real(r8) (:) ] tracer conductance for boundary layer [m/s] grnd_ch4_cond_col => ch4_inst%grnd_ch4_cond_col , & ! Output: [real(r8) (:) ] tracer conductance for boundary layer [m/s] (p2c) @@ -1724,17 +1783,19 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & conc_o2_lake => ch4_inst%conc_o2_lake_col , & ! Output: [real(r8) (:,:) ] O2 conc in each soil layer (mol/m3) (nlevsoi) ch4_dfsat_flux => ch4_inst%ch4_dfsat_flux_col , & ! Output: [real(r8) (:) ] CH4 flux to atm due to decreasing finundated (kg C/m^2/s) [+] zwt_ch4_unsat => ch4_inst%zwt_ch4_unsat_col , & ! Output: [real(r8) (:) ] depth of water table for unsaturated fraction (m) - totcolch4 => ch4_inst%totcolch4_col , & ! Output: [real(r8) (:) ] total methane in soil column (g C / m^2) + totcolch4_col => ch4_inst%totcolch4_col , & ! Output: [real(r8) (:) ] column-level total methane in soil column (g C / m^2) + totcolch4_grc => ch4_inst%totcolch4_grc , & ! Output: [real(r8) (:) ] gridcell-level total methane in soil column (g C / m^2) finundated => ch4_inst%finundated_col , & ! Output: [real(r8) (:) ] fractional inundated area in soil column (excluding dedicated wetland columns) finundated_pre_snow => ch4_inst%finundated_pre_snow_col , & ! Output: [real(r8) (:) ] fractional inundated area in soil column (excluding dedicated wetland columns) before snow - ch4_first_time => ch4_inst%ch4_first_time_col , & ! Output: [logical (:) ] whether this is the first time step that includes ch4 + ch4_first_time_grc => ch4_inst%ch4_first_time_grc , & ! Output: [logical (:) ] grc whether this is the first time step that includes ch4 qflx_surf_lag => ch4_inst%qflx_surf_lag_col , & ! Output: [real(r8) (:) ] time-lagged surface runoff (mm H2O /s) finundated_lag => ch4_inst%finundated_lag_col , & ! Output: [real(r8) (:) ] time-lagged fractional inundated area layer_sat_lag => ch4_inst%layer_sat_lag_col , & ! Output: [real(r8) (:,:) ] Lagged saturation status of soil layer in the unsaturated zone (1 = sat) c_atm => ch4_inst%c_atm_grc , & ! Output: [real(r8) (:,:) ] CH4, O2, CO2 atmospheric conc (mol/m3) ch4co2f => ch4_inst%ch4co2f_grc , & ! Output: [real(r8) (:) ] gridcell CO2 production from CH4 oxidation (g C/m**2/s) ch4prodg => ch4_inst%ch4prodg_grc , & ! Output: [real(r8) (:) ] gridcell average CH4 production (g C/m^2/s) - ch4_surf_flux_tot => ch4_inst%ch4_surf_flux_tot_col , & ! Output: [real(r8) (:) ] col CH4 flux to atm. (kg C/m**2/s) + ch4_surf_flux_tot_col => ch4_inst%ch4_surf_flux_tot_col , & ! Output: [real(r8) (:) ] col CH4 flux to atm. (kg C/m**2/s) + ch4_surf_flux_tot_grc => lnd2atm_inst%ch4_surf_flux_tot_grc , & ! Output: [real(r8) (:) ] grc CH4 flux to atm. (kg C/m**2/s) nem_grc => lnd2atm_inst%nem_grc , & ! Output: [real(r8) (:) ] gridcell average net methane correction to CO2 flux (g C/m^2/s) @@ -1762,7 +1823,7 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & jwt(begc:endc) = huge(1) ! Initialize local fluxes to zero: necessary for columns outside the filters because averaging up to gridcell will be done - ch4_surf_flux_tot(begc:endc) = 0._r8 + ch4_surf_flux_tot_col(begc:endc) = 0._r8 ch4_prod_tot(begc:endc) = 0._r8 ch4_oxid_tot(begc:endc) = 0._r8 rootfraction(begp:endp,:) = spval @@ -1848,7 +1909,8 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & ch4_dfsat_flux(c) = 0._r8 end if - if (.not. ch4_first_time(c)) then + g = col%gridcell(c) + if (.not. ch4_first_time_grc(g)) then if (finundated(c) > fsat_bef(c)) then !Reduce conc_ch4_sat dfsat = finundated(c) - fsat_bef(c) conc_ch4_sat(c,j) = (fsat_bef(c)*conc_ch4_sat(c,j) + dfsat*conc_ch4_unsat(c,j)) / finundated(c) @@ -2060,7 +2122,7 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & if (j == 1) then totalsat = ch4_surf_diff_sat(c) + ch4_surf_aere_sat(c) + ch4_surf_ebul_sat(c) totalunsat = ch4_surf_diff_unsat(c) + ch4_surf_aere_unsat(c) + ch4_surf_ebul_unsat(c) - ch4_surf_flux_tot(c) = (finundated(c)*totalsat + (1._r8 - finundated(c))*totalunsat) * & + ch4_surf_flux_tot_col(c) = (finundated(c)*totalsat + (1._r8 - finundated(c))*totalunsat) * & catomw / 1000._r8 !Convert from mol to kg C ! ch4_oxid_tot and ch4_prod_tot are initialized to zero above @@ -2086,7 +2148,7 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & do fc = 1, num_soilc c = filter_soilc(fc) - ch4_surf_flux_tot(c) = ch4_surf_flux_tot(c) + ch4_dfsat_flux(c) + ch4_surf_flux_tot_col(c) = ch4_surf_flux_tot_col(c) + ch4_dfsat_flux(c) end do if (allowlakeprod) then @@ -2097,7 +2159,7 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & if (j == 1) then ! ch4_oxid_tot and ch4_prod_tot are initialized to zero above totalsat = ch4_surf_diff_sat(c) + ch4_surf_aere_sat(c) + ch4_surf_ebul_sat(c) - ch4_surf_flux_tot(c) = totalsat*catomw / 1000._r8 + ch4_surf_flux_tot_col(c) = totalsat*catomw / 1000._r8 end if ch4_oxid_tot(c) = ch4_oxid_tot(c) + ch4_oxid_depth_sat(c,j)*dz(c,j)*catomw @@ -2144,27 +2206,29 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & ! Finalize CH4 balance and check for errors call ch4_totcolch4(bounds, num_nolakec, filter_nolakec, num_lakec, filter_lakec, & - ch4_inst, totcolch4(bounds%begc:bounds%endc)) + ch4_inst, totcolch4_col(bounds%begc:bounds%endc)) + + ! Column level balance do fc = 1, num_soilc c = filter_soilc(fc) + g = col%gridcell(c) - if (.not. ch4_first_time(c)) then + if (.not. ch4_first_time_grc(g)) then ! Check balance - errch4 = totcolch4(c) - totcolch4_bef(c) & + errch4 = totcolch4_col(c) - totcolch4_bef_col(c) & - dtime*(ch4_prod_tot(c) - ch4_oxid_tot(c) & - - ch4_surf_flux_tot(c)*1000._r8) ! kg C --> g C + - ch4_surf_flux_tot_col(c)*1000._r8) ! kg C --> g C if (abs(errch4) > 1.e-7_r8) then ! g C / m^2 / timestep - write(iulog,*)'CH4 Conservation Error in CH4Mod driver, nstep, c, errch4 (gC /m^2.timestep)', & + write(iulog,*)'Column-level CH4 Conservation Error in CH4Mod driver, nstep, c, errch4 (gC /m^2.timestep)', & nstep,c,errch4 - g = col%gridcell(c) write(iulog,*)'Latdeg,Londeg,col%itype=',grc%latdeg(g),grc%londeg(g),col%itype(c) - write(iulog,*)'totcolch4 = ', totcolch4(c) - write(iulog,*)'totcolch4_bef = ', totcolch4_bef(c) + write(iulog,*)'totcolch4_col = ', totcolch4_col(c) + write(iulog,*)'totcolch4_bef_col = ', totcolch4_bef_col(c) write(iulog,*)'dtime*ch4_prod_tot = ', dtime*ch4_prod_tot(c) write(iulog,*)'dtime*ch4_oxid_tot = ', dtime*ch4_oxid_tot(c) write(iulog,*)'dtime*ch4_surf_flux_tot*1000 = ', dtime*& - ch4_surf_flux_tot(c)*1000._r8 + ch4_surf_flux_tot_col(c)*1000._r8 call endrun(msg=' ERROR: Methane conservation error'//errMsg(sourcefile, __LINE__)) end if end if @@ -2173,23 +2237,23 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & if (allowlakeprod) then do fc = 1, num_lakec c = filter_lakec(fc) + g = col%gridcell(c) - if (.not. ch4_first_time(c)) then + if (.not. ch4_first_time_grc(g)) then ! Check balance - errch4 = totcolch4(c) - totcolch4_bef(c) & + errch4 = totcolch4_col(c) - totcolch4_bef_col(c) & - dtime*(ch4_prod_tot(c) - ch4_oxid_tot(c) & - - ch4_surf_flux_tot(c)*1000._r8) ! kg C --> g C + - ch4_surf_flux_tot_col(c)*1000._r8) ! kg C --> g C if (abs(errch4) > 1.e-7_r8) then ! g C / m^2 / timestep - write(iulog,*)'CH4 Conservation Error in CH4Mod driver for lake column, nstep, c, errch4 (gC/m^2.timestep)', & + write(iulog,*)'Column-level CH4 Conservation Error in CH4Mod driver for lake column, nstep, c, errch4 (gC/m^2.timestep)', & nstep,c,errch4 - g = col%gridcell(c) write(iulog,*)'Latdeg,Londeg=',grc%latdeg(g),grc%londeg(g) - write(iulog,*)'totcolch4 = ', totcolch4(c) - write(iulog,*)'totcolch4_bef = ', totcolch4_bef(c) + write(iulog,*)'totcolch4_col = ', totcolch4_col(c) + write(iulog,*)'totcolch4_bef_col = ', totcolch4_bef_col(c) write(iulog,*)'dtime*ch4_prod_tot = ', dtime*ch4_prod_tot(c) write(iulog,*)'dtime*ch4_oxid_tot = ', dtime*ch4_oxid_tot(c) write(iulog,*)'dtime*ch4_surf_flux_tot*1000 = ', dtime*& - ch4_surf_flux_tot(c)*1000._r8 + ch4_surf_flux_tot_col(c)*1000._r8 call endrun(msg=' ERROR: Methane conservation error, allowlakeprod'//& errMsg(sourcefile, __LINE__)) end if @@ -2198,7 +2262,7 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & end do end if - ! Now average up to gridcell for fluxes + ! Now average up to gridcell for fluxes and totcolch4 call c2g( bounds, & ch4_oxid_tot(begc:endc), ch4co2f(begg:endg), & c2l_scale_type= 'unity', l2g_scale_type='unity' ) @@ -2211,7 +2275,37 @@ subroutine ch4 (bounds, num_soilc, filter_soilc, num_lakec, filter_lakec, & nem_col(begc:endc), nem_grc(begg:endg), & c2l_scale_type= 'unity', l2g_scale_type='unity' ) - ch4_first_time(begc:endc) = .false. + call c2g( bounds, & + ch4_surf_flux_tot_col(begc:endc), ch4_surf_flux_tot_grc(begg:endg), & + c2l_scale_type= 'unity', l2g_scale_type='unity' ) + + call c2g( bounds, & + ch4_inst%totcolch4_col(begc:endc), & + ch4_inst%totcolch4_grc(begg:endg), & + c2l_scale_type= 'unity', l2g_scale_type='unity' ) + + ! Gricell level balance + + do g = begg, endg + if (.not. ch4_first_time_grc(g)) then + ! Check balance + errch4 = totcolch4_grc(g) - totcolch4_bef_grc(g) + dtime * & + (nem_grc(g) + ch4_surf_flux_tot_grc(g) * 1000._r8) ! kg C --> g C + + if (abs(errch4) > 1.e-7_r8) then ! g C / m^2 / timestep + write(iulog,*)'Gridcell-level CH4 Conservation Error in CH4Mod driver, nstep, g, errch4 (gC /m^2.timestep)', & + nstep, g, errch4 + write(iulog,*)'latdeg, londeg =', grc%latdeg(g), grc%londeg(g) + write(iulog,*)'totcolch4_grc =', totcolch4_grc(g) + write(iulog,*)'totcolch4_bef_grc =', totcolch4_bef_grc(g) + write(iulog,*)'dtime * nem_grc =', dtime * nem_grc(g) + write(iulog,*)'dtime * ch4_surf_flux_tot * 1000 =', dtime * ch4_surf_flux_tot_grc(g) * 1000._r8 + call endrun(msg=' ERROR: Methane conservation error'//errMsg(sourcefile, __LINE__)) + end if + end if + end do + + ch4_first_time_grc(begg:endg) = .false. end associate diff --git a/src/cpl/mct/lnd_import_export.F90 b/src/cpl/mct/lnd_import_export.F90 index a3e1010730..b93379979a 100644 --- a/src/cpl/mct/lnd_import_export.F90 +++ b/src/cpl/mct/lnd_import_export.F90 @@ -378,7 +378,7 @@ subroutine lnd_export( bounds, waterlnd2atmbulk_inst, lnd2atm_inst, lnd2glc_inst end if if (index_l2x_Fall_methane /= 0) then - l2x(index_l2x_Fall_methane,i) = -lnd2atm_inst%flux_ch4_grc(g) + l2x(index_l2x_Fall_methane,i) = -lnd2atm_inst%ch4_surf_flux_tot_grc(g) endif ! sign convention is positive downward with diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 0838b7a00a..396ecaf344 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -859,7 +859,7 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & minus=.true., ungridded_index=4, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call state_setexport(exportState, 'Fall_methane', bounds, input=lnd2atm_inst%flux_ch4_grc, minus=.true., rc=rc) + call state_setexport(exportState, 'Fall_methane', bounds, input=lnd2atm_inst%ch4_surf_flux_tot_grc, minus=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_setexport(exportState, 'Sl_ram1', bounds, input=lnd2atm_inst%ram1_grc, rc=rc) diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90 index 92c2372a52..4c117abc35 100644 --- a/src/main/clm_driver.F90 +++ b/src/main/clm_driver.F90 @@ -58,7 +58,7 @@ module clm_driver use SoilBiogeochemVerticalProfileMod , only : SoilBiogeochemVerticalProfile use SatellitePhenologyMod , only : SatellitePhenology, interpMonthlyVeg use ndepStreamMod , only : ndep_interp - use ch4Mod , only : ch4, ch4_init_balance_check + use ch4Mod , only : ch4, ch4_init_gridcell_balance_check, ch4_init_column_balance_check use DUSTMod , only : DustDryDep, DustEmission use VOCEmissionMod , only : VOCEmission ! @@ -318,6 +318,12 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro c14_soilbiogeochem_carbonstate_inst, & soilbiogeochem_nitrogenstate_inst) end if + if (use_lch4) then + call ch4_init_gridcell_balance_check(bounds_clump, & + filter(nc)%num_nolakec, filter(nc)%nolakec, & + filter(nc)%num_lakec, filter(nc)%lakec, & + ch4_inst) + end if call t_stopf('begcnbal_grc') end do @@ -397,7 +403,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro end if if (use_lch4) then - call ch4_init_balance_check(bounds_clump, & + call ch4_init_column_balance_check(bounds_clump, & filter(nc)%num_nolakec, filter(nc)%nolakec, & filter(nc)%num_lakec, filter(nc)%lakec, & ch4_inst) diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90 index acb0f5cfff..2fbea9433a 100644 --- a/src/main/lnd2atmMod.F90 +++ b/src/main/lnd2atmMod.F90 @@ -328,15 +328,6 @@ subroutine lnd2atm(bounds, & lnd2atm_inst%flxdst_grc (bounds%begg:bounds%endg, :), & p2c_scale_type='unity', c2l_scale_type= 'unity', l2g_scale_type='unity') - - ! ch4 flux - if (use_lch4) then - call c2g( bounds, & - ch4_inst%ch4_surf_flux_tot_col (bounds%begc:bounds%endc), & - lnd2atm_inst%flux_ch4_grc (bounds%begg:bounds%endg), & - c2l_scale_type= 'unity', l2g_scale_type='unity' ) - end if - !---------------------------------------------------- ! lnd -> rof !---------------------------------------------------- diff --git a/src/main/lnd2atmType.F90 b/src/main/lnd2atmType.F90 index 509a8afaf2..a0e8623018 100644 --- a/src/main/lnd2atmType.F90 +++ b/src/main/lnd2atmType.F90 @@ -56,7 +56,7 @@ module lnd2atmType real(r8), pointer :: flxvoc_grc (:,:) => null() ! VOC flux (size bins) real(r8), pointer :: fireflx_grc (:,:) => null() ! Wild Fire Emissions real(r8), pointer :: fireztop_grc (:) => null() ! Wild Fire Emissions vertical distribution top - real(r8), pointer :: flux_ch4_grc (:) => null() ! net CH4 flux (kg C/m**2/s) [+ to atm] + real(r8), pointer :: ch4_surf_flux_tot_grc(:) => null() ! net CH4 flux (kg C/m**2/s) [+ to atm] ! lnd->rof contains @@ -150,7 +150,7 @@ subroutine InitAllocate(this, bounds) allocate(this%ram1_grc (begg:endg)) ; this%ram1_grc (:) =ival allocate(this%fv_grc (begg:endg)) ; this%fv_grc (:) =ival allocate(this%flxdst_grc (begg:endg,1:ndst)) ; this%flxdst_grc (:,:) =ival - allocate(this%flux_ch4_grc (begg:endg)) ; this%flux_ch4_grc (:) =ival + allocate(this%ch4_surf_flux_tot_grc(begg:endg)) ; this%ch4_surf_flux_tot_grc(:) =ival if (shr_megan_mechcomps_n>0) then allocate(this%flxvoc_grc(begg:endg,1:shr_megan_mechcomps_n)); this%flxvoc_grc(:,:)=ival @@ -269,10 +269,10 @@ subroutine InitHistory(this, bounds) default='inactive') if (use_lch4) then - this%flux_ch4_grc(begg:endg) = 0._r8 + this%ch4_surf_flux_tot_grc(begg:endg) = 0._r8 call hist_addfld1d (fname='FCH4', units='kgC/m2/s', & avgflag='A', long_name='Gridcell surface CH4 flux to atmosphere (+ to atm)', & - ptr_lnd=this%flux_ch4_grc) + ptr_lnd=this%ch4_surf_flux_tot_grc) this%nem_grc(begg:endg) = spval call hist_addfld1d (fname='NEM', units='gC/m2/s', &