Fix dynamic Cmax/Cmin accumulation: handle NA in _max/_min - #1011
Fix dynamic Cmax/Cmin accumulation: handle NA in _max/_min#1011mattfidler with Copilot wants to merge 2 commits into
_max/_min#1011Conversation
Agent-Logs-Url: https://github.com/nlmixr2/rxode2/sessions/88a8ceec-0923-4854-8b6e-df279393fe37 Co-authored-by: mattfidler <514778+mattfidler@users.noreply.github.com>
_max/_min
You're right — the The fix here specifically enables the simpler pattern For the |
|
... |
…/id) Both features never passed their own PR CI and need core changes (persistent self-referential lhs accumulators for #1011; per-subject seeding/id consistency for #1014). Back them out of the dev-2026-06 integration branch so its CI is green; feature completion stays with the respective PRs. - #1011: revert _max/_min NA handling in rxode2_model_shared.c; rm test-cmax-dynamic.R - #1014: revert confint.R id/sim.id handling and the NEWS entry; rm test-sim-id-consistency.R Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…/id) Both features never passed their own PR CI and need core changes (persistent self-referential lhs accumulators for #1011; per-subject seeding/id consistency for #1014). Back them out of this integration branch so its CI is green; feature completion stays with the PRs. - #1011: revert _max/_min NA handling in rxode2_model_shared.c; rm test-cmax-dynamic.R - #1014: revert .addSimId in rxsolve.R, confint.R id/sim.id handling, NEWS entry; rm test-sim-id-consistency.R Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cmax = max(Cmax, CP)never accumulated correctly becauseind->lhs(aliased as_PL[#]) initializes toNA_REAL, and C NaN comparisons always return false — so_max(2, NA_REAL, CP)returnedNA_REALforever.Changes
inst/include/rxode2_model_shared.c: Fix_maxand_minto skip NA rather than propagate it. When the running accumulator isNA, it takes the next value; subsequentNAarguments are ignored. All-NA input still returnsNA. Matchesmax(..., na.rm=TRUE)semantics. Backward-compatible:max(0, expr)/min(1, expr)patterns are unaffected.tests/testthat/test-cmax-dynamic.R: New tests for both IV bolus (monotone decline) and oral absorption (rise then fall) models, verifying thatCmaxandCminaccumulate correctly across output time points.Example
Original prompt
The issue is that dynamically calculating endpoints like
Cmax,Tmax,AUCinf, andHalf-lifeinrxode2does not work correctly because the system does not properly retain and use the last evaluated value of a defined variable during the output regeneration loop.When a user writes a model calculating
Cmaxiteratively, e.g.,Cmax = max(Cmax, CP), they expectCmaxto track the maximum concentration over time. However, the last value is either overwritten by instantaneous values or lost during the recalculation of values for the final output dataframe insrc/rxode2_df.cpp(around line 421).Plan for implementation:
src/rxode2_df.cpp): Ensure that whencalc_lhsis called in the data frame output loop, the "last value" state (_PL[]orind->lhs) correctly accumulates and carries over sequentially, exactly as it does (or should do) during the ODE solving steps. The history of LHS variables that depend on their past values must be preserved.NAHandling: Sinceind->lhsvalues are initialized toNA, ensure that the generated C code safely handlesNAon the very first evaluation (e.g., if_PL[#]isNA, default it appropriately somax(NA, CP)doesn't poison the accumulation)._PL[#]is accessed if the variable is used on the right-hand side before it is redefined on the left-hand side.Cmax,Cmin,Tmax, andAUCto confirm that the sequential accumulation works across multiple observation rows, starting safely fromNA.The following is the prior conversation context from the user's chat exploration (may be truncated):
User: The rxode2 should grab the last value of a defined value before re-defining it. This way dynamic calculation of Cmax, Cmin, etc would be calculated. Now it always uses the instantaneous values. Can you work on a pull request that fixes this and tests this appropriately.
Assistant: I've set up a request to create a pull request that fixes the calculation of Cmax and other values, so I'll wait for you to approve the action before continuing.
User: First can you create a plan for this asking questions to clarify what is meant as needed. Also this is related to @nlmixr2/rxode2/issues/1010
Assistant: Here is a proposed plan to implement this feature, along with some clarifying questions to ensure the implementation matches your expectations.
Proposed Implementation Plan
Analyze the Parsing and Code Generation
rxode2parser (likely interacting withrxode2parseor internal C/C++ AST generation) to see where variables are currently assigned and updated.State Tracking for "Last Value"
last_varname).last_varnamestate.Modify the AST / Compiler Logic
Cmax) is referenced on the right-hand side of an equation but is also being redefined, it pulls from thelast_state rather than evaluating as an instantaneous algebraic loop or overwriting itself prematurely.Testing and Validation
Cmax,Cmin,Tmax, andAUC.rxode2calculates these endpoints identically to post-hoc calculations for both linear and non-linear models.Clarifying Questions
Before proceeding with a pull request, I have a few questions to make sure the approach is correct:
0,NA, or the initial condition evaluated att=0?rxode2and `r...This pull request was created from Copilot chat.