---
title: Calculation examples
slug: how-tos/0E8I-calculation-examples
createdAt: 2025-09-24T16:23:11.379Z
---

## Sampled calculations

### Add 2 variables

:::CodeblockTabs
Tengo

```go
return _A.Value + _B.Value
```
:::

### Select variable based on condition

:::CodeblockTabs
Tengo

```go
if _A.Value > 100.0 {
  return _B.Value
} else if _A.Value < 100.0 {
  return _C.Value
}
return _A.Value
```
:::

### Calculate enthalpy - if97 steam functions and units

:::CodeblockTabs
Tengo

```go
// 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 enthalpy
```
:::

### Calculate flow from current mass

:::CodeblockTabs
Tengo

```go
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/s
```
:::

## Raw calculations

### Map number to string

:::CodeblockTabs
Tengo

```go
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

:::CodeblockTabs
Tengo

```go
// 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 step
```
:::

### Extract value from string using regex

:::CodeblockTabs
Tengo

```go
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

:::CodeblockTabs
Tengo

```go
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 0
```
:::

### Use tags in calculation

:::CodeblockTabs
Tengo

```go
if is_equal(_A.Tags.range_check, "OK") {
    return _A.Value
}
```
:::

### Incremental counter - local context library

:::CodeblockTabs
Tengo

```go
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 result
```
:::

### Incremental counter - calculation context

:::CodeblockTabs
Tengo

```go
threshold := 100
previous := float(Context.PreviousResult.Value, 0.0)
result := previous + _A.Value

if result >= threshold {
	return 0.0
}

return result
```
:::

### Incremental counter with 1 output point per day

:::CodeblockTabs
Tengo

```go
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

:::CodeblockTabs
Tengo

```go
/*
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 - previous
```
:::

### Convert ASCII number to character

The library function `fmt.sprintf` is an alias for the builtin function `format`. The two scripts below are therefore identical.

:::CodeblockTabs
Tengo

```go
return format("%c", int(_A.Value))
```
:::

:::CodeblockTabs
Tengo

```go
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.

:::CodeblockTabs
Tengo

```go
// 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 + last
```
:::

### Calculate flow efficiency based on asset metadata

:::CodeblockTabs
Tengo

```go
// 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 unit
```
:::

## Simulated calculations

### Generate random float between 0 and 1

:::CodeblockTabs
Tengo

```go
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.

:::CodeblockTabs
Tengo

```go
// 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 0
```
:::

### Write value based on current time - with timezones

:::CodeblockTabs
Tengo

```go
// 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 0
```
:::

### Write formatted timestamp

:::CodeblockTabs
Tengo

```go
// 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)
```
:::
