Tutorials › Quantitative Systems Pharmacology (QSP) › Diagnosing Sign, Scale, and Indexing Errors

Writing and Debugging a Model · Tutorial 79 of 799

Diagnosing Sign, Scale, and Indexing Errors

Learn to diagnose two-compartment model bugs by checking transfer signs, expected amount changes, and the correspondence between state-vector indices and biological states.

Intermediate 11 min read

What You'll Learn

  • Write the expected two-compartment amount balances and identify each transfer contribution.
  • Use the total-amount derivative to detect a transfer term with the wrong sign.
  • Estimate plausible state changes from the rates and amounts before integrating.
  • Trace state-vector and derivative indices to find mismatched compartment assignments.
  • Separate sign, scale, and indexing symptoms using hand calculations and focused checks.

Why Small Implementation Errors Matter

A model can have biologically sensible equations on paper and still produce implausible trajectories because the code implements a different system. In a two-compartment model, a single transfer flux must leave one compartment and enter the other. Reversing its sign, multiplying the wrong state, or writing a derivative into the wrong vector position can all break that correspondence. The resulting trajectory may look smooth while representing the wrong biology.

This tutorial uses a simple amount model to make three checks concrete: the sign of each derivative contribution, the scale of expected state changes, and the mapping between biological states and vector indices. These checks complement dimensional audits: correct units do not guarantee correct signs or indices.

Reference Model and Diagnostic Invariants

Let \(A_1(t)\) and \(A_2(t)\) be amounts in compartments 1 and 2, measured in mg. Material transfers from compartment 1 to compartment 2 at rate \(k_{12}A_1\), and in the reverse direction at rate \(k_{21}A_2\). Material is eliminated from compartment 1 at rate \(k_{10}A_1\). The rate constants are nonnegative and measured in \(\mathrm{h}^{-1}\). There are no external inputs in this example.

Reference balances: With the state vector ordered as \(y=(A_1,A_2)\), the two-compartment model is
$$ \frac{dA_1}{dt}=-(k_{12}+k_{10})A_1+k_{21}A_2,\qquad \frac{dA_2}{dt}=k_{12}A_1-k_{21}A_2. $$
Each transfer term is negative in the equation for the compartment it leaves and positive in the equation for the compartment it enters. Elimination is a loss from the modeled system.

The sign pattern gives a useful check before any numerical solution is examined. For example, the forward transfer \(k_{12}A_1\) decreases \(A_1\) but increases \(A_2\). Adding the equations cancels both internal transfer terms:

$$ \frac{d(A_1+A_2)}{dt}=-k_{10}A_1. $$

Thus, in the absence of external input, total amount can decrease through elimination but not through internal transfer alone. This identity is a direct consequence of the stated balances, not an assumption that the two amounts are individually constant. If \(k_{10}=0\), total amount is conserved; if \(k_{10}>0\), its instantaneous rate of loss is determined by the amount in compartment 1.

For nonnegative initial amounts and nonnegative rates, the reference model also points inward at a zero boundary: if \(A_1=0\), then \(dA_1/dt=k_{21}A_2\geq 0\); if \(A_2=0\), then \(dA_2/dt=k_{12}A_1\geq 0\). These boundary checks help identify a sign error that would make an amount decrease through zero in a setting where the model should preserve nonnegativity.

Check the Signs by Following Each Flux

A reliable sign audit starts with the physical direction of each flux, not with the appearance of the final equation. For every modeled process, write down its source and destination. Subtract the flux from the source balance and add it to the destination balance. A loss such as elimination has a source but no modeled destination, so it contributes only a negative term. Finally, add the compartment balances: internal transfers should cancel from the total.

Worked Example: Finding a Reversed Transfer Sign

Suppose \(A_1=100\) mg, \(A_2=20\) mg, \(k_{12}=0.30\ \mathrm{h}^{-1}\), \(k_{21}=0.10\ \mathrm{h}^{-1}\), and \(k_{10}=0.05\ \mathrm{h}^{-1}\). A programmer implements the second equation with a negative forward-transfer term:

$$ \frac{dA_2}{dt}=-k_{12}A_1-k_{21}A_2. $$

The forward flux is \(k_{12}A_1=(0.30)(100)=30\) mg/h, and the reverse flux is \(k_{21}A_2=(0.10)(20)=2\) mg/h. In the correct model,

$$ \frac{dA_1}{dt}=-(0.30+0.05)(100)+(0.10)(20) =-35+2=-33\ \mathrm{mg/h}, $$ $$ \frac{dA_2}{dt}=(0.30)(100)-(0.10)(20) =30-2=28\ \mathrm{mg/h}. $$

