ExpressionEvaluator
From fmepedia
ExpressionEvaluator is a Workbench Transformer.
| Table of contents |
An ExpressionEvaluator performs a mathematical calculation on one or more attributes. It is capable of doing rather advanced math. You can use the provided interface to set up the expressions, but you can also edit them manually.
Please note that the ExpressionEvaluator will fail if a non-numerical attribute value is used in an expression. However, as of FME2009 it will log the offending feature and record which transformer caused the failure.
Integer or Floating Point?
Remember when using the ExpressionEvaluator that using Integer values gives an Integer output.
For example...
10/4 = 2
Whereas...
10.0/4.0 = 2.5
In case you are using attribute values, the ExpressionEvaluator might still perfom integer math when the attributes are actually floating point numbers. In order to avoid getting the wrong results, it may be necessary to multiply by 1.0 somewhere in the process.
Calculating Angles?
Remember that the acos, asin, atan functions return values in radians!
Use an AngleConverter transformer to convert radian values to decimal degrees.
Calculating Angles - Integer or Floating Point?
To combine the above two topics if you keep getting zero angles it is probably because of an integer problem.
For example; find a line bearing using...
(acos((&_endx-&_startx)/&_length))
With my data I had endx=45, startx=15, length=50, giving me...
(45 - 15) / 50
The result of which ought to be 0.6 but because all of the inputs are integers so is the output, giving 0.0! And (acos(0.0) = 0.0
I got around this by adding 0.000000001 to the length giving...
(45 - 15) / 50.0000000001
...which returns the only slightly incorrect value.
Random Numbers
The rand function in the ExpressionEvaluator generates a random value between 0 and 1. If you need more flexibility here, try using the RandomNumberGenerator right befor the ExpressionEvaluator.
fmod function
The fmod function calculates the floating-point remainder F of X/Y - therefore you need to select two attributes [fmod({x,y})] even though when the function is placed you only get 'prompted' for one [fmod({x})].
Calculating the remainder can help to determine the parity of a number - ie is it odd or even. It's used in this custom transformer.
Using attributes
You can insert an attribute value in an expression by prefixing the attribute name with a '&'. E.g.
&_x * 10
ExpressionEvaluator Performance
A drawback of the ExpressionEvaluator is that it uses TCL and therefore the TCL interpreter. Every time a feature passes through it, the expression has to be "compiled" before the calculation can be made. So 1 million features = 1 million compilations!
This is especially problematic when you have split up a single expression over several ExpressionEvaluators (for ease of use and clarification).
There are two solutions to this:
- Consolidate ExpressionEvaluators together where possible.
- Put the expression into a TCL procedure called by a TCLCaller transformer. If you can avoid the use of TCL proc parameters [i.e. avoid proc myproc (a,b) and instead use FME_GetAttribute] then the TCL will only be compiled once - and not for every feature.
Example
This section shows various examples use of the ExpressionEvaluator transformer as a substitute for the Tester.
Basic Use
At the most commonly used level, the ExpressionEvaluator is basically a transformer for carrying out numeric calculations; for example:
a = b + c a = b - c a = b * c

Above: An ExpressionEvaluator set up to calculate a = b + c (notice that a is defined as the 'Destination Attribute').
ExpressionEvaluator and C
At a deeper level, the operators used by the ExpressionEvaluator are actually those defined by the programming language C (http://en.wikipedia.org/wiki/Operators_in_C_and_C++); this gives rise to other possibilities like AND and OR statements:
a = b & c (and) a = b | c (or)
However, this page is more concerned with using a Conditional Operator that effectively turns the ExpressionEvaluator into a combination of ExpressionEvaluator plus any number of Testers.
ExpressionEvaluator as a Tester
A conditional test allows the recreation of the structure If...Then...Else within the ExpressionEvaluator. The conditional operator (IF) is the ? character, and the else part is represented by a : character; for example:
a = X ? b : c
...which translates as if X then a = b else a = c
X itself is therefore where the test is defined. It can be equals, not equals, greater than, etc... For example:
a = (x > 4) ? b : c
...which translates as if x > 4 then a = b else a = c. Technically the brackets aren't needed around x > 4, but are included for clarity.

Above: An ExpressionEvaluator set up to calculate (x > 4) ? b : c

Above: Of course b and c could be constant values not attributes - here if x > 4 then a = 1 else a = 2.
NB: Did you spot the error above? There's a missing close brace - the final ")" character? Make sure your open and closing brackets are equal in number!
Equivalence Gotcha
One big gotcha for new users (and even experienced ones take a while to spot this mistake!), a test for equivalence uses the operator == (and not =); i.e. two equals signs not one. For example:
a = (x == 4) ? b : c
...giving if X is equal to 4 then a = b else a = c
For the more technical this is because a single equals sign is reserved for assigning a value (eg x = 4 means assign X the value of 4)
Nested Expressions
Nested tests are permitted (if you can get your head around the syntax); for example:
a = (x == 4) ? 1 : (y == 4) ? 2 : 3
...meaning that if x = 4 then a = 1, else if y = 4 then a = 2 else a = 3

Above: The above nested expression as defined in the ExpressionEvaluator
Why Bother?
A good question. It might look more complicated than using Testers etc (and it is) but it dramatically reduces the number of transformers you need to use and is therefore a good candidate for an FME best practice.

Above: The workspace with the above nested expression defined in the ExpressionEvaluator

Above: The workspace with the above nested expression defined as Testers and AttributeSetters
