Formula Expressions
Several OctoMesh features let you enter a formula — a small numeric expression that
references one or more input values and produces a single value. All of them share the same
formula engine (mXparser, wrapped as IFormulaEngine), so the syntax below is identical
everywhere a formula is accepted.
Where formulas are used
| Feature | Input variable(s) | Notes |
|---|---|---|
DataPointMapping MappingExpression | value — the polled source value | Evaluated by the adapter when a control value is mapped onto a target attribute. Validate before saving with the validate-expression API. |
| Archive computed columns | each source column, bound by its column name (e.g. activepower, apparentpower) | Evaluated at archive-ingest time (and during backfill / rollup) for every row. A null / NaN result stores SQL NULL. The ResultType is stored with the column and drives the cast-back (see below). |
Runtime-query @-expressions | (none — constants + functions) | A query search term prefixed with @ is evaluated as a formula (e.g. a time bound @startOfDay(0)). |
The engine computes with double. Inputs and results are numbers; booleans are 0 / 1 and
date/times are .NET ticks. There is no string handling in formulas.
Variables
A formula references its inputs by name. For a DataPointMapping the single input is value;
other features bind their own names (e.g. an archive computed column binds each source column by
its column name). A name that is not provided by the feature is a syntax error.
Operators
| Category | Operators |
|---|---|
| Arithmetic | + - * / ^ (power) % (modulo) |
| Comparison | < <= > >= == != |
| Grouping | ( … ) |
Comparison results combine with the logical operators && (and), || (or) and ! (not).
Conditionals
Both forms are accepted and are equivalent:
value > 0 ? value : 0
if(value > 0, value, 0)
The C-style ternary cond ? a : b is normalized to mXparser's if(cond, a, b) before
evaluation. Nesting is supported; use parentheses for clarity:
value > 100 ? 100 : (value < 0 ? 0 : value)
Built-in functions (mXparser)
The engine is the full mXparser parser (v6.x) — nothing is disabled —
so the entire mXparser math collection is available, not just the handful most formulas use.
Because every input and the result are double (see the numeric-engine note above), the numeric
part of that collection is what's practically useful; the string / unit / probability-distribution
helpers exist but have no string or unit inputs to work on here.
The most commonly used functions:
| Function | Meaning |
|---|---|
abs(x) | absolute value |
sgn(x) | sign (-1 / 0 / +1) |
min(a, b, …) / max(a, b, …) | minimum / maximum (any number of arguments) |
round(x, n) | round to n decimals |
floor(x) / ceil(x) | round down / up |
sqrt(x) | square root |
exp(x) | e^x |
ln(x) / log2(x) / log10(x) | natural / base-2 / base-10 logarithm |
log(a, b) | logarithm with an explicit base (see the reference for argument order) |
mod(a, b) | modulo (same as the % operator) |
if(cond, a, b) | conditional |
iff(c1, v1, c2, v2, …) | multi-branch conditional — first true condition wins |
Other categories from the collection that work on numeric inputs:
| Category | Examples |
|---|---|
| Trigonometry (radians) | sin(x) cos(x) tan(x) cot(x) sec(x) csc(x) |
| Inverse / hyperbolic | asin(x) acos(x) atan(x), sinh(x) cosh(x) tanh(x) |
| Angle conversion | rad(deg) (degrees→radians), deg(rad) (radians→degrees) |
| Rounding / parts | floor(x) ceil(x) round(x,n), frac(x) (fractional part) |
| Combinatorics / number theory | gcd(a,b,…) lcm(a,b,…) C(n,k) (binomial), n! (factorial) |
| Aggregation | min(…) max(…), gcd(…) lcm(…) |
This table is a curated subset. The authoritative, version-matched list of every function, operator and constant the parser accepts is the mXparser math collection. Anything listed there that takes only numeric arguments works in an OctoMesh formula.
Constants
mXparser ships a large set of mathematical and physical constants. The ones you are most likely to use:
| Constant | Value |
|---|---|
pi | π ≈ 3.14159 |
e | Euler's number ≈ 2.71828 |
[phi] | golden ratio ≈ 1.61803 |
[gam] | Euler–Mascheroni constant ≈ 0.57722 |
true / false | 1 / 0 (handy with the logical operators) |
(Physical constants such as the speed of light are also defined — see the reference. As with functions, only their numeric values are relevant here.)
OctoMesh extensions
These three are registered by OctoMesh on top of the standard collection (see OctoExpression /
NowFunction / StartOfDayFunction in Runtime.Engine.Formulas):
| Function / constant | Meaning |
|---|---|
now(addMinutes) | current timestamp as .NET ticks, offset by addMinutes minutes (negative = past) |
startOfDay(dayCount) | local midnight as .NET ticks, shifted by dayCount days (startOfDay(0) = today, startOfDay(-1) = yesterday) |
null | the null sentinel — see below |
Both date functions return ticks, so they are designed for a DateTime result type or for
comparisons against other tick values (e.g. a runtime-query time bound @startOfDay(0)).
Null and error handling
- A missing / null input binds to the
nullsentinel. - If a formula evaluates to NaN (e.g.
0 / 0) or to thenullsentinel, the value is treated as no result — features map this to a fallback (DataPointMapping keeps the raw numeric value; an archive computed column storesNULL). - A syntax error (unbalanced parentheses, unknown variable, malformed expression) is reported at validation time, before the formula is ever used.
Examples
| Expression | Meaning |
|---|---|
value / 100 | scale percent to ratio |
value * 100 | scale ratio to percent |
value - 2.5 | calibration offset |
abs(value) | magnitude |
min(max(value, 0), 100) | clamp to 0…100 |
value > 0 ? value : 0 | positive part only |
value < 0 ? abs(value) : 0 | magnitude of the negative part (e.g. discharge power) |
Validating a formula
For DataPointMapping, the Communication Controller exposes an authoritative validation endpoint that runs the same engine the adapter uses at runtime, so a formula that validates will also run:
POST {tenantId}/v1/communication/validate-expression
{ "expression": "value > 0 ? value : 0", "testValue": 42.0 }
It returns { valid, error, result, normalizedExpression } — result is the value for the
supplied testValue, and normalizedExpression shows the ternary-to-if rewrite.
Result types
Features that persist a formula result (notably archive computed columns) store a result type
alongside the expression. The engine evaluates to double and then casts back:
| Result type | Cast-back |
|---|---|
Double | the raw value |
Int | truncated to a 32-bit integer |
Int64 | truncated to a 64-bit integer |
Boolean | false if the value is 0, otherwise true |
DateTime | the value is interpreted as .NET ticks (pairs naturally with now() / startOfDay()) |
A null-sentinel or NaN result always maps to null regardless of the chosen type.
The engine itself — the IFormulaEngine service contract, the mXparser dependency, the DI
registration and the shared ternary / null / cast-back conventions — is documented in the
developer guide: Formula Engine.