# Unit Analysis

Unit consistency

By associating a unit with every relevant identifier in your model, you enable AIMMS to automatically verify whether all terms in the assignments and constraints of your model are unit consistent. When AIMMS detects unit inconsistencies, this may help you to solve conceptual problems in your model, which could otherwise have remained undetected for a long time.

…always in atomic units

With every derived unit or compound unit symbol, it is possible to
associate a unique unit expression consisting of a constant scale factor
and atomic units only. *All assignments and definitions in AIMMS are
interpreted as formulas expressed in terms of these atomic unit
expressions, and unit consistency checking is based on this
interpretation*. While ignoring the constant scale factors, AIMMS will
verify that the atomic unit expression for every term in either an
assignment statement or a constraint is identical. If the resulting unit
check identifies an inconsistency, an error or warning will be
generated.

Example

Consider the identifiers `a`

, `b`

, and `c`

having units `[m]`

,
`[km]`

, and `[10*m]`

respectively, all with `[m]`

as their
corresponding associated atomic unit expression, and scale factors 1,
1000 and 10, respectively. Then the assignment

```
c := a + b ;
```

is *unit consistent*, because all terms share the same atomic unit
expression `[m]`

.

Constant expressions

If an expression on the right-hand side of an assignment consists of a
constant scalar term or a data expression (preceded by the keyword
`DATA`

), AIMMS will assume by default that such expressions have the
same unit as the identifier on the left-hand side. If the intended unit
of the right-hand side is different than the declared unit of the
identifier on the left, you should explicitly specify the appropriate
unit for this term, by locally overriding the unit as explained in
Locally Overriding Units.

Constant terms in expressions

On the other hand, if a non-constant expression contains a constant term, then AIMMS will make no assumption about the intended unit of the constant term. In fact, it is considered unitless. If a unit inconsistency occurs for that reason, you should explicitly add a unit to the constant term to resolve the inconsistency, as explained in Locally Overriding Units.

Example

Given parameters `a`

