fix(flux.uncertainty): prevent crash when positive-flux model is not fitted#4011
fix(flux.uncertainty): prevent crash when positive-flux model is not fitted#4011anshul23102 wants to merge 3 commits into
Conversation
…fitted
When all positive-magnitude bins have NA error estimates, the `mp` lm
object is never created. The original else-branch on the negative-slope
fallback referenced `mp$coefficients[1]` unconditionally, producing an
"object 'mp' not found" error at runtime. This crash is easily triggered
by passing flux data that contains only negative values (e.g. nighttime
respiration-only records).
Two changes in `flux.uncertainty()`:
- Removed a duplicate `E2 <- errBin - errBin[zero]` line that appeared
twice in succession with no effect.
- Changed the bare `else` on the negative-slope fallback to
`else if (exists("mp", inherits = FALSE))` so the fallback only runs
when the positive-slope model was actually fitted.
mdietze
left a comment
There was a problem hiding this comment.
Please confirm Test plan completion
| }else{ | ||
| } else if (exists("mp", inherits = FALSE)) { | ||
| return.list$slopeN <- mp$coefficients[1] | ||
| } |
There was a problem hiding this comment.
updated code is going to leave slopeN undefined if the new if is false. Doing so silently is going to cause issues downstream. Seems like there should be an additional else that sets slopeN to something, as well as a similar set of cases for the earlier slopeP. One option would be a sensible default (e.g., mean value from analyzing many site-years of data), another would be a NA or something like that. If we do set the parameter to NA, it would be good to check what existing PEcAn code calls this function to see what additional checks would be useful there.
|
Thanks @mdietze. I have now run all items in the test plan against the fixed code. Test 1: purely negative flux (nighttime/respiration-only data) This is the primary crash scenario the PR fixes. With 120 paired measurements all in the range [-20, -2]: source("modules/uncertainty/R/flux_uncertainty.R")
set.seed(42)
vals <- seq(-20, -2, length.out = 120)
meas <- numeric(240)
meas[seq(1, 240, 2)] <- vals
meas[seq(2, 240, 2)] <- vals + rnorm(120, 0, 0.5)
qc <- rep(0L, 240)
result <- flux.uncertainty(meas, QC = qc, bin.num = 8, minBin = 3)Result: no error. Test 2: mixed positive/negative flux With values spanning [-15, 15]: Result: no error. Both Test 3: purely positive flux With values spanning [2, 20]: Result: no error. Test 4: file parse check
Checking off:
|
… fix
Three scenarios exercise the `exists("mp", inherits = FALSE)` guard added
in the previous commit:
1. All-negative flux: positive-flux model mp is never assigned; the
function must return without error and without slopeP.
2. Mixed positive/negative flux: both slopeP and slopeN are fit normally.
3. All-positive flux: negative bins are empty, slopeN falls back to mp.
Summary
flux.uncertainty()fits separate linear models for the positive-flux (mp) and negative-flux (mn) components of the heteroskedastic error model. If every positive-magnitude bin has fewer thanminBinpoints (or all produce NA errors), the positive-flux block is skipped andmpis never assigned. The original code then entered anelsebranch that referencedmp$coefficients[1]unconditionally, crashing with:This crash is reliably reproducible by passing a flux time-series that contains only negative values (for example, nighttime-only or respiration-only records), which is a common subset that ecologists regularly pass to this function.
Changes
modules/uncertainty/R/flux_uncertainty.RE2 <- errBin - errBin[zero]line that appeared twice in succession with no computational effect.elsefallback toelse if (exists("mp", inherits = FALSE)), soslopeNis set frommponly whenmpwas actually fitted. When neither model is fitted the list entry is simply omitted, which is consistent with howslopePis handled.modules/uncertainty/NEWS.md: added entry for the 1.9.0.9000 development version.Test plan
flux.uncertainty()with a purely negative flux vector; confirm no "object 'mp' not found" error.flux.uncertainty()with a mixed positive/negative flux vector; confirm bothslopePandslopeNare returned correctly.flux.uncertainty()with a purely positive flux vector; confirmslopeNis absent from the result (no crash).R CMD checkonPEcAn.uncertaintypasses without warnings or errors.