Advanced calculations

The calculations that you can add to analysis sets are powered by our expression engine. This versatile engine enables you to implement rich logic in your analysis sets. Combined with the workflows, this enables you to create business logic within AlisQI.

This article presents an overview of how to create and use advanced expressions in AlisQI. Due to the vast possibilities, this guide is necessarily incomprehensive. Please refer to the resources on the bottom of this page for full documentation of the underlying syntax and available features.

Syntax and features

The expression engine is based on Twig, an open source templating engine. Calculations are evaluated in a sandboxed environment which offers many features, including functions, filters, tests and operators.

Operators

Twig provides a variety of operators for math, logic, comparisons and other means.

Here are some example to show you a few possibilities:

'Hello, ' ~ ({user_} ? {user_} : 'unknown user')
{a_} // ({b_} != 0 ? {b_} : 1)

Filters

Variables can be modified by filters . Filters are separated from the variable by a pipe symbol (|). Multiple filters can be chained. The output of one filter is applied to the next.
The following example converts a text variable to uppercase, using the upper filter:

{name_}|upper
	
See Twig documentation on filters

Functions

Functions can be called to generate content. Functions are called by their name followed by parentheses () and may have arguments.
For instance, the date function can convert date(time)s. The following function call returns the current date minus 2 dates:

date('-2days')
	

See Twig documentation on functions

Tests

Tests can be used to test a variable against a common expression.

{numericfield_} is odd
'pass' in {status_}
	

See Twig documentation on tests

Beyond result values

The sandbox offers more data than just the result values. You also have specifications, field visibility, attachments and more available to use.
You can use the following variables:

{field_}

The value for a particular field in your analysis set. Can be null.
For selection fields, this is the string value of the chosen option (e.g., "Pass").
{fieldname_}.id
For selection fields only.
The option's static id. Use this to prevent changes to the option value (e.g., from "Pass" to "OK") from impacting the calculation.
{fieldname_}.option
For selection fields only.
This syntax allows you to retrieve all field values from a selection list option. See example #7 below.
(Technically speaking, the .option is a hash of the selected option's values.)
{field_}.spec
The current specification values for this field.
For numeric fields (including calculations), this is a hash with keys min, innermin, goal, innermax, max. Access any boundary using {field_}.spec.min.
For selection fields, this is a list (array) of in-spec options (e.g., ['White', 'Transparent']).
{field_}.offspec and {field_}.offspec_internal
For selection and numeric fields only.
Boolean value which indicates whether the value is outside of (internal) specification.
{fieldname_}.label and {fieldname_}.unit The field's label and unit (if any, can be null).
{fieldname_}.decimals and {fieldname_}.default
For numeric fields (including calculations) only.
The field's number of decimals and default (if any, can be null).
{fieldname_}.visibility The current field visibility state for this field.
{fieldname_}.operator
For numeric fields (including calculations) only
The operator (< or >) set for this field (if any, can be null).
attachments The list (array) of filenames, e.g., ['CoA.pdf', 'Delivery by pallet.jpeg'].

Examples

To demonstrate the power of the expression engine, we now go through some real life examples.
These are just meant to inspire you. The possibilities are endless. Dive into the resources and go nuts!
1. Expiry date
Calculate the expiry date by adding 3 months to the production date
DATE_ADD_MONTH({productiondate_}, 3)
Alternatively, we could use the date filter to transform the production date string to a unix timestamp, add the necessary number of second, and convert back to a date string.
({productiondate_}|date('U') + 3 * 30 * 24 * 60 * 60)|date('Y-m-d')

2. Logical expressions

If (condition) then (A) else (B) 

Can be defined as: 

condition ? A : B
	

Read here about how to use logical operators in your expressions.

3. Use goal spec if no value was inputted
Use the inputted value, or fall back to the goal spec if no value was inputted. (Uses the ternary operator.)
{ph_} ?: {ph_}.spec.goal

4. Test if an attachment was uploaded

attachments is empty ? "No attachments" : ("Number of attachments: " ~ attachments|length)

5. List all pdf attachments

attachments|filter(att => att ends with '.pdf')|join("\n")

6. Find the lower of two dates
Convert date1 and date2 to timestamps, determine the minimum value, are transform back to yyyy-mm-dd again.

MIN({date1_}|date('U'), {date2_}|date('U'))|date('Y-m-d')

Actually, thanks to the formatting of date strings, we can compare the date strings directly

MIN({date1_}, {date2_})
7. User's name and e-mail address
Suppose the field assignee_ is a selection field based on the user list. The following will evaluate to the chosen user's address.
{assignee_}.option.email

Errors and warnings

The enormous flexibility offered by the expression engine does come with a price. It's possible to create calculations that will run into problems.

AlisQI will try to validate the calculation by evaluating it using dummy values, but it cannot possibly catch all errors. Therefore, a list of errors and warnings is displayed while creating the calculation, as well as in the result entry screen. Use the preview in the analysis-set management to test the calculation with different input without needing to actually store results.

Examples

Consider the following example for a numeric calculation: {$batch_}, where Batch is a text field. The syntax of this calculation is fine, but whether a batch number can be interpreted as a number depends on its value. "1234AB" will be interpreted as the number 1234, but "AB1234" cannot be interpreted as a number. AlisQI cannot predict what values will be used, so it can only warn that using a text field in a numeric calculation can cause issues.

Here's a more devious example, using a numeric field a: 1 + ({a} ?: {}). As long as the value for a is truthy (not empty and not 0), this calculation will evaluate to 1 + a, which will always be a number. However, if the value for a is empty, the engine will try to add a number and a hash, which isn't defined, and causes an error.

Caveats and technical details

If you read Twig's documentation, you may have noticed a couple of discrepancies with the syntax of calculations. To understand the differences, let's dive into how exactly calculations are evaluated.

First of all, calculation is enclosed in output delimiters: {{ calculation }}. Therefore, you cannot use Twig tags.

Next, the field variables (e.g., {field_}) are actually invalid syntax. AlisQI transforms these to values['field_']. Likewise, {field_}.spec.min is transformed to spec['field_'].min, etc. The sandbox context actually contains (only) the following variables: attachments, values, id, operator, decimals, default, label, unit. You can use these if you wish.

Useful resources

Still need help? Contact Us Contact Us