Docs/Infohub (Flow)/Calculated Measures
Infohub (Flow)Concept

Calculated Measures

When to compute rather than aggregate, how dependencies drive recalculation, and the mistakes that cause stuck values.

Updated 15 Oct 2026Infohub Docs

A calculated measure produces its values by evaluating an expression against other measures. It is how every KPI in Infohub gets built — efficiency, yield, OEE, cost per unit, specific energy consumption — and it is the retrieval type where most modelling judgement is exercised.

Aggregate or calculate?#

The two are easy to confuse because both derive values from other measures.

Aggregate when you want the same quantity over a longer period. Daily steam flow from hourly steam flow. Monthly production from daily production. One input measure, one interval step, a summary rule.

Calculate when you want a different quantity over the same period. Efficiency from output and input. Yield from good and total. Cost from consumption and price. Several input measures, arithmetic, same interval.

If you find yourself wanting to aggregate and combine in one step, you need two measures: aggregate each input to the interval you want, then calculate at that interval.

Important

Calculate at the interval, then aggregate the calculation — carefully. A daily efficiency is not always the average of hourly efficiencies. If you need the daily figure to be "total output over total input for the day", calculate it from the daily totals, not by averaging the hourly efficiencies. Averaging ratios weights every hour equally regardless of how much ran in it, and produces a number that will not reconcile with the daily totals.

Creating one#

A calculated measure needs:

Setting Notes
Interval The interval it produces values at. Its dependencies are read at this interval.
Dependencies The measures the expression may reference
Expression C# evaluating to a double?
Unit The unit of the result, which is often not the unit of any input
Format How the value is displayed

Adding a dependency is what creates the Measure_<id> symbol the expression uses. See Calculation Expression Reference for the full API.

A minimal example — yield as a percentage, guarded:

Measure_2010.Value == 0 ? 0 : Measure_2009.Value / Measure_2010.Value * 100

Interval matching matters#

A calculated measure reads each dependency at its own interval. A daily calculation referencing an hourly measure gets that measure's daily-aligned value, not twenty-four values.

In practice this means: build the aggregation chain first, so each input exists at the interval where you need it, then calculate. A calculation reaching across intervals is usually a sign that a missing aggregation should be added instead.

How recalculation is triggered#

This is the part worth understanding properly, because it explains most surprises.

Infohub tracks dependencies. When a measure's value changes for an interval, the measures that depend on it are queued for recalculation for that interval. The chain propagates: a corrected hourly value re-aggregates to daily, which re-triggers the daily calculation, which re-triggers anything depending on that.

Two consequences:

Backfilling works. Load history into a base measure and everything above it recalculates for those periods.

Order does not need managing. You do not sequence calculations. Declaring dependencies is how you express order, and the engine derives the rest.

Important

A dependency you do not declare is a dependency Infohub cannot see. If an expression reaches a value by a route Infohub does not know about, that route will not trigger recalculation. The measure will compute once and then look stuck, updating only when one of its declared dependencies changes. When a calculated measure holds a stale value while its inputs move, the declared dependency list is the first thing to check.

Dependencies on other periods#

Expressions can read previous periods — Measure_1043[-1].Value — and windows — Measure_1043[-7, 0].Values.Average(). This is how period comparison, growth rates, and rolling averages are built without extra measures.

Be aware of what this implies for recalculation: a rolling seven-day average depends on seven days of input, so correcting one historical day legitimately causes seven days of that average to recompute. That is correct behaviour, and it is also why very long windows over very frequent intervals get expensive.

Returning null versus zero#

double? lets a calculation say "no value here". Choose deliberately:

  • Return 0 where zero is operationally true — no production means zero output.
  • Return null where the value is genuinely unknown, and you would rather see a gap than a false zero averaged into a monthly figure.

The common mistake is returning 0 from a ratio that will later be averaged. Five shutdown days contributing 0% will drag a monthly efficiency well below reality. See The Zero Guard.

Units and formats are not automatic#

Infohub does not derive the result unit from the expression. If you divide litres by tonnes, the result is l/t only because you said so.

Getting this wrong is quietly damaging: a chart legend claiming % on a ratio that was never multiplied by 100, or a measure labelled kWh that actually holds MWh, will be believed by whoever reads it. Set the unit and the format when you create the measure, not later. See Format Strings and Units of Measure.

Keeping expressions maintainable#

Push repeated logic into functions. Any pattern appearing more than twice — a safe division, a percentage of target, a conversion — belongs in a custom function.

Read parameters from model attributes. A capacity, a factor, or a price hard-coded into an expression cannot be templated and has to be edited per instance. Read it from a model attribute and one expression serves every instance.

Prefer several clear measures to one clever one. An expression combining six inputs and three conditionals is hard to review and harder to debug, because you can only see its output. Two intermediate measures cost almost nothing and make the failure visible at the step that failed.

Keep expressions numeric. Formatting belongs in the measure's format string, not in the expression.

Diagnosing a calculated measure#

Symptom Usual cause
No values at all Expression fails every interval — often an unguarded division or a null reference
Gaps on weekends, shutdowns, or month boundaries Unguarded division meeting a zero denominator
Value stuck while inputs move Missing declared dependency
Values wrong by a factor of 100 Percentage not multiplied, or multiplied twice
Daily figure disagrees with the sum of hours Ratio averaged instead of recalculated from daily totals
Correct going forward, wrong historically Expression fixed but the affected range never recalculated
Wrong after an unrelated edit in the same session A stale cached calculation assembly — reopen and recalculate the affected range

For a systematic approach, see Diagnosing Missing Data.

A worked example: specific energy consumption#

Energy per tonne, daily, from an energy totaliser and a production counter.

  1. Energy Meter — Retrieved, Tag, from the energy register
  2. Energy Used Hourly — Aggregated, Hourly, Counter (register to quantity)
  3. Energy Used Daily — Aggregated, Daily, Sum
  4. Production Daily — Aggregated, Daily, Sum, from the hourly production count
  5. Specific Energy Daily — Calculated, Daily, unit kWh/t:
SafeDivide(Measure_<energyDailyId>.Value, Measure_<productionDailyId>.Value)

Five measures, one KPI, and every step inspectable when the number looks wrong.

esc
↑↓ navigate · ↵ open · ⌘K anywhere