Expressions and operators
There are six numeric data types in NCL: double, float, long, integer,
short, byte
. The float type is the basic type for representing floating
point numbers; double will provide the same or more precision than float;
integer is the basic type for representing integral values; short will
have the same or less precision as integer; byte will almost always be
an 8-bit quantity. The algebraic operators operate on the numeric data
types.
The following table summarizes the non-numeric data types in NCL:
----------------------------------------------------------------
Data type Description
----------------------------------------------------------------
character Used to store a single character
string A finite sequence of characters
logical Can have one of two values: True or False
graphic References an instance of an HLU object
file References a disk file (returned by addfile)
----------------------------------------------------------------
For an expression to be evaluated correctly, it is often necessary to
convert one of the basic data types into another. This processes is called
"coercion" and it is often done automatically. For example, when a float
is multiplied by an integer, the integer will be converted to a float,
the multiplication performed, and a float calculated for the
expression value. The following table shows how the type coercions
are performed:
Type Coercible to
----------------------------------------------------------------
character string
----------------------------------------------------------------
short character
string
integer
long
logical
float
double
---------------------------------------------------------------
integer string
long
logical
float
double
----------------------------------------------------------------
long logical
string
float
double
----------------------------------------------------------------
float logical
string
double
----------------------------------------------------------------
All numeric data types, strings, characters, logical, and graphic types
can be created using the "new"
statement. There are two types of new calls: one creates an
array of data with a specific missing value assigned to each element;
the other creates the array of data using the default missing value.
The new function takes, as parameters, an array of dimension sizes,
the type keyword to create, and (optionally) a missing value to assign
to each element of the new data array. The following creates a
three-dimensional float array:
a = new((/5,6,7/),float)
The following is an example of how to assign a specific missing value.
a = new((/5,6,7/),float,-1e12)
File data types are created differently. A file type is created only by
the addfile function. Arrays of type graphic can be created with new,
but none of the elements of the array will actually reference an existing
HLU object. Each element will contain a missing value. In addition to
new, there are ways of entering data manually. Currently there are four
types of literal values. Floating point numbers must be entered with a
decimal point. The following show creation of data using literal
floating point values:
a = 2.
a = 1.2
a = (/ 1., 2., 3. /)
Integer values are specified without the decimal point:
a = 2
a = (/ 1, 2, 3 /)
String values are specified as characters enclosed in double quotes ("):
a = "NCAR Graphics"
Logical values are specified using the keywords "True" and "False":
a = False
The following table summarizes the primary operators in NCL.
The operators are presented in their order of precedence, that is, in the
evaluation of an expression, if one operator appears above another in
the table, it will be performed first. See the
examples of expression evaluation
below. If a
non-associative
operator (such as "^" or "%") occurs
successively, then the precedence proceeds left-to-right. For
example, 2^3^4 evaluates to 4096.
----------------------------------------------------------------
Operator Description Type
----------------------------------------------------------------
-> File variable metadata
----------------------------------------------------------------
@ Attribute metadata
& Coordinate variable metadata
! Dimension name metadata
----------------------------------------------------------------
- Unary negation algebraic
----------------------------------------------------------------
^ Exponentiation algebraic
----------------------------------------------------------------
* Multiplication algebraic
/ Division algebraic
% Modulus algebraic
----------------------------------------------------------------
+ Addition algebraic
- Subtraction algebraic
----------------------------------------------------------------
< Less than selector algebraic
> Greater than selector algebraic
----------------------------------------------------------------
.not. Logical negation logical
.le. Less than or equal to relational
.lt. Less than relational
.ge. Greater than or equal to relational
.gt. Greater than relational
.ne. Not equal to relational
.eq. Equal to relational
.and. And logical
.or. Or logical
.xor. Exclusive or logical
----------------------------------------------------------------
= Assignment assignment
----------------------------------------------------------------
- File variable (->)
- This operator requires two operands. The first operand is a
file variable (as created with an
addfile
command). The second operand is a variable name. The specified
variable is either set or retrieved as appropriate. The file variable
operator differs from other operators in that the operands are not expressions
but identifiers.
Examples:
file1->a = 5
file1->a@value = 22.
print(file1->var1)
- Attribute (@)
- This operator takes two operands. The first operand is a
variable name, and the second operand is an
attribute
name for the variable in the first operand. The result can be any type.
The attribute operator is similar to the file variable operator in that
its operands also must be identifiers and not expressions.
Examples:
a@units = "Degrees"
a@value = 3.14159
print(a@units)
- Coordinate variable (&)
- This operator requires two operands. The first operand is a
variable name, and the second operand is the
name of a dimension of
the first operand. The result is a
coordinate variable. The
values in the coordinate variable must be
monotonically increasing
or decreasing. If the value assigned is non-monotonic or contains
missing values, the assignment still occurs but a WARNING message
is generated and attempts to use coordinate subscripting will fail
with a FATAL message. The coordinate variable operator only
accepts identifiers just like the attribute and file variable
operators.
Example:
a&Dimension1 = (/.1,.2,.3,.4,.5,.../)
- Dimension name (!)
- This operator takes two operands. The first operand is either a
variable or a
file variable, and the second operand is an integer.
The second operand indicates the dimension number (starting with 0).
The result is of type string. This operator is used to retrieve or
set names for a variable's dimension(s).
- Unary negation (-)
- This operator operates on a single operand and that operand must
have a numeric type. If the operand is an array, the negation will
be applied individually to each element of the array.
- Exponentiation (^)
- This operator requires two operands. The first operand is raised
to the power of the second operand. The operands must be of
numeric type. If the first operand is negative, then the second
operand must be positive. If either operand is a non-linear array,
then the other operand must be a scalar or an array of the same shape.
An array raised to a scalar power results in an array of the same
size with each element of the original array raised to the scalar
power. A scalar raised to an array power will result in array of
the same shape as the power where each element of the array is
the scalar raised to the power of the array element. An array raised
to an array power results in the obvious thing. The result of the
exponentiation operator is of type double.
- Multiplication (*)
- This operator requires two operands. The first operand is multiplied
by the second operand. The operands must be of numeric type.
Array operands are handled in a manner analogous to that described
in exponentiation.
- Division (/)
- This operator requires two operands. The first operand is divided
by the second operand. The operands must be of numeric type. If
both operands are of type integer, then the result will be an
integer where any decimal remainders are truncated. Array operands
are handled in a manner analogous to that described in exponentiation.
- Modulus (%)
- This operator requires two operands of type integer. The result is
an integer type that is the integral remainder of dividing the
first operand by the second. Array operands are handled in a manner
analogous to that described for exponentiation.
- Addition (+)
- This operator requires two operands. The first operand is added to
the second operand. The operands must both be of numeric type or
both of string type. If both operands are of numeric type, then the
result will be the sum of the two operands; if both operands are
of string type, then the result will be the concatenation of the two
strings. Array operands are handled in a manner analogous to that
described for exponentiation.
- Subtraction (-)
- This operator requires two operands. The second operand is
subtracted from the first operand. The operands must both be of
numeric type. Array operands are handled in a manner analogous to
that described for exponentiation.
- Less than selector (<)
- This operator requires two operands. The result is the smaller of
the values in the first operand and the second operand. If one operand
is a scalar and the other is an array, then, for each array entry,
the smaller of the array element and the scalar is selected for each
element of the resultant array. The operands must either both be type
numeric, or both type string. For strings string1 and string2,
"string1 < string2" yields string1 if the first character of
string1 is less than the first character of string2 in the ASCII
collating sequence.
- Greater than selector (>)
- This operator requires two operands. The result is the larger of
the values in the first operand and the second operand. If one
operand is a scalar and the other is an array, then, for each
array entry, the larger of the array element and the scalar is
selected for each element of the resultant array. For strings
string1 and string2, "string1 > string2" yields string1 if
the first character of string1 is greater than the first character
of string2 in the ASCII collating sequence.
- Logical negation (.ne.)
- This operator requires a single logical operand and returns a
logical result. If the operand is True, then the result is False;
if the operand is False, then the result is True.
- Less than or equal to (.le.)
- This operator requires two operands of numeric type. The two operands
can be a scalar and an array, or two arrays of the same shape.
If a scalar is being compared to an array, then an array of
logical values is returned as per individual comparisons of the scalar
with each array element. If two arrays are being compared,
then an array of logical values is returned as per comparing
each of the elements in one array with those in the other.
- Less than (.lt.)
- This operator requires two operands of numeric type. The two
operands can be a scalar and an array, or two arrays of the same
shape. If a scalar is being compared to an array, then an array of
logical values is returned as per individual comparisons of the
scalar with each array element. If two arrays are being
compared, then an array of logical values is returned as per
comparing each of the elements in one array with those in the other.
-
Greater than or equal to (.ge.)
- This operator requires two operands of numeric type. The two
operands can be a scalar and an array, or two arrays of the same
shape. If a scalar is being compared to an array, then an array of
logical values is returned as per individual comparisons of
the scalar with each array element. If two arrays are being
compared, then an array of logical values is returned as per
comparing each of the elements in one array with those in the other.
- Greater than (.gt.)
- This operator requires two operands of numeric type. The two operands
can be a scalar and an array, or two arrays of the same shape. If
a scalar is being compared to an array, then an array of logical
values is returned as per individual comparisons of the scalar
with each array element. If two arrays are being compared, then
an array of logical values is returned as per comparing each of
the elements in one array with those in the other.
- Not equal to (.ne.)
- This operator requires two operands of any type and returns a
result of type logical. If a scalar is being compared to an array,
then an array of logical values is returned as per individual
comparisons of the scalar with each array element. If two arrays
are being compared, then an array of logical values is returned as
per comparing each of the elements in one array with those in the other.
- Equal to (.eq.)
- This operator requires two operands of any type and returns a
result of type logical. If a scalar is being compared to an
array, then an array of logical values is returned as per individual
comparisons of the scalar with each array element. If two arrays are
being compared, then an array of logical values is returned as per
comparing each of the elements in one array with those in the other.
- And (.and.)
- This operator requires two operands of type logical and returns a
result of type logical. The result is True if and only if both
operands are True.
- Or (.or.)
- This operator requires two operands of type logical and returns
a result of type logical. The result is True if and only if
either of the operands is True.
- Exclusive or (.xor.)
- This operator requires two operands of type logical and returns
a result of type logical. The result is True if and only if one,
but not both, of the operands is True.
- Assignment (=)
- The operator requires two operands. The value of the second operand
is assigned to the first operand. The type of the second operand must
be coercible to the type of the first operand.
An NCL expression is any sequence of operators and operands that results
in the computation of a value. In particular, any
literal value is an
expression, and any variable is an expression. Also, arrays are
expressions as well as functions and procedures. Operators applied to
expressions are expressions.
Parentheses surrounding an expression result in an expression and can be
used to alter the order of evaluation in expressions in the same manner
that they are used in most all programming languages. So, for example,
a + b / c
would be evaluated by dividing b by c and then adding a, whereas
(a + b)/ c
would be evaluated by adding b and a and then dividing by c.
Here are some examples of expressions:
.5
v1
sin(3.1415926)
a(2,3,1)^(b-1) + (file1->a)/2.718
String3 = "String1" + "String2"
(/2,8,11/) % (/2,3,4/)
((v1.lt.v3) .xor. (v2.lt.v4))
If a variable is created and no valid value has been assigned to that
variable, then that variable will have an
attribute named "_FillValue",
and the value of the variable will be set to the value of "_FillValue".
A pre-defined value of the same type as the variable will be assigned
to "_FillValue" unless a value has been specifically assigned by the
user. Consider the following NCL session:
ncl 0> a = new(2,float)
ncl 1> b = (/ 3., a(0) /)
ncl 2> print(b)
Variable: b
Type: float
Total Size: 8 bytes
2 values
Number of Dimensions: 1
Dimensions and sizes: [2]
Coordinates:
(0) 3
(1) -999
ncl 3> c = (/ 5., 8. /) + b
ncl 4> print(c)
Variable: c
Type: float
Total Size: 8 bytes
2 values
Number of Dimensions: 1
Dimensions and sizes: [2]
Coordinates:
(0) 8
(1) -991
The variable "a" is created using the new command and, since a has not
been assigned any value, it receives the default _FillValue of -999.
This value for a is used in the creation of b, and this becomes the
actual value of the second element of b. This value is used in the
computation of c.
If the variables making up an expression contain more than one
"_FillValue" value, the _FillValue of the left-most variable that
contains a missing value is used for the value of the expression.
The handling of
metadata in the computation of expressions presents
problems. For example, consider a case where one file named "east"
contains a vector variable U and another file named "north" contains a
vector variable V. Suppose U has an attribute "long_name" that is set
to "east wind component" and V has an attribute called "long_name" that
is set to "north wind component". Then, suppose we want to calculate the
wind speed and store the result in a variable c:
c = sqrt(east->U^2 + north->V^2)
Clearly, neither of the values for the attribute "long_name" applies
to c. Similarly, attributes like valid_range, valid_min, valid_max,
and scale_factor could not be correctly propagated to c. NCL solves
this problem simply by not propagating metadata in the evaluation of an
expression unless that expression is a single variable. This
rule also applies to variables used as parameters to functions.
----------------------------------------------------------------
Expression Evaluates as
----------------------------------------------------------------
a < b + c a < (b + c)
a/b*d%c ((a/b)*d) % c
a^b*-c/d+e%f<g ((((a^b)*(-c))/d) + (e % f)) < g
a+b.lt.c*d (a+b) .lt. (c*d)
a.le.c.or.d.gt.e.and.f.ne.g (a.le.c).or.((d.gt.e).and.(f.ne.g))
file2->a^3+file2->b*5 ((file2->a)^3) + ((file2->b)*5)
----------------------------------------------------------------
User Guide Control Panel
NG4.1 Home, Index, Examples, Glossary, Feedback, UG Contents, UG WhereAmI?
$Revision: 1.9 $ $Date: 1998/06/15 22:08:54 $