Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ sections to include in release notes:

### Fixed

- Prevent zero carbon transfers from producing non-finite nitrogen fluxes when
litter or soil carbon pools are empty.

### Changed

### Removed
Expand Down
18 changes: 10 additions & 8 deletions src/sipnet/nitrogen.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ static void calcNPoolFluxes(void) {

// for both litter and soil, mineralization is calculated as heterotrophic
// respiration divided by the C:N ratio of that pool.
double litterMin = fluxes.rLitter / litterCN;
double soilMin = fluxes.rSoil / soilCN;
// A zero carbon transfer carries no nitrogen, including from an empty pool.
double litterMin = fluxes.rLitter == 0.0 ? 0.0 : fluxes.rLitter / litterCN;
double soilMin = fluxes.rSoil == 0.0 ? 0.0 : 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 +
double litterNToSoil =
fluxes.litterToSoil == 0.0 ? 0.0 : fluxes.litterToSoil / litterCN;
double soilNInputs = litterNToSoil + fluxes.fineRootLoss / params.fineRootCN +
fluxes.coarseRootLoss / params.woodCN;
// saturationFraction capped between zero and one
double saturationFraction =
Expand All @@ -67,10 +69,10 @@ static void calcNPoolFluxes(void) {
// 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 + (soilNInputs * saturationFraction);
fluxes.nOrgLitter = fluxes.leafLitter / params.leafCN -
fluxes.leafOffNResorption +
fluxes.woodLitter / params.woodCN - litterMin -
litterNToSoil + (soilNInputs * saturationFraction);

// soil
// The soil org N flux is determined by the carbon flux from the litter pool,
Expand Down
40 changes: 40 additions & 0 deletions tests/sipnet/test_modeling/testNitrogenCycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,45 @@ int testOrganicN(void) {
return status;
}

int testZeroCarbonNitrogenTransfer(void) {
int status = 0;
logTest("Running testZeroCarbonNitrogenTransfer\n");

for (int organicNPresent = 0; organicNPresent <= 1; organicNPresent++) {
resetState();
envi.litterC = 0.0;
envi.soilC = 0.0;
envi.minN = 2.0;
envi.litterN = organicNPresent ? 0.0211 : 0.0;
envi.soilOrgN = organicNPresent ? 127.7255 : 0.0;

double initialTotalN = envi.minN + envi.litterN + envi.soilOrgN;
double initialLitterN = envi.litterN;
double initialSoilOrgN = envi.soilOrgN;

calcNPoolFluxes();
updateNitrogenPools();

if (!isfinite(envi.minN) || !isfinite(envi.litterN) ||
!isfinite(envi.soilOrgN)) {
logTest("Zero-carbon pools produced non-finite nitrogen stocks\n");
status = 1;
}
status |= checkFlux(fluxes.nMin, 0.0, "Zero-carbon mineralization");
status |= checkFlux(fluxes.nOrgLitter, 0.0, "Zero-carbon organic litter N");
status |= checkFlux(fluxes.nOrgSoil, 0.0, "Zero-carbon organic soil N");
status |= checkFlux(envi.minN, 2.0, "Zero-carbon mineral N pool");
status |=
checkFlux(envi.litterN, initialLitterN, "Zero-carbon litter N pool");
status |= checkFlux(envi.soilOrgN, initialSoilOrgN,
"Zero-carbon soil organic N pool");
status |= checkFlux(envi.minN + envi.litterN + envi.soilOrgN, initialTotalN,
"Zero-carbon total N conservation");
}

return status;
}

/////
// Organic N with leafOffNResorption
int testOrganicNWithResorption(void) {
Expand Down Expand Up @@ -841,6 +880,7 @@ int run(void) {
status |= testFertilization();
status |= testNLeaching();
status |= testOrganicN();
status |= testZeroCarbonNitrogenTransfer();
status |= testLeafOnNFromC();
status |= testNFixation();
status |= testNLimitation();
Expand Down
Loading