diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d9bb568c..27e8c155 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -30,6 +30,7 @@ sections to include in release notes: - `leafon` and `leafoff` events for tracking phenological transitions (#326) - `leafon` limited by available carbon and nitrogen; N storage pool; N resorption on `leafoff` (#337) - New required parameter `leafOnReallocFrac` to control how much of wood and coarse root carbon is reallocated to leaves on `leafon` (#337) +- `carbonSaturation` flag and calculation of soil and litter carbon pools that observes soil carbon saturating behavior (#301) ### Fixed diff --git a/docs/model-structure.md b/docs/model-structure.md index 80f506c4..aed428f0 100644 --- a/docs/model-structure.md +++ b/docs/model-structure.md @@ -309,6 +309,13 @@ F^C_\text{fert,org} Where $K_{\text{plant},i}$ is the turnover rate of plant pool $i$ that controls the rate at which plant biomass is transferred to litter. +When soil carbon saturation is enabled, a fraction of soil carbon inputs may be redirected to the litter pool as fast-turnover carbon. This functionality is described in more detail below in the Soil Carbon section \eqref{eq:soil_carbon_saturation}. + +\begin{equation} +\frac{dC_\text{litter}}{dt} = F^C_\text{litter} + F^C_{\text{soil}} \cdot \frac{C_{\text{soil}}}{C_{\text{soil,saturation}}} - F^C_{\text{decomp}} - F^C_{\text{CH}_4\text{,litter}} +\label{eq:soil_carbon_to_litter} +\end{equation} + $F^C_{\text{decomp}}$ represents the rate at which litter carbon is processed by microbial activity. Litter decomposition is modeled as a first-order process proportional to litter carbon content and modified by temperature and moisture: @@ -370,6 +377,15 @@ F^C_{\text{soil}} = F^C_{\text{soil,litter}} + F^C_{\text{soil,roots}} \label{eq:soil_carbon_flux} \end{equation} +When soil carbon saturation is enabled, only a saturation-dependent fraction of gross soil C inputs is added to the soil pool. This fraction declines as $C_{\text{soil}}$ approaches the specified soil C saturation limit. The remaining input C is redirected to the litter pool \eqref{eq:soil_carbon_to_litter} as fast-turnover carbon rather than being added to the soil pool. + +\begin{equation} +\frac{dC_\text{soil}}{dt} = F^C_{\text{soil}} \cdot (1 - \frac{C_{\text{soil}}}{C_{\text{soil,saturation}}}) - R_{\text{soil}} - F^C_{\text{CH}_4\text{,soil}} +\label{eq:soil_carbon_saturation} +\end{equation} + +where $C_{\text{soil,saturation}}$ is the soil carbon saturation limit entered as an input paramter. This is based on equation (3) from Stewart et al. (2007). + Soil heterotrophic respiration is modeled as a first-order process proportional to soil organic carbon content and modified by environmental and management factors: diff --git a/docs/parameters.md b/docs/parameters.md index 41318140..15cfe141 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -197,6 +197,7 @@ Run-time parameters can change from one run to the next, or when the model is st | $Q_{10s}$ | soilRespQ10 | Soil respiration Q10 | unitless | scalar determining effect of temp on soil respiration | | $D_{\text{moisture}}$ | soilRespMoistEffect | scalar determining effect of moisture on soil resp. | unitless | | | $f_{\text{till}}$ | tillageEff | Effect of tillage on decomposition that exponentially decays over time | fraction | Documented in model structure; event-level term in `events.in` | +| $C_{\text{soil,saturation}}$ | soilCSaturation | Maximum amount of carbon that can be stabilized in the soil determined by soil texture | $\text{g C} \cdot \text{m}^{-2} \text{ ground area}$ | | ### Nitrogen Cycle Parameters diff --git a/docs/user-guide/model-inputs.md b/docs/user-guide/model-inputs.md index b1be9896..ad4eff7a 100644 --- a/docs/user-guide/model-inputs.md +++ b/docs/user-guide/model-inputs.md @@ -242,6 +242,7 @@ Thus, command-line arguments override settings in the configuration file, and co | `snow` | on | Keep track of snowpack, rather than assuming all precipitation is liquid | | `soil-phenol` | off | Use soil temperature to determine leaf growth | | `water-hresp` | on | Whether soil moisture affects heterotrophic respiration | +| `carbon-saturation`| off | Enable soil carbon saturation behavior to constrain carbon stored in soil | Note the following restrictions on these options: - `soil-phenol` and `gdd` may not both be turned on diff --git a/docs/user-guide/running-sipnet.md b/docs/user-guide/running-sipnet.md index c2f2e577..4b5e02bf 100644 --- a/docs/user-guide/running-sipnet.md +++ b/docs/user-guide/running-sipnet.md @@ -48,6 +48,7 @@ These flags enable or disable optional model processes. Prepend `no-` to the fla | `--snow` | ON (1) | Track snowpack separately; if disabled, all precipitation is treated as liquid | | `--soil-phenol` | OFF (0) | Use soil temperature (instead of growing degree days) to determine leaf growth | | `--water-hresp` | ON (1) | Allow soil moisture to affect heterotrophic respiration rates | +| `--carbon-saturation`| OFF (0) | Enable soil carbon saturation behavior to constrain carbon stored in soil | #### Model Flag Restrictions @@ -56,6 +57,7 @@ The following flag constraints are enforced: - `--soil-phenol` and `--gdd` cannot both be enabled - `--anaerobic` requires `--water-hresp` - `--nitrogen-cycle` requires both `--litter-pool` and `--anaerobic` +- `--carbon-saturation` requires `--litter-pool` ### Output Flags diff --git a/src/common/context.c b/src/common/context.c index 3564f3ff..3f9dd1dc 100644 --- a/src/common/context.c +++ b/src/common/context.c @@ -43,6 +43,7 @@ void initContext(void) { CREATE_INT_CONTEXT(nitrogenCycle, "NITROGEN_CYCLE", ARG_OFF, FLAG_YES); CREATE_INT_CONTEXT(anaerobic, "ANAEROBIC", ARG_OFF, FLAG_YES); CREATE_INT_CONTEXT(flooding, "FLOODING", ARG_OFF, FLAG_YES); + CREATE_INT_CONTEXT(carbonSaturation,"CARBON_SATURATION",ARG_OFF, FLAG_YES); // Flags, I/O CREATE_INT_CONTEXT(doMainOutput, "DO_MAIN_OUTPUT", ARG_ON, FLAG_YES); @@ -209,6 +210,12 @@ void validateContext(void) { hasError = 1; } + if (ctx.carbonSaturation && !ctx.litterPool) { + logError("carbon-saturation requires litter-pool to be " + "turned on\n"); + hasError = 1; + } + if (hasError) { exit(EXIT_CODE_BAD_PARAMETER_VALUE); } diff --git a/src/common/context.h b/src/common/context.h index ddafc4b9..fb8d2650 100644 --- a/src/common/context.h +++ b/src/common/context.h @@ -36,7 +36,7 @@ struct context_metadata { UT_hash_handle hh; // makes this structure hashable }; -#define NUM_CONTEXT_MODEL_FLAGS 11 +#define NUM_CONTEXT_MODEL_FLAGS 12 // See docs/developer-guide/cli-options.md for details on how to add a new // Context entry struct Context { @@ -53,7 +53,7 @@ struct Context { int nitrogenCycle; int anaerobic; int flooding; - + int carbonSaturation; // IF ADDING A NEW MODEL FLAG, update NUM_CONTEXT_MODEL_FLAGS above and // relevant code in restart.c diff --git a/src/sipnet/cli.c b/src/sipnet/cli.c index ab71d397..231c835e 100644 --- a/src/sipnet/cli.c +++ b/src/sipnet/cli.c @@ -32,6 +32,7 @@ static struct option long_options[] = { // NOLINT DECLARE_FLAG(nitrogen-cycle), DECLARE_FLAG(anaerobic), DECLARE_FLAG(flooding), + DECLARE_FLAG(carbon-saturation), DECLARE_FLAG(do-main-output), DECLARE_FLAG(do-single-outputs), @@ -65,7 +66,7 @@ char *argNameMap[] = { DECLARE_ARG_FOR_MAP(litterPool), DECLARE_ARG_FOR_MAP(snow), DECLARE_ARG_FOR_MAP(soilPhenol), DECLARE_ARG_FOR_MAP(waterHResp), DECLARE_ARG_FOR_MAP(nitrogenCycle), DECLARE_ARG_FOR_MAP(anaerobic), - DECLARE_ARG_FOR_MAP(flooding), + DECLARE_ARG_FOR_MAP(flooding), DECLARE_ARG_FOR_MAP(carbonSaturation), // I/O DECLARE_ARG_FOR_MAP(doMainOutput), DECLARE_ARG_FOR_MAP(doSingleOutputs), @@ -98,6 +99,7 @@ void usage(char *progName) { printf(" --snow Keep track of snowpack, rather than assuming all precipitation is liquid (1)\n"); printf(" --soil-phenol Use soil temperature to determine leaf growth (0)\n"); printf(" --water-hresp Whether soil moisture affects heterotrophic respiration (1)\n"); + printf(" --carbon-saturation Enable maximum storage limit of soil organic carbon (0)\n"); printf("\n"); printf("Output flags: (prepend flag with 'no-' to force off, eg '--no-print-header')\n"); printf(" --do-main-output Print time series of all output variables to .out (1)\n"); @@ -121,6 +123,7 @@ void usage(char *progName) { printf(" --soil-phenol and --gdd may not both be turned on\n"); printf(" --anaerobic requires --water-hresp\n"); printf(" --nitrogen-cycle requires both --litter-pool and --anaerobic\n"); + printf(" --carbon-saturation requires --litter-pool\n"); // clang-format on } diff --git a/src/sipnet/cli.h b/src/sipnet/cli.h index b1b1ff0f..fab31d3e 100644 --- a/src/sipnet/cli.h +++ b/src/sipnet/cli.h @@ -14,7 +14,7 @@ // The run-time option names do not match their corresponding fields in Context, // so we need a way to get from one to the other. -#define NUM_FLAG_OPTIONS 16 +#define NUM_FLAG_OPTIONS 17 extern char *argNameMap[2 * NUM_FLAG_OPTIONS]; /*! diff --git a/src/sipnet/nitrogen.c b/src/sipnet/nitrogen.c index 626a807c..d0af41c9 100644 --- a/src/sipnet/nitrogen.c +++ b/src/sipnet/nitrogen.c @@ -51,22 +51,32 @@ static void calcNPoolFluxes(void) { double litterMin = fluxes.rLitter / litterCN; double soilMin = fluxes.rSoil / soilCN; + // Adding soil carbon saturation functionality so organic N fluxes to soil + // and litter are proportional to respective carbon fluxes dependent on + // soil carbon saturation + double soilNInputs = fluxes.litterToSoil / litterCN + + fluxes.fineRootLoss / params.fineRootCN + + fluxes.coarseRootLoss / params.woodCN; + // saturationFraction capped between zero and one + double saturationFraction = + (ctx.carbonSaturation) + ? (fmin(1.0, fmax(0.0, envi.soilC / params.soilCSaturation))) + : 0.0; + // litter // The litter org N flux is determined by the carbon fluxes from wood and leaf // litter (modified by leaf N resorption), and N loss due to mineralization. // N added via fertilization is handled elsewhere. - fluxes.nOrgLitter = fluxes.leafLitter / params.leafCN - - fluxes.leafOffNResorption + - fluxes.woodLitter / params.woodCN - litterMin - - fluxes.litterToSoil / litterCN; + fluxes.nOrgLitter = + fluxes.leafLitter / params.leafCN - fluxes.leafOffNResorption + + fluxes.woodLitter / params.woodCN - litterMin - + fluxes.litterToSoil / litterCN + (soilNInputs * saturationFraction); // soil // The soil org N flux is determined by the carbon flux from the litter pool, // carbon fluxes from roots, and N loss due to mineralization // (Note: woodCN is used for coarse roots) - fluxes.nOrgSoil = fluxes.litterToSoil / litterCN - soilMin + - fluxes.fineRootLoss / params.fineRootCN + - fluxes.coarseRootLoss / params.woodCN; + fluxes.nOrgSoil = soilNInputs * (1 - saturationFraction) - soilMin; // mineralization fluxes.nMin = litterMin + soilMin; diff --git a/src/sipnet/restart.c b/src/sipnet/restart.c index 27ae7ccd..9457cc31 100644 --- a/src/sipnet/restart.c +++ b/src/sipnet/restart.c @@ -87,6 +87,7 @@ typedef struct RestartContextModelFlags { int nitrogenCycle; int anaerobic; int flooding; + int carbonSaturation; } RestartContextModelFlags; static RestartContextModelFlags modelFlags; @@ -162,7 +163,8 @@ void initResetState(RestartState *state, MeanTracker *npp) { state->flagsPF[8] = (StateField){"flags.nitrogenCycle", FT_INT, &modelFlags.nitrogenCycle, 0}; state->flagsPF[9] = (StateField){"flags.anaerobic", FT_INT, &modelFlags.anaerobic, 0}; state->flagsPF[10] = (StateField){"flags.flooding", FT_INT, &modelFlags.flooding, 0}; - state->flagsPF[11] = (StateField){"flags.invalid", FT_INVALID, NULL, FIELD_INVALID}; + state->flagsPF[11] = (StateField){"flags.carbonSaturation", FT_INT, &modelFlags.carbonSaturation, 0}; + state->flagsPF[12] = (StateField){"flags.invalid", FT_INVALID, NULL, FIELD_INVALID}; state->boundaryPF[0] = (StateField){"boundary.year", FT_INT, &boundaryClimate.year, 0}; state->boundaryPF[1] = (StateField){"boundary.day", FT_INT, &boundaryClimate.day, 0}; @@ -777,6 +779,7 @@ static void checkRestartContextCompatibility(void) { mismatch |= (ctx.nitrogenCycle != modelFlags.nitrogenCycle); mismatch |= (ctx.anaerobic != modelFlags.anaerobic); mismatch |= (ctx.flooding != modelFlags.flooding); + mismatch |= (ctx.carbonSaturation != modelFlags.carbonSaturation); if (mismatch) { logError("Restart context mismatch: model flags must match checkpoint " @@ -900,6 +903,8 @@ void restartWriteCheckpoint(const char *restartOut, MeanTracker *meanNPP) { ++numFlagsSet; modelFlags.flooding = ctx.flooding; ++numFlagsSet; + modelFlags.carbonSaturation = ctx.carbonSaturation; + ++numFlagsSet; if (numFlagsSet != NUM_CONTEXT_MODEL_FLAGS) { logInternalError("Not all model flags set while writing checkpoint\n"); exit(EXIT_CODE_INTERNAL_ERROR); diff --git a/src/sipnet/sipnet.c b/src/sipnet/sipnet.c index 25d0aa56..ce4b8652 100644 --- a/src/sipnet/sipnet.c +++ b/src/sipnet/sipnet.c @@ -392,6 +392,9 @@ void readParamData(ModelParams **modelParamsPtr, const char *paramFile) { // Water drainage initializeOneModelParam(modelParams, "waterDrainFrac", &(params.waterDrainFrac), ctx.flooding); + // Soil carbon saturation + initializeOneModelParam(modelParams, "soilCSaturation", &(params.soilCSaturation), ctx.carbonSaturation); + // NOLINTEND // clang-format on @@ -1647,15 +1650,27 @@ void updateMainPools(void) { */ void updatePoolsForSoil(void) { if (ctx.litterPool) { + double soilInputs = + fluxes.coarseRootLoss + fluxes.fineRootLoss + fluxes.litterToSoil; + // Adding soil carbon saturation functionality + // soilFraction capped between zero and one + // if envi.soilC > params.soilCSaturation (due to initialization or events) + // saturationFraction will return 1 and no additional soil C inputs will be + // accepted to envi.soilC until losses due to respiration and methane reduce + // pool below saturation level, all inputs will be directed to envi.litterC + // pool while envi.soilC is above saturation level + double saturationFraction = + (ctx.carbonSaturation) + ? (fmin(1.0, fmax(0.0, envi.soilC / params.soilCSaturation))) + : 0.0; // :: from [2], litter model description - envi.litterC += - (fluxes.woodLitter + fluxes.leafLitter - fluxes.litterToSoil - - fluxes.rLitter - fluxes.litterMethane) * - climate->length; - + envi.litterC += (fluxes.woodLitter + fluxes.leafLitter + + (soilInputs * saturationFraction) - fluxes.litterToSoil - + fluxes.rLitter - fluxes.litterMethane) * + climate->length; // from [2] and [3], litter and root terms respectively - envi.soilC += (fluxes.coarseRootLoss + fluxes.fineRootLoss + - fluxes.litterToSoil - fluxes.rSoil - fluxes.soilMethane) * + envi.soilC += (soilInputs * (1 - saturationFraction) - fluxes.rSoil - + fluxes.soilMethane) * climate->length; } else { // Normal pool (single pool, no microbes) diff --git a/src/sipnet/state.h b/src/sipnet/state.h index 7935b88a..a07c0f7b 100644 --- a/src/sipnet/state.h +++ b/src/sipnet/state.h @@ -397,6 +397,14 @@ typedef struct Parameters { // Relative methane production rate in the litter pool, in [0, 1), per day double litterMethaneRate; + + // ****** + // Soil carbon saturation + // ****** + + // Maximum threshold for stabilizing carbon in soil organic pool as + // slow-turnover pool units: g C * m^-2 ground area + double soilCSaturation; } Params; #define NUM_PARAMS (sizeof(Params) / sizeof(double)) @@ -628,6 +636,7 @@ typedef struct FluxVars { double soilMethane; // Methane produced from litter double litterMethane; + } Fluxes; // Global var diff --git a/tests/sipnet/test_modeling/Makefile b/tests/sipnet/test_modeling/Makefile index 964d4cb4..0110f7ea 100644 --- a/tests/sipnet/test_modeling/Makefile +++ b/tests/sipnet/test_modeling/Makefile @@ -8,7 +8,7 @@ LDFLAGS=-L$(ROOT_DIR)/libs LDLIBS=-lsipnet -lsipnet_common -lm # List test files in this directory here -TEST_CFILES=testNitrogenCycle.c testDependencyFunctions.c testBalance.c testMethane.c testSoilMoisture.c +TEST_CFILES=testNitrogenCycle.c testDependencyFunctions.c testBalance.c testMethane.c testSoilMoisture.c testCarbonSaturation.c # The rest is boilerplate, likely copyable as is to a new test directory TEST_OBJ_FILES=$(TEST_CFILES:%.c=%.o) diff --git a/tests/sipnet/test_modeling/testCarbonSaturation.c b/tests/sipnet/test_modeling/testCarbonSaturation.c new file mode 100644 index 00000000..6d703d1b --- /dev/null +++ b/tests/sipnet/test_modeling/testCarbonSaturation.c @@ -0,0 +1,184 @@ +#include "utils/tUtils.h" +#include "sipnet/sipnet.c" + +void resetState(void) { + ctx.litterPool = 1; + ctx.carbonSaturation = 1; + + envi.litterC = 10; + + params.soilCSaturation = 10; + + fluxes.woodLitter = 0; + fluxes.leafLitter = 0; + fluxes.litterToSoil = 0; + fluxes.rLitter = 0; + fluxes.litterMethane = 0; + fluxes.soilMethane = 0; + fluxes.fineRootLoss = 0; +} + +void setupTests(void) { + // set up dummy climate + climate = (ClimateNode *)malloc(sizeof(ClimateNode)); + climate->year = 2024; + climate->day = 70; + climate->length = 0.125; + climate->tsoil = 20.0; + + // Initialize general state + resetState(); + + // Set up the context + initContext(); +} + +int checkPool(double calcPool, double expPool, const char *label) { + // Make sure we didn't forget to update context, in case dependencies changed + validateContext(); + + int status = 0; + if (!compareDoubles(calcPool, expPool)) { + status = 1; + logTest("Calculated %s pool is %f, expected %f\n", label, calcPool, + expPool); + } + + return status; +} + +int checkSoil(double pool) { + int status = 0; + status |= checkPool(envi.soilC, pool, "soil"); + return status; +} + +int checkLitter(double pool) { + int status = 0; + status |= checkPool(envi.litterC, pool, "litter"); + return status; +} + +void calcCSaturation(double *expSoilC, double *expLitterC) { + double saturationFraction; + double soilInputs = + fluxes.coarseRootLoss + fluxes.fineRootLoss + fluxes.litterToSoil; + + saturationFraction = + (ctx.carbonSaturation) + ? (fmin(1.0, fmax(0.0, *expSoilC / params.soilCSaturation))) + : 0.0; + + *expLitterC += soilInputs * saturationFraction * climate->length; + + *expSoilC += + (soilInputs * (1 - saturationFraction) - fluxes.rSoil) * climate->length; +} + +int testCarbonSaturation(void) { + int status = 0; + double expSoilC; + double expLitterC; + + // Low C inputs, low saturationFraction + logTest(" Test: low soilInputs, low satFrac\n"); + resetState(); + + expSoilC = 2.5; // 25% saturation + envi.soilC = 2.5; + expLitterC = 10; + fluxes.coarseRootLoss = 100; + fluxes.rSoil = 0; + + calcCSaturation(&expSoilC, &expLitterC); + updatePoolsForSoil(); + status |= checkSoil(expSoilC); + status |= checkLitter(expLitterC); + + // High C inputs, low saturationFraction + logTest(" Test: high soilInputs, low satFrac\n"); + resetState(); + + expSoilC = 2.5; // 25% saturation + envi.soilC = 2.5; + expLitterC = 10; + fluxes.coarseRootLoss = 200; + fluxes.rSoil = 0; + + calcCSaturation(&expSoilC, &expLitterC); + updatePoolsForSoil(); + status |= checkSoil(expSoilC); + status |= checkLitter(expLitterC); + + // Low C inputs, high saturationFraction + logTest(" Test: low soilInputs, high satFrac\n"); + resetState(); + + expSoilC = 7.5; // 75% saturation + envi.soilC = 7.5; + expLitterC = 10; + fluxes.coarseRootLoss = 100; + fluxes.rSoil = 0; + + calcCSaturation(&expSoilC, &expLitterC); + updatePoolsForSoil(); + status |= checkSoil(expSoilC); + status |= checkLitter(expLitterC); + + // High C inputs, high saturationFraction + logTest(" Test: high soilInputs, high satFrac\n"); + resetState(); + + expSoilC = 7.5; // 75% saturation + envi.soilC = 7.5; + expLitterC = 10; + fluxes.coarseRootLoss = 200; + fluxes.rSoil = 0; + + calcCSaturation(&expSoilC, &expLitterC); + updatePoolsForSoil(); + status |= checkSoil(expSoilC); + status |= checkLitter(expLitterC); + + // Soil C Pool > saturationFraction + logTest(" Test: soilC > saturation\n"); + resetState(); + + expSoilC = 12.5; // 125% saturation + envi.soilC = 12.5; + expLitterC = 10; + fluxes.coarseRootLoss = 200; + fluxes.rSoil = 50; + + calcCSaturation(&expSoilC, &expLitterC); + updatePoolsForSoil(); + // logTest(" expSoilC is %f\n", expSoilC); + // logTest(" expLitterC is %f\n", expLitterC); + status |= checkSoil(expSoilC); + status |= checkLitter(expLitterC); + + return status; +} + +int run(void) { + int status = 0; + + setupTests(); + + status |= testCarbonSaturation(); + + return status; +} + +int main(void) { + int status; + + logTest("Starting testCarbonSaturation:run()\n"); + status = run(); + if (status) { + logTest("FAILED testCarbonSaturation with status %d\n", status); + exit(status); + } + + logTest("PASSED testCarbonSaturation\n"); +} diff --git a/tests/smoke/niwot/sipnet.config b/tests/smoke/niwot/sipnet.config index abd352f8..590efc17 100644 --- a/tests/smoke/niwot/sipnet.config +++ b/tests/smoke/niwot/sipnet.config @@ -1,4 +1,5 @@ ANAEROBIC DEFAULT 0 + CARBON_SATURATION DEFAULT 0 CLIM_FILE CALCULATED sipnet.clim DO_MAIN_OUTPUT INPUT_FILE 1 DO_SINGLE_OUTPUT INPUT_FILE 0 diff --git a/tests/smoke/russell_1/sipnet.config b/tests/smoke/russell_1/sipnet.config index 881e02bc..c0db7fe1 100644 --- a/tests/smoke/russell_1/sipnet.config +++ b/tests/smoke/russell_1/sipnet.config @@ -1,6 +1,7 @@ -Final config for SIPNET run at 2026-04-24 03:35:15 UTC +Final config for SIPNET run at 2026-05-21 16:24:01 UTC Name Source Value ANAEROBIC DEFAULT 0 + CARBON_SATURATION DEFAULT 0 CLIM_FILE CALCULATED sipnet.clim DO_MAIN_OUTPUT DEFAULT 1 DO_SINGLE_OUTPUT DEFAULT 0 diff --git a/tests/smoke/russell_1/sipnet.param b/tests/smoke/russell_1/sipnet.param index 1ab81698..75e2fea6 100644 --- a/tests/smoke/russell_1/sipnet.param +++ b/tests/smoke/russell_1/sipnet.param @@ -75,3 +75,4 @@ waterDrainFrac 1.0 plantStorageNInit 5.0 leafNResorptionFrac 0.5 leafOnReallocFrac 0.2 +soilCSaturation 1.0 diff --git a/tests/smoke/russell_2/sipnet.config b/tests/smoke/russell_2/sipnet.config index cc39144f..6b2201dd 100644 --- a/tests/smoke/russell_2/sipnet.config +++ b/tests/smoke/russell_2/sipnet.config @@ -1,6 +1,7 @@ -Final config for SIPNET run at 2026-04-24 03:35:15 UTC +Final config for SIPNET run at 2026-05-21 16:24:01 UTC Name Source Value ANAEROBIC INPUT_FILE 1 + CARBON_SATURATION DEFAULT 0 CLIM_FILE CALCULATED sipnet.clim DO_MAIN_OUTPUT INPUT_FILE 1 DO_SINGLE_OUTPUT INPUT_FILE 0 diff --git a/tests/smoke/russell_2/sipnet.param b/tests/smoke/russell_2/sipnet.param index a6062946..df9109b7 100644 --- a/tests/smoke/russell_2/sipnet.param +++ b/tests/smoke/russell_2/sipnet.param @@ -75,3 +75,4 @@ waterDrainFrac 1.0 plantStorageNInit 5.0 leafNResorptionFrac 0.5 leafOnReallocFrac 0.2 +soilCSaturation 1.0 diff --git a/tests/smoke/russell_3/sipnet.config b/tests/smoke/russell_3/sipnet.config index 5e178df9..27d465f2 100644 --- a/tests/smoke/russell_3/sipnet.config +++ b/tests/smoke/russell_3/sipnet.config @@ -1,6 +1,7 @@ -Final config for SIPNET run at 2026-04-24 03:35:15 UTC +Final config for SIPNET run at 2026-05-21 16:24:01 UTC Name Source Value ANAEROBIC DEFAULT 0 + CARBON_SATURATION DEFAULT 0 CLIM_FILE CALCULATED sipnet.clim DO_MAIN_OUTPUT DEFAULT 1 DO_SINGLE_OUTPUT DEFAULT 0 diff --git a/tests/smoke/russell_3/sipnet.param b/tests/smoke/russell_3/sipnet.param index 7701d7bc..e5b8ecd1 100644 --- a/tests/smoke/russell_3/sipnet.param +++ b/tests/smoke/russell_3/sipnet.param @@ -68,3 +68,4 @@ nFixationFracMax 0.5 halfNFixationMax 1.0 waterDrainFrac 1.0 leafOnReallocFrac 0.2 +soilCSaturation 1.0 diff --git a/tests/smoke/russell_4/sipnet.param b/tests/smoke/russell_4/sipnet.param index bbb47a98..65367c6d 100644 --- a/tests/smoke/russell_4/sipnet.param +++ b/tests/smoke/russell_4/sipnet.param @@ -66,3 +66,4 @@ fineRootCN 40.0 kCN 80.0 waterDrainFrac 1.0 leafOnReallocFrac 0.2 +soilCSaturation 1.0