Pitfalls

Each of these produces a confident, plausible, wrong answer rather than an error.

Mixing is linear in concentration

Never log-transform concentrations and never mix ratios of species. Log axes are for looking at a wide range; a log transform destroys the linearity the whole method rests on. Use alkalinity or HCO₃ rather than pH.

Solute isotope ratios do not mix linearly

δ¹⁸O and δ²H of the water molecule are fine — water is the solvent. But δ¹³C-DIC, δ³⁴S-SO₄ and ⁸⁷Sr/⁸⁶Sr are carried by an element whose concentration differs between end-members, so the mixture is a concentration-weighted average.

With a twentyfold contrast in the carrier, a true fraction of 0.75 read through the naive formula comes back as 0.13. Use linearize(); the estimators warn if you forget. See 08 · Isotope tracers, and the one that breaks linear mixing.

A non-detect is not a measurement

It says the concentration lies in [0, limit]. Carry it as censored rather than substituting half the detection limit — in our tests that conventional substitution was worse than doing nothing, while the one-sided treatment recovered the truth exactly.

Fit the ratios on conservative tracers before diagnosing reactions

If a reacting species influences the ratios, least squares absorbs part of the reaction by shifting them, and the residual is smeared across every species — the reacting one looks conservative and innocent ones are convicted in its place. Use fit_conservative().

A conservative tracer is conservative in this system

SO₄ is a fine tracer in an oxic aquifer and useless where sulphate reduction occurs. NO₃ is rarely conservative in redox-active groundwater — Tubau et al. explicitly chose not to explain it.

Electrical conductivity is not an independent species

It is a weighted sum of ions you are probably already using. Including EC and Cl, Na, SO₄, HCO₃ double-counts the dilution axis. Legitimate as a cheap, densely sampled proxy, but do not read its loading as independent evidence.

Samples outside the mixing hull are information

A negative unconstrained ratio means the sample is not a mixture of those end-members. Clipping hides that. Run the unconstrained solve as a diagnostic even when you report the constrained one — identifiability_report() does it for you.

A mislabelled unit will not break a mixing ratio, but it will break a charge balance

Mixing is linear within each species, so the unit label does not enter it. The conversions read the label to decide what is already converted — so data already in meq/L but labelled mg/L is converted a second time, silently. State the units you actually have; see Units.

A charge balance error means nothing without its convention

Two conventions are in circulation and they differ by exactly a factor of two:

  • convention="sum" (the default) divides by the sum of the two ion sums — Freeze & Cherry (1979) eq. 3.21, and what PHREEQC prints;

  • convention="mean" divides by their mean — APHA Standard Methods 1030E, the form most water-quality QA literature uses.

Neither is wrong. The trap is that the ±5% acceptance rule is quoted for both, so screening at 5% under "mean" is twice as strict as under "sum". The same water can pass one and fail the other.

charge_balance_report() records which was used in .attrs["convention"]. Quote it whenever you quote a CBE.

am.charge_balance_report(samples, convention="mean", tolerance=10.0)

The hardest assumption is that the end-members held still

Mixing analysis assumes constant end-member compositions. Over decades of changing land use that is doubtful, and it is rarely tested. The bundled Hubbard Brook precipitation record is the clearest public demonstration that it can fail: non-sea-salt sulphate in it falls roughly fivefold between the 1960s and the 2010s.