G.1 Defining Transformation Functions

G.2 Calculating Intermediate Values

G.3 Expression Syntax

G.4 Variables

G.5 Literal Constants

G.6 Arithmetic Precision

G.7 Propagation of Missing Data

G.8 Arithmetic Operators

G.9 Logical Operators

G.10 Relational Operators

G.11 Bitwise Operators

G.12 Functions

G.13 Symbolic Constants

G.14 Evaluation Precedence and Associativity

G.2 Calculating Intermediate Values

G.3 Expression Syntax

G.4 Variables

G.5 Literal Constants

G.6 Arithmetic Precision

G.7 Propagation of Missing Data

G.8 Arithmetic Operators

G.9 Logical Operators

G.10 Relational Operators

G.11 Bitwise Operators

G.12 Functions

G.13 Symbolic Constants

G.14 Evaluation Precedence and Associativity

A MathMap is an AST Object which contains a recipe for transforming positions from one co-ordinate Frame to another and (optionally) back again. These transformations are specified using arithmetic operations and mathematical functions similar to those available in Fortran. WCSADD can be used to create a MathMap and store it in a text file, and such text files can then be used by applications such as REGRID which require a mapping.

A MathMap’s transformation functions are defined by a set of character strings holding Fortran-like expressions. If the required Mapping has Nin input axes and Nout output axes, you would normally supply the Nout expressions for the forward transformation. For instance, if Nout is 2 you might use:

which defines a transformation from Cartesian to polar co-ordinates. Here, the variables that appear on the left of each expression (R and THETA) provide names for the output variables and those that appear on the right (X and Y) are references to input variables.

To complement this, you must also supply expressions for the inverse transformation. In this case, the number of expressions given would normally match the number of MathMap input co-ordinates, Nin. If Nin is 2, you might use:

which expresses the transformation from polar to Cartesian co-ordinates. Note that here the input variables (X and Y) are named on the left of each expression, and the output variables (R and THETA) are referenced on the right.

Normally, you cannot refer to a variable on the right of an expression unless it is named on the left of an expression in the complementary set of functions. Therefore both sets of functions (forward and inverse) must be formulated using the same consistent set of variable names. This means that if you wish to leave one of the transformations undefined, you must supply dummy expressions which simply name each of the output (or input) variables. For example, you might use:

for the inverse transformation above, which serves to name the input variables but without defining an inverse transformation.

It is sometimes useful to calculate intermediate values and then to use these in the final expressions for the output (or input) variables. This may be done by supplying additional expressions for the forward (or inverse) transformation functions. For instance, the following array of five expressions describes two-dimensional pin-cushion distortion:

’R = SQRT( XIN $*$ XIN $+$ YIN $*$ YIN )’

’ROUT = R $*$ ( 1 $+$ 0.1 $*$ R $*$ R )’

’THETA = ATAN2( YIN, XIN )’,

’XOUT = ROUT $*$ COS( THETA )’

’YOUT = ROUT $*$ SIN( THETA )’

’ROUT = R $*$ ( 1 $+$ 0.1 $*$ R $*$ R )’

’THETA = ATAN2( YIN, XIN )’,

’XOUT = ROUT $*$ COS( THETA )’

’YOUT = ROUT $*$ SIN( THETA )’

Here, we first calculate three intermediate results ($R$, $ROUT$ and $THETA$) and then use these to calculate the final results ($XOUT$ and $YOUT$). The MathMap knows that only the final two results constitute values for the output variables because its Nout attribute is set to 2. You may define as many intermediate variables in this way as you choose. Having defined a variable, you may then refer to it on the right of any subsequent expressions.

Note that when defining the inverse transformation you may only refer to the output variables $XOUT$ and $YOUT$. The intermediate variables $R$, $ROUT$ and $THETA$ (above) are private to the forward transformation and may not be referenced by the inverse transformation. The inverse transformation may, however, define its own private intermediate variables.

The expressions given for the forward and inverse transformations closely follow the syntax of Fortran (with some extensions for compatibility with the C language). They may contain references to variables and literal constants, together with arithmetic, logical, relational and bitwise operators, and function invocations. A set of symbolic constants is also available. Each of these is described in detail below. Parentheses may be used to override the normal order of evaluation. There is no built-in limit to the length of expressions and they are insensitive to case or the presence of additional white space.