The incorrect second equation instead gives \(dA_2/dt=-30-2=-32\) mg/h. Its total derivative is \(-33-32=-65\) mg/h, whereas elimination predicts \(d(A_1+A_2)/dt=-(0.05)(100)=-5\) mg/h. The discrepancy identifies a transfer-sign error: the implementation makes the forward transfer remove material from both compartments.

As a short-step check, a forward Euler calculation with \(\Delta t=0.1\) h gives the correct first-step estimates \(A_1=100+0.1(-33)=96.7\) mg and \(A_2=20+0.1(28)=22.8\) mg. Total amount becomes \(119.5\) mg, a decrease of \(0.5\) mg consistent with the initial elimination rate of \(5\) mg/h over \(0.1\) h. This is a local diagnostic calculation, not a claim that Euler integration is the preferred solver.

Check Whether the State Scale Is Plausible

A scale check asks whether the magnitude and direction of the computed changes are reasonable for the states, rates, and time interval. It is not enough that the solver returns finite values. In the numerical example, the initial changes per hour are tens of mg, compared with amounts of tens to hundreds of mg. Over \(0.1\) h, changes of a few mg are plausible; a jump of hundreds of mg would need an explanation in the model or its inputs.

A useful first estimate comes directly from the right-hand sides. At the stated initial values, the fractional rate of change in compartment 1 is \((-33\ \mathrm{mg/h})/(100\ \mathrm{mg})=-0.33\ \mathrm{h}^{-1}\); in compartment 2 it is \((28\ \mathrm{mg/h})/(20\ \mathrm{mg})=1.4\ \mathrm{h}^{-1}\). These are initial rates, not constant fractional changes over the whole simulation. They indicate that compartment 2 can change more rapidly in relative terms because its initial amount is smaller.

The rate constants also give rough time scales. Without return transfer, the combined loss rate from compartment 1 is \(k_{12}+k_{10}=0.35\ \mathrm{h}^{-1}\), corresponding to a characteristic time \(1/0.35\approx2.86\) h. The reverse transfer rate has a characteristic time \(1/k_{21}=10\) h. These are scale guides, not exact half-lives for the coupled system. If a plotted trajectory changes nearly all its amount within a few seconds, while all rates are on an hourly scale and there are no fast inputs, check the time units, rate units, and state scaling before interpreting that behavior.

Worked Example: Spotting an Implausible Short-Time Change

Use the same initial amounts and rate constants, but suppose a simulation reports \(A_1=70\) mg and \(A_2=5\) mg after \(0.1\) h, with no external input. The reported total has fallen from \(120\) mg to \(75\) mg. At the initial state, the reference model predicts an initial total loss rate of only \(5\) mg/h, so the first-order expected total change over \(0.1\) h is about \(-0.5\) mg, not \(-45\) mg.

The individual changes are also inconsistent with the initial derivatives: the initial derivative predicts \(A_1\) near \(96.7\) mg and \(A_2\) near \(22.8\) mg over that short interval. These linear estimates are not exact trajectories, but the large discrepancy is a strong diagnostic signal. Because the total has fallen far beyond what elimination can explain, first inspect whether a transfer has been coded as a loss from both compartments. If the total balance is correct in the implementation, then inspect time units, rate magnitudes, state units, and whether the reported outputs correspond to the intended states.

This check does not establish which bug is present. It narrows the investigation by comparing the observed scale with a model-based expectation before attributing the behavior to biology.

Trace the State Vector and Its Derivative

In code, the state vector is an ordered list. Every read from that vector and every derivative written to the derivative vector must use the same documented ordering. For this example, let \(y[0]=A_1\) and \(y[1]=A_2\), using zero-based indices. Then the returned derivative must satisfy \(dy[0]/dt=dA_1/dt\) and \(dy[1]/dt=dA_2/dt\). The biological names, the indices, and the order of returned derivatives are three parts of one contract.

An indexing bug can leave the signs looking superficially reasonable while applying a flux to the wrong state. A useful check is to substitute distinct, easily recognized state values and calculate every flux by hand. Equal compartment amounts can conceal a swap, so diagnostic values should generally differ.

Worked Example: Detecting a Wrong State Index

Suppose the implementation correctly sets \(y[0]=A_1=100\) mg and \(y[1]=A_2=20\) mg, and correctly computes \(dA_1/dt=-33\) mg/h. But when constructing the second derivative, it mistakenly uses \(y[1]\) instead of \(y[0]\) for the forward transfer:

$$ \frac{dy[1]}{dt}=k_{12}y[1]-k_{21}y[1]. $$

This produces \((0.30)(20)-(0.10)(20)=4\) mg/h rather than the correct \(28\) mg/h. The total derivative returned by the code is then \(-33+4=-29\) mg/h, which violates the expected total balance of \(-5\) mg/h. The distinct state values expose that the forward flux is using the amount in the wrong compartment.

