Update neg growth handling to be an actual limitation check - #368
Conversation
* Initial plan * Add unit tests for carbon accounting and plant mortality changes * Update for clang-format * Update context handling --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Mike Longfritz <Mike.Longfritz@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: dlebauer <464871+dlebauer@users.noreply.github.com>
Co-authored-by: dlebauer <464871+dlebauer@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors negative-growth handling by moving “can’t drive pools negative” allocation adjustments into the limitations layer, and consolidates reduction-driven nitrogen resorption accounting into the nitrogen module. This fits the SIPNET execution model by separating flux calculation, limitation checks, and pool updates more cleanly.
Changes:
- Moved negative-growth allocation correction (leaf↔wood and fine↔coarse root) out of
sipnet.cintolimitations.cvia a newcheckCarbonLimitations()step. - Replaced incremental
updateNResorptionFlux()updates with a centralizedcalcReductionResorptionFlux()calculation innitrogen.c. - Updated unit tests to reflect the new call order/locations for carbon limitation checks and reduction resorption.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/sipnet/test_modeling/testNitrogenCycle.c | Removes the unit test for the deleted updateNResorptionFlux() helper. |
| tests/sipnet/test_modeling/testFluxCalculations.c | Adjusts flux tests to call checkCarbonLimitations() and calcReductionResorptionFlux() explicitly and updates expected resorption values. |
| src/sipnet/sipnet.c | Removes in-function negative-creation adjustments and adds a centralized checkCarbonLimitations() call before nitrogen flux calculations. |
| src/sipnet/nitrogen.h | Removes the old resorption update API and exposes calcReductionResorptionFlux() (used by tests). |
| src/sipnet/nitrogen.c | Implements centralized reduction-driven resorption and changes nitrogen flux wrapper behavior. |
| src/sipnet/limitations.h | Adds checkCarbonLimitations() to the limitations interface. |
| src/sipnet/limitations.c | Implements carbon limitation logic previously embedded in wood/leaf and root flux calculators. |
Suppressed comments (1)
src/sipnet/nitrogen.h:64
- The calcNitrogenFluxes() header comment says it computes all nitrogen fluxes "except N resorption", but calcNitrogenFluxes() now calls calcReductionResorptionFlux(). The comment should be updated so it matches the current behavior.
/*!
* Calculate all nitrogen fluxes (except N resorption)
*
* This is the general flux calculation wrapper for sipnet.c
*/
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (fluxes.woodCreation < 0.0) { | ||
| // Note: we want these negative fluxes to INCREASE N resorption | ||
| fluxes.reductionNResorption -= |
There was a problem hiding this comment.
I agree that this is a weak check, but:
- if mean NPP < 0, ALL creation terms are <= 0; likewise, if mean NPP >=0, all creation terms are >= 0
- this only fails if the wood allocation fraction parameter is zero, which I think is nonsense?
However...
- better commenting would be good, and
- given that they are all non-positive-or-not, checking the sum is stronger
Will update.
| // If leafCreation is too negative, we need to deduct from wood instead | ||
| double leafDeficit = envi.plantLeafC / climate->length + fluxes.leafCreation - | ||
| fluxes.leafLitter; |
There was a problem hiding this comment.
Good catch! In the long run, I think it's better to consider the leaf-off litter too, but let's stick with "no functional change" for this PR. I'll make a ticket to consider leaf-off - and events - in this limitation check.
|
Done. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (2)
src/sipnet/nitrogen.c:193
- This introduces an additional model-state change beyond the event-output change described in the PR.
fluxes.leafLitterincludes calculated phenology leaf-off litter regardless ofctx.events, whereas the previous resorption update for that litter was insideif (leafOff > TINY && ctx.events). Consequently, nitrogen-enabled runs with events disabled now resorb phenology leaf N when they previously did not. Either preserve the old guard/flux split for this zero-functional-change PR, or explicitly document and regression-test this behavior change.
// Leaf litter resorption; at this point, fluxes.leafLitter counts both normal
// turnover and leaf-off calcs. Note that event leaf off is handled in
// events.c
double nResorp =
params.leafNResorptionFrac * fluxes.leafLitter / params.leafCN;
fluxes.leafOffNResorption += nResorp;
src/sipnet/limitations.c:161
- The relocated below-ground limitation has no test exercising either redistribution branch. The existing negative-root test leaves both root pools solvent and does not call
checkCarbonLimitations(), so a regression in this core moved logic would pass. Add cases where only the fine-root pool and only the coarse-root pool would go negative, and verify that creation is transferred to the other root pool.
if ((fineRootDeficit < 0.0) != (coarseRootDeficit < 0.0)) {
// If neither are negative, nothing to do
// If both are negative, the plant will die in checkForMortality()
if (fineRootDeficit < 0.0) {
fluxes.coarseRootCreation += fineRootDeficit;
fluxes.fineRootCreation -= fineRootDeficit;
}
if (coarseRootDeficit < 0.0) {
fluxes.fineRootCreation += coarseRootDeficit;
fluxes.coarseRootCreation -= coarseRootDeficit;
dlebauer
left a comment
There was a problem hiding this comment.
LGTM
Please update changelog
|
linter check appears to be hung; close and reopen to restart. |
Pull request was closed
Summary
Details
limitations.c, in a proper limitation checknitrogen.c, which is more appropriate thansipnet.c(better modularity)updatedNResorptionFluxfunctionHow was this change tested?
This should be a zero-functional-change PR, with one minor exception - leaf-off events no longer report resorbed N (but this can be calculated, so no real loss). Some unit tests needed to be updated (and were), but the smoke tests pass without modification.
Related issues
Checklist
docs/CHANGELOG.mdupdated with noteworthy changes (None)clang-format(rungit clang-formatif needed)