Variable names must begin with an alphabetic character and may contain only alphabetic
characters, digits, and the underscore character `"_"`

. There is no built-in limit to the
length of variable names.

Literal constants, such as `"0"`

, `"1"`

, `"0.007"`

or `"2.505E-16"`

may appear in expressions,
with the decimal point and exponent being optional (a `"D"`

may also be used as an
exponent character). A unary minus `"-"`

may be used as a prefix.

All arithmetic is floating point, performed in double precision.

Unless indicated otherwise, if any argument of a function or operator has a bad
value (indicating missing data), then the result of that function or operation
is also bad, so that such values are propagated automatically through all
operations performed by MathMap transformations. The special value used to
flag bad values can be represented in expressions by the symbolic constant
`"`

$<$bad$>$`"`

.

A $<$bad$>$ result is also produced in response to any numerical error (such as division by zero or numerical overflow), or if an invalid argument value is provided to a function or operator.

The following arithmetic operators are available:

- X1 $+$ X2: Sum of X1 and X2.
- X1 - X2: Difference of X1 and X2.
- X1 $\ast $ X2: Product of X1 and X2.
- X1 / X2: Ratio of X1 and X2.
- X1 $\ast $$\ast $ X2: X1 raised to the power of X2.
- $+$ X: Unary plus, has no effect on its argument.
- - X: Unary minus, negates its argument.

Logical values are represented using zero to indicate .FALSE. And non-zero to indicate
.TRUE.. In addition, the bad value is taken to mean `"unknown"`

. The values returned by
logical operators may therefore be 0, 1 or bad. Where appropriate, `"tri-state"`

logic is
implemented. For example, A.OR.B may evaluate to 1 if A is non-zero, even if B has the
bad value. This is because the result of the operation would not be affected by the
value of B, so long as A is non-zero.

The following logical operators are available:

- X1 .AND. X2: Logical AND between X1 and X2, returning 1 if both X1 and X2
are non-zero, and 0 otherwise. This operator implements tri-state logic.
(The synonym
`"&&"`

is also provided for compatibility with C.) - X1 .OR. X2: Logical OR between X1 and X2, returning 1 if either X1 or X2 are
non-zero, and 0 otherwise. This operator implements tri-state logic. (The synonym
`"$|$$|$"`

is also provided for compatibility with C.) - X1 .NEQV. X2: Logical exclusive OR (XOR) between X1 and X2, returning 1 if exactly
one of X1 and X2 is non-zero, and 0 otherwise. Tri-state logic is not used with
this operator. (The synonym
`".XOR."`

is also provided, although this is not standard Fortran. In addition, the C-like synonym`"$$`

may be used, although this is also not standard.)

$$^

"^ - X1 .EQV. X2: Tests whether the logical states of X1 and X2 (
*i.e.*.TRUE./.FALSE.) are equal. It is the negative of the exclusive OR (XOR) function. Tri-state logic is not used with this operator. - .NOT. X: Logical unary NOT operation, returning 1 if X is zero, and 0
otherwise. (The synonym
`"`

!`"`

is also provided for compatibility with C.)

Relational operators return the logical result (0 or 1) of comparing the values of two floating-point values for equality or inequality. The bad value may also be returned if either argument is $<$bad$>$.

The following relational operators are available:

- X1 .EQ. X2: Tests whether X1 equals X2. (The synonym
`"=="`

is also provided for compatibility with C.) - X1 .NE. X2: Tests whether X1 is unequal to X2. (The synonym
`"!="`

is also provided for compatibility with C.) - X1 .GT. X2: Tests whether X1 is greater than X2. (The synonym
`"$>$"`

is also provided for compatibility with C.) - X1 .GE. X2: Tests whether X1 is greater than or equal to X2. (The synonym
`"$>$="`

is also provided for compatibility with C.) - X1 .LT. X2: Tests whether X1 is less than X2. (The synonym
`"$<$"`

is also provided for compatibility with C.) - X1 .LE. X2: Tests whether X1 is less than or equal to X2. (The synonym
`"$<$="`

is also provided for compatibility with C.)