(`[m]`

and `b`

(`[km]`

), as well as a
1-dimensional parameter `d(i)`

with associated unit `[m]`

, the
following assignments illustrate the interpretation of constant numbers
by AIMMS.

```
a := 10; ! OK: constant number 10 interpreted as [m]
a := 10 [km]; ! OK: constant number 10 interpreted as [km]
d(i) := DATA { 1: 10, 2: 20 }; ! OK: all data interpreted as [m]
a := 10*b; ! OK: constant number 10 considered unitless
a := b + 10; ! ERROR: unit inconsistency, constant term 10 unitless
a := b + 10 [km]; ! OK: unit inconsistency resolved
```

Automatic unit checking on or off

By default, the global AIMMS option to perform automatic unit analysis is on and inconsistencies are detected. AIMMS will produce either warning messages or error messages (the former is the default). You can find the full details on all unit-related options in the help file that comes with your AIMMS system.

Automatic scale consistency

The assignment `c := a + b`

of the first example in this section is
unit consistent, but it does not appear to be *scale consistent* since
the units of `a`

, `b`

and `c`

have different scales. In AIMMS,
however, a unit consistent assignment is automatically scale consistent,
because AIMMS translates and stores all data in terms of the underlying
atomic unit expression. In the example, this implies that the use of the
values of `a`

, `b`

, and `c`

as well as the assignment are in the
atomic unit `[m]`

. Consequently, AIMMS can now directly execute the
assignment, and the scale consistency is automatically ensured. Of
course, any *display* of values of `a`

, `b`

and `c`

will be again
in terms of the units associated with these identifiers.

Advanced example…

This example illustrates a number of identifiers with compound unit
definitions. It is based on the SI units for weight, velocity and
energy, and uses the derived units `ton`

, `km`

, `h`

and `MJ`

.

```
Variable WeightOfItem {
IndexDomain : i;
Unit : ton;
}
Variable VelocityOfItem {
IndexDomain : i;
Unit : Velocity: km/h;
}
Variable KineticEnergyOfItem {
IndexDomain : i;
Unit : MJ;
Definition : 1/2 * WeightofItem(i) * VelocityOfItem(i)^2;
}
```

Any display of these variables will be in terms of `ton`

, `km/h`

and
`MJ`

, respectively, but internally AIMMS uses the units `kg`

,
`m/s`

and `kg*m^2/s^2`

for storage. The latter represent the
corresponding unique atomic unit expressions associated with weight,
velocity and energy.

…is unit consistent

As a consequence of specifying units, there will be an automatic
consistency check on the defined variable `KineticEnergyOfItem(i)`

.
AIMMS interprets the definition of `KineticEnergyOfItem(i)`

as a
formula expressed in terms of the atomic units. The relevant unit
components are:

`[ton ] = 10^3 * [kg ]`

,`[km/h] = (1/3.6) * [m/s ]`

, and`[MJ ] = 10^6 * [kg*m^2/s^2]`

.

The definition of `KineticEnergyOfItem(i)`

as expressed in terms of
atomic units is `kg*(m/s)^2`

, while its own unit in terms of atomic
units is `kg*m^2/`

`s^2`

. These two unit expressions are
consistent.

Beware of non-absolute units

If the unit conversion between a derived unit and its corresponding
atomic unit not only consists of a scale factor, but also contains a
constant term, such a derived unit is referred to as a *non-absolute*
unit. If an arithmetic expression in your model refers to identifiers or
constants expressed in a non-absolute unit, you should pay special
attention to make sure that the result of the computation is what you
intended. The following example makes the point.

Example

Consider the following quantity declaration.

```
Quantity Temperature {
BaseUnit : K;
Conversions : degC -> K : # -> # + 273.15;
}
```

Given this declaration, what is the result of the assignment

```
x := 1 [degC] + 2 [degC];
```

where `x`

is a scalar parameter with unit `degC`

? Following the
rules explained above-AIMMS stores all data and performs all
computations in terms of atomic units- AIMMS performs the following
computation internally

```
x := 274.15 [K] + 275.15 [K];
```

resulting in an assignment to `x`

of \(549.3\)
`[K]`

\({}= 276.15\) `[degC]`

, which is probably not the
intended answer. The key observation is that in an addition only one of
the operands should be expressed in a non-absolute unit. Similarly, in a
multiplication or division probably none of the operands should be
expressed in a non-absolute unit. The mistake in the above assignment is
that the second argument in fact should be a temperature difference
(e.g. between 3 `[degC]`

and 1 `[degC]`

), which precisely yields an
expression in terms of the corresponding absolute unit `K`

:

```
x := 1 [degC] + (3 [degC] - 1 [degC]); ! equals 274.15 [K] + 2 [K] = 3 [degC]
```

Using temperature differences is more common in assignments to
identifiers like `LengthIncreasePerDegC`

(expressed in `[m/degC]`

),
which probably takes the form of a *difference quotient*, as illustrated
below.

```
LengthIncreasePerDegC := (Length1 - Length0) / (Temperature1 - Temperature0);
```

Units and intrinsic functions

When you use an intrinsic AIMMS function (see Arithmetic Functions) inside an expression in your model, the unit associated with the corresponding function call will in general depend on its arguments. The unit relationship between the arguments and the result of the function falls into one of the following function categories.

*Unitless*functions, for which both the arguments and the result are dimensionless. Examples are:`exp`

,`log`

,`log10`

,`errorf`

,`atan`

,`cos`

,`sin`

,`tan`

,`degrees`

,`radians`

,`atanh`

,`cosh`

,`sinh`

,`tanh`

, and the exponential operator with a non-constant exponent.*Transparent*functions that do not alter units. Examples are:`abs`

,`max`

,`min`

,`mod`

,`ceil`

,`floor`

,`precision`

,`round`

, and`trunc`

.*Conversion*functions that convert units in a predictable way. Examples are:`sqr`

,`sqrt`

, and the exponential operator with a constant integer exponent.

Explicit units in expressions

In some exceptional cases, one or more terms in an expression may not be unit consistent with the other terms in the expression. To restore unit consistency, AIMMS allows you to explicitly specify a unit for the inconsistent term(s) as an emergency measure. The syntax for such unit overrides is explained in Locally Overriding Units. You should make sure, however, that these explicit unit overrides do not affect the scale consistency of the expression (see Locally Overriding Units).

## Unit Analysis of Procedures and Functions

Unit analysis of procedures and functions

Once you have associated units of measurement with the global identifiers in your model, you will also need to associate units of measurement with the arguments, local identifiers and result values of procedures and functions. When you do so, you enable AIMMS to perform the common unit analysis on the statements in the bodies of all internal procedures and functions. For external procedures and functions, AIMMS cannot perform a unit analysis on the function and procedure bodies, but will use the assigned units for scaling purposes as explained in Unit-based Scaling.

Two procedure types

In general, one can distinguish two types of procedures and functions, namely

procedures and functions of a very specific nature, whose arguments and result values have associated units of measurement that are constant and known a priori, and

procedures and functions of a very general nature, whose arguments and result values can have any associated unit of measurement.

An example of the latter type is a function with a single one-dimensional argument to compute the average of all values contained in its argument. For such a function, the specific units associated with the argument and the result values are not known a priori, but it is known that they must be equal.

Express units in local unit parameters

To let you declare procedure and functions of the second type, AIMMS allows you to express the units of measurement of its arguments and the result values in terms of unit parameters (see also Unit-valued Parameters) declared locally within the procedure or function. At runtime, AIMMS will dynamically determine the value of the unit parameter, based on the actual arguments passed to the procedure or function. In addition, AIMMS will verify that the unit of a function value is commensurate with the remainder of the statement or expression from which it was called.

Example

The function `MyAverage`

in this example computes the average of a
general one-dimensional identifier. It combines AIMMS’ ability to define
arguments over local sets (see Internal Procedures), with a unit
expressed in term of a local unit parameter. Its declaration is given by

```
Function MyAverage {
Arguments : (Ident);
Unit : LocalUnit;
Body : {
MyAverage := sum(i, Ident(i)) / Card(LocalSet)
}
}
```

The single argument `Ident(i)`

of the function `MyAverage`

is
defined by

```
Parameter Ident {
IndexDomain : i;
Unit : LocalUnit;
}
Set LocalSet {
Index : i;
}
UnitParameter LocalUnit;
```

Note that `Ident(i)`

is defined over a local set `LocalSet`

and that
its unit is expressed in terms of a local unit parameter `LocalUnit`

,
both of which are determined at runtime. Because the unit of the
function `MyAverage`

itself is also equal to `LocalUnit`

, the
assignment in the body of `MyAverage`

is unit consistent.