To localize the issue, compare each term with its intended source state: \(k_{12}\) must multiply \(A_1=y[0]\), while \(k_{21}\) must multiply \(A_2=y[1]\). Also verify the destination of each computed derivative. Correct flux arithmetic does not prevent an error if the resulting derivative is stored in the wrong index.

A Practical Diagnostic Sequence

These checks work best in a fixed order: first establish what each state and flux means, then test the right-hand side at a chosen state, and finally compare a short segment of the simulated trajectory with those expectations. This keeps a numerical symptom from being mistaken for a biological conclusion.

1
Write the state-index map.
Record that \(y[0]=A_1\), \(y[1]=A_2\), and which returned derivative corresponds to each state. Check initial conditions and output mapping against that same order.
2
Trace each flux.
For every transfer, identify its source, destination, and rate expression. Confirm a negative contribution at the source and a positive contribution at the destination.
3
Calculate a hand-check value.
Substitute distinct, nonzero state values and the parameter values into each derivative. Compare the computed code output with the arithmetic term by term.
4
Check total balance and scale.
Verify that internal transfer cancels and that the total derivative equals \(-k_{10}A_1\). Compare short-time changes with the derivative magnitudes and rate time scales.

A hand calculation and total-balance check are especially effective for sign errors. A state-index map and deliberately unequal test values are more direct for indexing errors. Expected state scales can reveal problems that survive both checks, such as a time-unit mismatch or output mapping error. Plotting is useful for seeing where a trajectory becomes implausible, but a smooth plot alone cannot verify the equations.

Common Pitfalls and Limits of These Checks

  • Assuming a smooth trajectory is correct. A solver can accurately integrate an incorrectly coded right-hand side. Check the equations and their balance identities, not only the appearance of the plot.
  • Checking only whether amounts are positive. Positivity does not prove that transfer terms are correct. The reversed-sign example can produce positive values initially while violating the total balance.
  • Using equal states to test indexing. If \(A_1=A_2\), swapping the two state values may not change a calculation that uses them in the same way. Use distinct values and inspect each term separately.
  • Treating a rough scale estimate as an exact prediction. Initial derivatives describe local change. In a coupled model, rates change as states change, so a linear short-step estimate should not be extrapolated far into the simulation.
  • Blaming the solver for every implausible result. Incorrect signs, units, indices, initial conditions, or observation mappings can produce bad outputs even when integration itself is functioning as intended.

These diagnostics are targeted, not exhaustive. A correct sign pattern and plausible scale do not prove that the biological model is appropriate, nor do they rule out parameter, input, or observation errors. They provide a disciplined way to detect implementation mismatches in this two-compartment balance before interpreting its predictions.

Check Your Understanding

Use the reference model and the stated state-vector order to answer the questions.

  1. If \(k_{10}=0\), what should the derivative of \(A_1+A_2\) be? Explain how this helps diagnose a transfer-term sign error.
  2. At \(A_1=50\) mg, \(A_2=10\) mg, \(k_{12}=0.20\ \mathrm{h}^{-1}\), \(k_{21}=0.10\ \mathrm{h}^{-1}\), and \(k_{10}=0.02\ \mathrm{h}^{-1}\), calculate both initial derivatives and the total derivative.
  3. If \(y[0]=A_1\) and \(y[1]=A_2\), which state must multiply the forward transfer rate \(k_{12}\)? Why should a diagnostic test use unequal state values?
  4. A model loses 20 mg of total amount over 0.1 h, although its initial elimination rate is 2 mg/h and there is no input. Is this consistent with the initial total-balance scale? Give one implementation issue to inspect.

Solutions. (1) The total derivative is zero because internal transfers cancel and elimination is absent; a nonzero total derivative suggests a missing or mismatched transfer contribution. (2) \(dA_1/dt=-(0.20+0.02)(50)+(0.10)(10)=-11+1=-10\) mg/h. \(dA_2/dt=(0.20)(50)-(0.10)(10)=10-1=9\) mg/h. Their sum is \(-1\) mg/h, equal to \(-k_{10}A_1=-(0.02)(50)\) mg/h. (3) \(k_{12}\) must multiply \(A_1=y[0]\), its source state. Unequal values make accidental substitution of \(A_2\) easier to detect. (4) No. The initial loss rate implies a first-order change of about \(-(2\ \mathrm{mg/h})(0.1\ \mathrm{h})=-0.2\) mg over that interval, not \(-20\) mg. Inspect for a transfer counted as a loss from both compartments, as well as time-scale and unit mismatches.

Clinical Biostats