Calculation examples
Sampled calculations
Add 2 variables
return _A.Value + _B.ValueSelect variable based on condition
if _A.Value > 100.0 {
return _B.Value
} else if _A.Value < 100.0 {
return _C.Value
}
return _A.ValueCalculate enthalpy - if97 steam functions and units
// Get input values for temperature and pressure from input references
temperatureCelsius := _A.Value // Assuming _A is an alias for temperature input in Celsius
pressureBar := _B.Value // Assuming _B is an alias for pressure input in Bar
// Convert temperature from Celsius to Kelvin
temperature := units.convert(temperatureCelsius, "C", "K")
// Convert pressure from Bar to Pascal
pascal := units.find("Pa")
pressure := units.convert(pressureBar, "bar", pascal)
// Calculate the specific enthalpy of steam using the if97.specificEnthalpy function
enthalpy := if97.specificEnthalpy(temperature, pressure)
// Save the enthalpy value in local memory (optional)
local.set("enthalpy", units.float(enthalpy))
// Return the calculated specific enthalpy
return enthalpyCalculate flow from current mass
mass := float(_A.Value) // Assuming _A is an alias for mass input in kg
seconds := Context.IntervalMs / 1000.0 // convert from milliseconds interval to seconds
return mass / seconds // flow rate in kg/sRaw calculations
Map number to string
if _A.Value == 1.0 {
return "STEP_A"
} else if _A.Value == 2.0 {
return "STEP_B"
}
return "INVALID"Map step numbers to string - setting status in script
// build map of step numbers
stepNumbers := {
"100": "RUNNING",
"101": "FILLING",
"102": "RUNNING",
"103": "EMPTYING",
"104": "BOTTLING",
"105": "PACKAGING",
"201": "CLEANING",
"300": "PLANNED_STOP",
"400": "UNPLANNED_STOP"
}
// look up current step in map
step := stepNumbers[_Category.Value]
/*
values not in map are considered bad data ->
set status other than Good to discard data for downstream processing
*/
if is_equal(step, undefined) {
set_status("BadUnknownStepNumber")
step = 0
}
return stepExtract value from string using regex
result := text.re_find("\\d+\\.?\\d*",_A.Value) // eg _A = "SOME_2344324.34_VALUE"
if result != undefined && len(result) > 0 {
found := result[0][0].text
return float(found)
}Elapsed time since previous value in seconds - set tag in script
previous := Context.PreviousInput._A
if previous {
// subtract timestamps
difference := times.sub(_A.Timestamp, previous.Timestamp)
// return result in seconds - default times.sub result is in nanoseconds
difference_seconds := times.duration_seconds(difference)
// add a time series tag to the result indicating if the calculated difference is within the expected range
if difference_seconds > 10 || difference_seconds < 1 {
set_tag("range_check", "out_of_bounds")
} else {
set_tag("range_check", "OK")
}
return difference_seconds
}
return 0Use tags in calculation
if is_equal(_A.Tags.range_check, "OK") {
return _A.Value
}Incremental counter - local context library
threshold := 100
previous := float(local.get("previous"),0.0)
result := previous + _A.Value
if result >= threshold {
local.set("previous", 0.0)
return 0.0
}
local.set("previous",result)
return resultIncremental counter - calculation context
threshold := 100
previous := float(Context.PreviousResult.Value, 0.0)
result := previous + _A.Value
if result >= threshold {
return 0.0
}
return resultIncremental counter with 1 output point per day
previous := float(local.get("previous"),0.0)
result := previous + _A.Value
// calculate hour in the day
hour := times.time_hour(Context.Timestamp)
previous_hour := times.time_hour(Context.PreviousTimestamp)
/*
only when current and previous values are on different sides of 1pm, the value is returned and the counter reset
since the calculation is raw, we cannot be sure that the input has a value at exactly 1pm
if that would be the case, we could also use times.time_minute and times.time_second to match 1pm exactly
*/
if (hour >= 13 && previous_hour <= 13) {
local.set("previous", 0.0)
return result
}
// on all other timestamps, save the result but do not return it
local.set("previous",result)
// an empty return will not write a point to the time series database
return Current value from incremental counter with resets
/*
previous result is undefined at first
this should be prevented from impacting the result
*/
if is_equal(Context.PreviousResult, undefined) {
return 0.0
}
current := float(_A.Value)
previous := float(Context.PreviousResult.Value)
/*
if current value is lower than previous, counter was reset
we assume reset to zero and output current value as difference with zero
*/
if current < previous {
return current
}
// write difference with previous value
return current - previousConvert ASCII number to character
The library function fmt.sprintf is an alias for the builtin function format. The two scripts below are therefore identical.
return format("%c", int(_A.Value))return fmt.sprintf("%c", int(_A.Value))Integer-byte conversions
Convert 16-bit integer to byte, then convert each separate byte back to an 8-bit integer using a function and sum the result together.
// function to convert bytes to 8-bit integers
byteToInt := func(value) {
return text.parse_int(value, 2, 8)
}
// convert input integer to bytes
bts := fmt.sprintf("%016b", int(_A.Value))
// convert first and last 8 bits to separate integers
first := byteToInt(bts[:8])
last := byteToInt(bts[8:])
// sum the resulting numbers
return first + lastCalculate flow efficiency based on asset metadata
// get max flow from asset metadata
maxFlow := factry.get_input_asset_metadata("_A", "maxFlow")
return _A.Value / maxFlow // Assuming _A is an alias for flow input and maxFlow is in the same unitSimulated calculations
Generate random float between 0 and 1
return rand.float()Write value based on current time
For live calculations, times.now() provides the same timestamp as Context.Timestamp. However, for recalculations this is no longer the case.
// calculate hour in the day
hour := times.time_hour(Context.Timestamp)
// only return 1 between 1pm and 2pm
if (hour >= 13 && hour <= 14) {
return 1
}
return 0Write value based on current time - with timezones
// localize timestamp in Europe/Brussels time zone
timestamp := times.to_location(Context.Timestamp, "Europe/Brussels")
// calculate day of the month and hour in the day
day := times.time_weekday(timestamp)
hour := times.time_hour(Context.Timestamp)
// only return 1 between 1pm and 2pm on a Monday
if day == 1 && (hour >= 13 && hour <= 14) {
return 1
}
return 0Write formatted timestamp
// localize timestamp in Europe/Brussels time zone
timestamp := times.to_location(Context.Timestamp, "Europe/Brussels")
// format timestamp following the RFC3339 convention
return times.time_format(timestamp, times.format_rfc3339)