Some results are measured. Others are derived. SENAITE handles the derived ones through Calculations, a small feature that saves labs an enormous amount of copy-paste and rework. Once you know the formula grammar and the way it resolves dependencies, it’s a tool you’ll reach for constantly.
The building block
A Calculation is a first-class content object with a name, a
description, and a formula. The formula uses standard
arithmetic (+, -, *, /, (, )) and references other
values by their keyword in square brackets. The classic
example from the SENAITE codebase itself:
[Ca] + [Mg]
That’s the formula for Total Hardness. It reads the results of
two Analysis Services whose keywords are Ca and Mg, sums
them, and returns the value. Attach the Calculation to a
service called “Total Hardness” and every time both Ca and Mg
are entered on a sample, the derived value appears.
The evaluator resolves keywords against two scopes: results of sibling analyses on the same sample, and the calculation’s own Interim Fields.
Interim Fields
An Interim Field is a per-sample input that isn’t a result of another analysis. It lives on the Calculation itself. The sample form renders one editable field per Interim Field, next to the analyses.
Typical uses are dilution factors, sample weights, aliquot volumes, or anything else that varies per sample but comes from the analyst rather than from another measurement. Each Interim Field has a keyword, a title, an optional default value, an optional unit, and an optional choice list for picklist input.
Once defined, an Interim Field is referenced in the formula
exactly like an analysis result: [dilution], [weight].
Chains resolve automatically
A Calculation can depend on another calculated Analysis
Service. The core module tracks this through two symmetric
methods on the Calculation object: getCalculationDependencies
walks the graph of services this calculation reads from, and
getCalculationDependents walks the graph of services that
read from services this calculation drives.
That backward walk matters for change management. Rename a keyword and SENAITE can tell you every downstream calculation that will break. Deactivate a service and SENAITE can warn you which derived results will stop updating.
The forward walk drives evaluation. When any input in the graph gets a new value, every dependent calculation re-evaluates in the correct order. No manual recalculation button; no stale values on the sample.
Test parameters
New in recent core versions: every Calculation has a test parameters panel where you can supply sample values for every keyword in the formula and see the result render live. This is how you validate a formula before attaching it to a live Analysis Service. Type in realistic Ca and Mg values, check that Total Hardness comes out right, save. No round-tripping through a real sample to sanity-check your algebra.
Pitfalls that catch new labs
Renaming a keyword mid-project silently breaks every formula that references it. SENAITE stores keywords by string, not by object reference. Treat keywords as contracts: pick them carefully at go-live, and never rename them.
Formulas with an empty input evaluate to nothing. A calculation whose input hasn’t been entered yet doesn’t fail; it just doesn’t populate. That’s usually what you want, but it does mean a report generated before all inputs are entered will show empty derived values. Wait for the full workflow.
Rounding is a display concern, not a formula concern. SENAITE stores the raw numeric result. Rounding happens when the value is rendered. If you need the rounded value to feed another calculation, round explicitly in the upstream formula. Don’t rely on display rounding to propagate.
Division by zero throws. SENAITE renders it as an error on the analysis. Guard the formula with a conditional or catch it in an Interim Field default.
Interim Fields are not results. They aren’t verified by the result-verification workflow. If the correctness of an Interim value is quality-critical (a certified dilution factor, a calibrated weight), record it on a separate Analysis Service instead, so it flows through the verification chain like any other result.
When to prefer a Calculation over a manual entry
Any time the same arithmetic runs on every sample. The moment a technician is doing math on a calculator, it belongs in SENAITE. Not because they can’t do the math, but because computed results are traceable, auditable, and can’t drift. The formula is stored with the Calculation; the sample carries the values that fed it; the audit log records who verified what. Nobody has to trust a spreadsheet nobody owns anymore.
The habit worth building
Whenever you catch a service running the same manual arithmetic twice, promote it to a Calculation. Add the Interim Fields it needs. Test with the built-in parameters panel. Attach it to the analysis. Ten minutes of setup replaces a permanent source of transcription errors.