From e8fb92b4fbe9d03433ea58efdcf1aa66d152e9a6 Mon Sep 17 00:00:00 2001 From: wwieder Date: Tue, 23 Sep 2025 08:51:09 -0600 Subject: [PATCH 1/3] overflow respiration bug fixes #3491 --- .../SoilBiogeochemCarbonFluxType.F90 | 2 + .../SoilBiogeochemCompetitionMod.F90 | 16 ++++---- .../SoilBiogeochemPotentialMod.F90 | 40 ++++++++++++++----- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 index 23f24e44d5..ae127fcd59 100644 --- a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 @@ -469,6 +469,8 @@ subroutine InitHistory(this, bounds, carbon_type) call hist_addfld2d (fname='HR_vr', units='gC/m^3/s', type2d='levsoi', & avgflag='A', long_name='total vertically resolved heterotrophic respiration', & ptr_col=data2dptr) + + ! WW TODO is this where I can add overflow_vr fluxes to history? endif end if diff --git a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 index 57bc82984e..afcd97b213 100644 --- a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 @@ -253,8 +253,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,nu sminn_vr => soilbiogeochem_nitrogenstate_inst%sminn_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral N smin_nh4_vr => soilbiogeochem_nitrogenstate_inst%smin_nh4_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral NH4 smin_no3_vr => soilbiogeochem_nitrogenstate_inst%smin_no3_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral NO3 - - c_overflow_vr => soilbiogeochem_carbonflux_inst%c_overflow_vr , & ! Output: [real(r8) (:,:,:)] (gC/m3/s) vertically-resolved C rejected by microbes that cannot process it + !WW handling overflow respiration in SoilBiogeochemPotentialMod for now + !c_overflow_vr => soilbiogeochem_carbonflux_inst%c_overflow_vr , & ! Output: [real(r8) (:,:,:)] (gC/m3/s) vertically-resolved C rejected by microbes that cannot process it cascade_receiver_pool => decomp_cascade_con%cascade_receiver_pool , & ! Input: [integer (:) ] which pool is C added to for a given decomposition step pot_f_nit_vr => soilbiogeochem_nitrogenflux_inst%pot_f_nit_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3/s) potential soil nitrification flux @@ -821,6 +821,7 @@ subroutine SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,nu cascade_receiver_pool(k) == i_oli_mic) then sum_ndemand_vr(c,j) = sum_no3_demand_scaled(c,j) + & sum_nh4_demand_scaled(c,j) + ! WW effectively turn this off now, since pmnf_decomp_cascade < 0 for mineralization if (pmnf_decomp_cascade(c,j,k) > 0.0_r8 .and. & sum_ndemand_vr(c,j) > 0.0_r8) then amnf_immob_vr = (sminn_vr(c,j) / dt) * & @@ -828,19 +829,20 @@ subroutine SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,nu sum_ndemand_vr(c,j)) n_deficit_vr = pmnf_decomp_cascade(c,j,k) - & amnf_immob_vr - c_overflow_vr(c,j,k) = & - n_deficit_vr * p_decomp_cn_gain(c,j,cascade_receiver_pool(k)) + !c_overflow_vr(c,j,k) = & + ! n_deficit_vr * p_decomp_cn_gain(c,j,cascade_receiver_pool(k)) + ! TODO, need to updated p_decomp_c_gain accordingly else ! not pmnf and sum_ndemand > 0 - c_overflow_vr(c,j,k) = 0.0_r8 + !c_overflow_vr(c,j,k) = 0.0_r8 end if else ! not microbes receiving - c_overflow_vr(c,j,k) = 0.0_r8 + !c_overflow_vr(c,j,k) = 0.0_r8 end if end do end do end do else ! not mimics_decomp - c_overflow_vr(:,:,:) = 0.0_r8 + !c_overflow_vr(:,:,:) = 0.0_r8 end if if(.not.local_use_fun)then diff --git a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 index deb9bdbf78..38098f445f 100644 --- a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 @@ -104,6 +104,7 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & real(r8):: p_decomp_npool_gain_sum(1:ndecomp_pools) ! total potential N gain by receiver pool (only microbial pools) real(r8):: decomp_nc_loss_donor ! N:C ratio of donor pool real(r8):: p_decomp_cn_diff_ratio ! relative change in receiver pool C:N + real(r8):: adjusted_c_to_mic ! relative change in receiver pool C:N real(r8):: p_decomp_npool_loss ! potential N flux out of donor pool real(r8):: ratio !temporary variable !----------------------------------------------------------------------- @@ -129,6 +130,7 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & decomp_npools_vr => soilbiogeochem_nitrogenstate_inst%decomp_npools_vr_col , & ! Input: [real(r8) (:,:,:) ] (gC/m3) vertically-resolved decomposing (litter, cwd, soil) N pools decomp_cpools_vr => soilbiogeochem_carbonstate_inst%decomp_cpools_vr_col , & ! Input: [real(r8) (:,:,:) ] (gC/m3) vertically-resolved decomposing (litter, cwd, soil) c pools + c_overflow_vr => soilbiogeochem_carbonflux_inst%c_overflow_vr , & ! Output: [real(r8) (:,:,:)] (gC/m3/s) vertically-resolved C rejected by microbes that cannot process it potential_immob_vr => soilbiogeochem_nitrogenflux_inst%potential_immob_vr_col , & ! Output: [real(r8) (:,:) ] gross_nmin_vr => soilbiogeochem_nitrogenflux_inst%gross_nmin_vr_col , & ! Output: [real(r8) (:,:) ] @@ -198,6 +200,7 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & endif else ! CWD -> litter OR mimics_decomp is true pmnf_decomp_cascade(c,j,k) = 0._r8 + c_overflow_vr(c,j,k) = 0._r8 if (decomp_method == mimics_decomp) then ! N:C ratio of donor pools (N:C instead of C:N because @@ -271,18 +274,33 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & cascade_receiver_pool(k) == i_oli_mic) then if (decomp_cpools_vr(c,j,cascade_donor_pool(k)) > 0._r8 .and. & decomp_k(c,j,cascade_donor_pool(k)) > 0._r8 ) then - ! if p_decomp_cn_diff < 0 N mineralization - ! > 0 immobilization - ! "min" in next line turns off immobilization flux - p_decomp_cn_diff_ratio = min(0.0_r8, & + ! if p_decomp_cn_diff_ratio < 0 N mineralization + ! > 0 immobilization + !! Easier here if p_decomp_cn_diff_ratio < 0 + !! then calculate C supply for each N flux to meet cn_col demands + !! and extra C goes to overflow respiration + !! This approcah this would be on a per flux basis + !! Alternatively could sum all C and N fluxes into microbes and then balance stoich + !! but this would have to take place outside of k loop + p_decomp_cn_diff_ratio = & (p_decomp_cn_gain(c,j,cascade_receiver_pool(k)) - & - cn_col(c,cascade_receiver_pool(k))) / cn_col(c,cascade_receiver_pool(k))) - ! Actual amount of N that's mineralized or that would - ! need to be immobilized - ! negative=mineralization: add to the DIN pool - ! positive=immobilizaiton: compete for N with plants to - ! see how much we get - pmnf_decomp_cascade(c,j,k) = p_decomp_cn_diff_ratio * p_decomp_npool_gain(c,j,k) + cn_col(c,cascade_receiver_pool(k))) / cn_col(c,cascade_receiver_pool(k)) + + ! Actual amount of N that's mineralized or that would be need to be immobilized + ! negative=mineralization: add to the DIN pool + ! positive=immobilizaiton: compete for N with plants to see how much we get + ! WW Overflow respiration calculation requires positive ratio to be active + ! TODO may need to think about how we track actual immobilization fluxes too? + if (p_decomp_cn_diff_ratio <= 0._r8) then + pmnf_decomp_cascade(c,j,k) = p_decomp_cn_diff_ratio * p_decomp_npool_gain(c,j,k) + c_overflow_vr(c,j,k) = 0.0_r8 + else + ! Assumes each flux into MIC must be in stoichiometric ballance + ! Could also sum at all C fluxes into MIC and then maintain stoichiometry + pmnf_decomp_cascade(c,j,k) = 0._r8 + adjusted_c_to_mic = p_decomp_npool_gain(c,j,k) * cn_col(c,cascade_receiver_pool(k)) + c_overflow_vr(c,j,k) = p_decomp_cpool_gain(c,j,k) - adjusted_c_to_mic + end if end if ! donors donating (decomp_cpools_vr & decomp_k > 0) end if ! microbes receiving end do ! transitions loop From 19d4a34bb1936cc19ca6aceae9db57767cfb6fb9 Mon Sep 17 00:00:00 2001 From: wwieder Date: Mon, 23 Feb 2026 05:55:29 -0700 Subject: [PATCH 2/3] unused temperature threshold --- .../SoilBiogeochemDecompCascadeMIMICSMod.F90 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 b/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 index c9eb91bfa8..6c327fdd04 100644 --- a/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemDecompCascadeMIMICSMod.F90 @@ -1179,6 +1179,14 @@ subroutine decomp_rates_mimics(bounds, num_bgc_soilc, filter_bgc_soilc, & ! place the conversion once in w_d_o_scalars tau_m1 = mimics_tau_r_p1 * exp(mimics_tau_r_p2 * fmet) * tau_mod / & secsphr + ! WW testing adding temperature threshold for microbial turnover + ! Here with copios shutting down in cold temps + ! TODO, make min soil temperatures and scaling factor parameters + + !IF (t_soi_degC < 1._r8) THEN + ! tau_m1 = tau_m1 * 2._r8 + !END IF + tau_m2 = mimics_tau_k_p1 * exp(mimics_tau_k_p2 * fmet) * tau_mod / & secsphr From 79fca6535c7222d9a39d7d05192b55ee3a6b1fef Mon Sep 17 00:00:00 2001 From: wwieder Date: Mon, 11 May 2026 11:16:02 -0600 Subject: [PATCH 3/3] Revert to "overflow respiration bug fixes #3491" This reverts commit e8fb92b4fbe9d03433ea58efdcf1aa66d152e9a6. --- .../SoilBiogeochemCarbonFluxType.F90 | 2 - .../SoilBiogeochemCompetitionMod.F90 | 16 ++++---- .../SoilBiogeochemPotentialMod.F90 | 40 +++++-------------- 3 files changed, 18 insertions(+), 40 deletions(-) diff --git a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 index ae127fcd59..23f24e44d5 100644 --- a/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCarbonFluxType.F90 @@ -469,8 +469,6 @@ subroutine InitHistory(this, bounds, carbon_type) call hist_addfld2d (fname='HR_vr', units='gC/m^3/s', type2d='levsoi', & avgflag='A', long_name='total vertically resolved heterotrophic respiration', & ptr_col=data2dptr) - - ! WW TODO is this where I can add overflow_vr fluxes to history? endif end if diff --git a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 index afcd97b213..57bc82984e 100644 --- a/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemCompetitionMod.F90 @@ -253,8 +253,8 @@ subroutine SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,nu sminn_vr => soilbiogeochem_nitrogenstate_inst%sminn_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral N smin_nh4_vr => soilbiogeochem_nitrogenstate_inst%smin_nh4_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral NH4 smin_no3_vr => soilbiogeochem_nitrogenstate_inst%smin_no3_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3) soil mineral NO3 - !WW handling overflow respiration in SoilBiogeochemPotentialMod for now - !c_overflow_vr => soilbiogeochem_carbonflux_inst%c_overflow_vr , & ! Output: [real(r8) (:,:,:)] (gC/m3/s) vertically-resolved C rejected by microbes that cannot process it + + c_overflow_vr => soilbiogeochem_carbonflux_inst%c_overflow_vr , & ! Output: [real(r8) (:,:,:)] (gC/m3/s) vertically-resolved C rejected by microbes that cannot process it cascade_receiver_pool => decomp_cascade_con%cascade_receiver_pool , & ! Input: [integer (:) ] which pool is C added to for a given decomposition step pot_f_nit_vr => soilbiogeochem_nitrogenflux_inst%pot_f_nit_vr_col , & ! Input: [real(r8) (:,:) ] (gN/m3/s) potential soil nitrification flux @@ -821,7 +821,6 @@ subroutine SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,nu cascade_receiver_pool(k) == i_oli_mic) then sum_ndemand_vr(c,j) = sum_no3_demand_scaled(c,j) + & sum_nh4_demand_scaled(c,j) - ! WW effectively turn this off now, since pmnf_decomp_cascade < 0 for mineralization if (pmnf_decomp_cascade(c,j,k) > 0.0_r8 .and. & sum_ndemand_vr(c,j) > 0.0_r8) then amnf_immob_vr = (sminn_vr(c,j) / dt) * & @@ -829,20 +828,19 @@ subroutine SoilBiogeochemCompetition (bounds, num_bgc_soilc, filter_bgc_soilc,nu sum_ndemand_vr(c,j)) n_deficit_vr = pmnf_decomp_cascade(c,j,k) - & amnf_immob_vr - !c_overflow_vr(c,j,k) = & - ! n_deficit_vr * p_decomp_cn_gain(c,j,cascade_receiver_pool(k)) - ! TODO, need to updated p_decomp_c_gain accordingly + c_overflow_vr(c,j,k) = & + n_deficit_vr * p_decomp_cn_gain(c,j,cascade_receiver_pool(k)) else ! not pmnf and sum_ndemand > 0 - !c_overflow_vr(c,j,k) = 0.0_r8 + c_overflow_vr(c,j,k) = 0.0_r8 end if else ! not microbes receiving - !c_overflow_vr(c,j,k) = 0.0_r8 + c_overflow_vr(c,j,k) = 0.0_r8 end if end do end do end do else ! not mimics_decomp - !c_overflow_vr(:,:,:) = 0.0_r8 + c_overflow_vr(:,:,:) = 0.0_r8 end if if(.not.local_use_fun)then diff --git a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 index 38098f445f..deb9bdbf78 100644 --- a/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 +++ b/src/soilbiogeochem/SoilBiogeochemPotentialMod.F90 @@ -104,7 +104,6 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & real(r8):: p_decomp_npool_gain_sum(1:ndecomp_pools) ! total potential N gain by receiver pool (only microbial pools) real(r8):: decomp_nc_loss_donor ! N:C ratio of donor pool real(r8):: p_decomp_cn_diff_ratio ! relative change in receiver pool C:N - real(r8):: adjusted_c_to_mic ! relative change in receiver pool C:N real(r8):: p_decomp_npool_loss ! potential N flux out of donor pool real(r8):: ratio !temporary variable !----------------------------------------------------------------------- @@ -130,7 +129,6 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & decomp_npools_vr => soilbiogeochem_nitrogenstate_inst%decomp_npools_vr_col , & ! Input: [real(r8) (:,:,:) ] (gC/m3) vertically-resolved decomposing (litter, cwd, soil) N pools decomp_cpools_vr => soilbiogeochem_carbonstate_inst%decomp_cpools_vr_col , & ! Input: [real(r8) (:,:,:) ] (gC/m3) vertically-resolved decomposing (litter, cwd, soil) c pools - c_overflow_vr => soilbiogeochem_carbonflux_inst%c_overflow_vr , & ! Output: [real(r8) (:,:,:)] (gC/m3/s) vertically-resolved C rejected by microbes that cannot process it potential_immob_vr => soilbiogeochem_nitrogenflux_inst%potential_immob_vr_col , & ! Output: [real(r8) (:,:) ] gross_nmin_vr => soilbiogeochem_nitrogenflux_inst%gross_nmin_vr_col , & ! Output: [real(r8) (:,:) ] @@ -200,7 +198,6 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & endif else ! CWD -> litter OR mimics_decomp is true pmnf_decomp_cascade(c,j,k) = 0._r8 - c_overflow_vr(c,j,k) = 0._r8 if (decomp_method == mimics_decomp) then ! N:C ratio of donor pools (N:C instead of C:N because @@ -274,33 +271,18 @@ subroutine SoilBiogeochemPotential (bounds, num_bgc_soilc, filter_bgc_soilc, & cascade_receiver_pool(k) == i_oli_mic) then if (decomp_cpools_vr(c,j,cascade_donor_pool(k)) > 0._r8 .and. & decomp_k(c,j,cascade_donor_pool(k)) > 0._r8 ) then - ! if p_decomp_cn_diff_ratio < 0 N mineralization - ! > 0 immobilization - !! Easier here if p_decomp_cn_diff_ratio < 0 - !! then calculate C supply for each N flux to meet cn_col demands - !! and extra C goes to overflow respiration - !! This approcah this would be on a per flux basis - !! Alternatively could sum all C and N fluxes into microbes and then balance stoich - !! but this would have to take place outside of k loop - p_decomp_cn_diff_ratio = & + ! if p_decomp_cn_diff < 0 N mineralization + ! > 0 immobilization + ! "min" in next line turns off immobilization flux + p_decomp_cn_diff_ratio = min(0.0_r8, & (p_decomp_cn_gain(c,j,cascade_receiver_pool(k)) - & - cn_col(c,cascade_receiver_pool(k))) / cn_col(c,cascade_receiver_pool(k)) - - ! Actual amount of N that's mineralized or that would be need to be immobilized - ! negative=mineralization: add to the DIN pool - ! positive=immobilizaiton: compete for N with plants to see how much we get - ! WW Overflow respiration calculation requires positive ratio to be active - ! TODO may need to think about how we track actual immobilization fluxes too? - if (p_decomp_cn_diff_ratio <= 0._r8) then - pmnf_decomp_cascade(c,j,k) = p_decomp_cn_diff_ratio * p_decomp_npool_gain(c,j,k) - c_overflow_vr(c,j,k) = 0.0_r8 - else - ! Assumes each flux into MIC must be in stoichiometric ballance - ! Could also sum at all C fluxes into MIC and then maintain stoichiometry - pmnf_decomp_cascade(c,j,k) = 0._r8 - adjusted_c_to_mic = p_decomp_npool_gain(c,j,k) * cn_col(c,cascade_receiver_pool(k)) - c_overflow_vr(c,j,k) = p_decomp_cpool_gain(c,j,k) - adjusted_c_to_mic - end if + cn_col(c,cascade_receiver_pool(k))) / cn_col(c,cascade_receiver_pool(k))) + ! Actual amount of N that's mineralized or that would + ! need to be immobilized + ! negative=mineralization: add to the DIN pool + ! positive=immobilizaiton: compete for N with plants to + ! see how much we get + pmnf_decomp_cascade(c,j,k) = p_decomp_cn_diff_ratio * p_decomp_npool_gain(c,j,k) end if ! donors donating (decomp_cpools_vr & decomp_k > 0) end if ! microbes receiving end do ! transitions loop