Note that relational operators cannot usefully be used to compare values with the $<$bad$>$ value (representing missing data), because the result is always $<$bad$>$. The ISBAD() function should be used instead.

Note, also, that because logical operators can operate on floating point values, care must be taken to use parentheses in some cases where they would not normally be required in Fortran. For example, the expression:

must be written:

to prevent the .NOT. Operator from associating with the variable A.

Bitwise operators are often useful when operating on raw data (*e.g.* from instruments),
so they are provided for use in MathMap expressions. In this case, however, the values
on which they operate are floating-point values rather than the more usual pure
integers. In order to produce results which match the pure integer case, the operands
are regarded as fixed point binary numbers (*i.e.* with the binary equivalent
of a decimal point) with negative numbers represented using twos-complement
notation. For integer values, the resulting bit pattern corresponds to that of
the equivalent signed integer (digits to the right of the point being zero).
Operations on the bits representing the fractional part are also possible,
however.

The following bitwise operators are available:

- X1 $>$$>$ X2: Rightward bit shift. The integer value of X2 is taken (rounding towards zero) and the bits representing X1 are then shifted this number of places to the right (or to the left if the number of places is negative). This is equivalent to dividing X1 by the corresponding power of 2.
- X1 $<$$<$ X2: Leftward bit shift. The integer value of X2 is taken (rounding towards zero), and the bits representing X1 are then shifted this number of places to the left (or to the right if the number of places is negative). This is equivalent to multiplying X1 by the corresponding power of 2.
- X1 & X2: Bitwise AND between the bits of X1 and those of X2 (equivalent to a logical AND applied at each bit position in turn).
- X1 $|$ X2: Bitwise OR between the bits of X1 and those of X2 (equivalent to a logical OR applied at each bit position in turn).
- X1 $$

X2: Bitwise exclusive OR (XOR) between the bits of X1 and those of X2 (equivalent to a logical XOR applied at each bit position in turn).^

Note that no bit inversion operator is provided. This is because inverting the
bits of a twos-complement fixed point binary number is equivalent to simply
negating it. This differs from the pure integer case because bits to the right
of the binary point are also inverted. To invert only those bits to the left
of the binary point, use a bitwise exclusive OR with the value -1 (*i.e.*
X$$

-1).

The following functions are available:

- ABS(X): Absolute value of X (sign removal), same as FABS(X).
- ACOS(X): Inverse cosine of X, in radians.
- ACOSD(X): Inverse cosine of X, in degrees.
- ACOSH(X): Inverse hyperbolic cosine of X.
- ACOTH(X): Inverse hyperbolic cotangent of X.
- ACSCH(X): Inverse hyperbolic cosecant of X.
- AINT(X): Integer part of X (round towards zero), same as INT(X).
- ASECH(X): Inverse hyperbolic secant of X.
- ASIN(X): Inverse sine of X, in radians.
- ASIND(X): Inverse sine of X, in degrees.
- ASINH(X): Inverse hyperbolic sine of X.
- ATAN(X): Inverse tangent of X, in radians.
- ATAND(X): Inverse tangent of X, in degrees.
- ATANH(X): Inverse hyperbolic tangent of X.
- ATAN2(X1, X2): Inverse tangent of X1/X2, in radians.
- ATAN2D(X1, X2): Inverse tangent of X1/X2, in degrees.
- CEIL(X): Smallest integer value not less then X (round towards plus infinity).
- COS(X): Cosine of X in radians.
- COSD(X): Cosine of X in degrees.
- COSH(X): Hyperbolic cosine of X.
- COTH(X): Hyperbolic cotangent of X.
- CSCH(X): Hyperbolic cosecant of X.
- DIM(X1, X2): Returns X1-X2 if X1 is greater than X2, otherwise 0.
- EXP(X): Exponential function of X.
- FABS(X): Absolute value of X (sign removal), same as ABS(X).
- FLOOR(X): Largest integer not greater than X (round towards minus infinity).
- FMOD(X1, X2): Remainder when X1 is divided by X2, same as MOD(X1, X2).
- GAUSS(X1, X2): Random sample from a Gaussian distribution with mean X1 and standard deviation X2.
- INT(X): Integer part of X (round towards zero), same as AINT(X).
- ISBAD(X): Returns 1 if X has the $<$bad$>$ value, otherwise 0.
- LOG(X): Natural logarithm of X.
- LOG10(X): Logarithm of X to base 10.
- MAX(X1, X2, ...): Maximum of two or more values.
- MIN(X1, X2, ...): Minimum of two or more values.
- MOD(X1, X2): Remainder when X1 is divided by X2, same as FMOD(X1, X2).
- NINT(X): Nearest integer to X (round to nearest).
- POISSON(X): Random integer-valued sample from a Poisson distribution with mean X.
- POW(X1, X2): X1 raised to the power of X2.
- RAND(X1, X2): Random sample from a uniform distribution in the range X1 to X2 inclusive.
- SECH(X): Hyperbolic secant of X.
- SIGN(X1, X2): Absolute value of X1 with the sign of X2 (transfer of sign).
- SIN(X): Sine of X in radians.
- SINC(X): Sinc function of X [= SIN(X)/X].
- SIND(X): Sine of X in degrees.
- SINH(X): Hyperbolic sine of X.
- SQR(X): Square of X (= X$\ast $X).
- SQRT(X): Square root of X.
- TAN(X): Tangent of X in radians.
- TAND(X): Tangent of X in degrees.
- TANH(X): Hyperbolic tangent of X.

The following symbolic constants are available (the enclosing
`"`

$<$$>$`"`

brackets must be included):

- $<$bad$>$: The ‘bad’ value used to flag missing data. Note that you cannot usefully compare values with this constant because the result is always $<$bad$>$. The ISBAD() function should be used instead.
- $<$dig$>$: Number of decimal digits of precision available in a floating-point (double-precision) value.
- $<$e$>$: ?? of natural logarithms.
- $<$epsilon$>$: Smallest positive number such that 1.0$+$$<$epsilon$>$ is distinguishable from unity.
- $<$mant_dig$>$: The number of base $<$radix$>$ digits stored in the mantissa of a floating-point (double-precision) value.
- $<$max$>$: Maximum representable floating-point (double-precision) value.
- $<$max_10_exp$>$: Maximum integer such that 10 raised to that power can be represented as a floating-point (double-precision) value.
- $<$max_exp$>$: Maximum integer such that $<$radix$>$ raised to that power minus 1 can be represented as a floating-point (double-precision) value.
- $<$min$>$: Smallest positive number which can be represented as a normalised floating-point (double-precision) value.
- $<$min_10_exp$>$: Minimum negative integer such that 10 raised to that power can be represented as a normalised floating-point (double-precision) value.
- $<$min_exp$>$: Minimum negative integer such that $<$radix$>$ raised to that power minus 1 can be represented as a normalised floating-point (double-precision) value.
- $<$pi$>$: Ratio of the circumference of a circle to its diameter.
- $<$radix$>$: The radix (number base) used to represent the mantissa of floating-point (double-precision) values.
- $<$rounds$>$: The mode used for rounding floating-point results after addition. Possible values include: -1 (indeterminate), 0 (toward zero), 1 (to nearest), 2 (toward plus infinity) and 3 (toward minus infinity). Other values indicate machine-dependent behaviour.

Items appearing in expressions are evaluated in the following order (highest precedence first):

- Constants and variables
- Function arguments and parenthesised expressions
- Function invocations
- Unary $+$ - ! .not.
- $\ast $$\ast $
- $\ast $ /
- $+$ -
- $<$$<$ $>$$>$
- $<$ .lt. $<$= .le. $>$ .gt. $>$= .ge.
- == .eq. != .ne.
- &
- $$
^ - $|$
- && .and.
- $$

$$^ ^ - $|$$|$ .or
- .eqv. .neqv. .xor.

All operators associate from left-to-right, except for unary $+$, unary -, !, .not. And $\ast $$\ast $ which associate from right-to-left.