The ability to define new variables lies at the heart of the computational power that Ferret provides. Complex analyses in Ferret generally proceed as hierarchies of simple variable definitions. As a simple example, suppose we wish to calculate the root mean squared value of variable, V, over 100 time steps. We could achieve this with the simple hierarchy of definitions:
LET v_rms = v_mean_sq ^ 0.5 LET v_mean_sq = v_squared[L=@AVE] LET v_squared = v * v SET VARIABLE/TITLE="RMS V" v_rms LIST/L=1:100 v_rms (listed output not included)
As the example shows, the variables can be defined in any order and without knowledge in advance of the domain over which they will be evaluated. As variable definitions are given to Ferret with the LET (alias for DEFINE VARIABLE) command the expressions are parsed but not evaluated. Evaluation occurs only when an actual request for data is made. In the preceding example this is the point at which the LIST command is given. At that point Ferret uses the current context (SET REGION and SET DATA_SET) and the command qualifiers (e.g., "L=1:100") to determine the domain for evaluation. Ferret achieves great efficiency by evaluating only the minimum subset of data required to satisfy the request.
One consequence of this approach is that definitions such as
LET a = a + 1 ! nonsense
are nonsense within Ferret. The value(s) of variable "a" come into existence only as they are called for, thus it is nonsense for them to appear simultaneously on the left and right of an equal sign.
Variable names can be 1 to 128 characters in length and must begin with a letter. They must not match pseudo-variable names (e.g. X, Y, K, L, _E, _M) or operators ( AND, OR, GT, GE, LT, LE, EQ, NE, IF , and ELSE). See the command reference DEFINE VARIABLE for the available qualifiers when defining variables. The name that you give to the variable is in general not treated in a case-sensitive way. If you define for instance, variables named TEMP and Temp, both in the same Ferret session, the second definition will supersede any previous definitions. The only detail of case-sensitivity that is implemented is that on saving variables to a NetCDF file, the original upper- or lower-case spelling of the variable name will be retained.
All of the above definitions are examples of "global variable definitions." A global variable definition applies to all data sets. In the above example the expression "v_rms[D=dset_1]" would be based on the values and domain of the variable V from data set dset_1 and "v_rms[D=dset_2]" would similarly be drawn from data set dset_2. The domain of v_rms, its size, shape, and resolution, will depend on the particular data set in which it is evaluated.
Although global variables are simple to use they can lead to ambiguities. Suppose, for example, that data sets dset_1 and dset_2 contain the following variables:
dset_1 : speed
dset_2 : u, v
If we would like to compare speeds from the two data sets we might be tempted to define a new variable, speed, as
LET speed = (u*u + v*v)^0.5
In doing so, however, we create an ambiguity of interpretation for the expression "speed[d=dset_1]".
To avoid this ambiguity we need to create a variable definition, "speed," that is local to data set dset_2. The qualifier /D= used as follows
LET/D=dset_2 speed = (u*u + v*v)^0.5 ! in dset_2, only
provides this capability. The use of /D=dset_2 indicates that this new definition of "speed" applies only to data set dset_2.
A convenient shortcut is often to define a "default variable." A default variable is defined using the /D qualifier with no argument
LET/D speed = (u*u + v*v)^0.5 ! where "speed" doesn't already exist
As a default variable "speed" is a definition that applies only to data sets that would otherwise not posses a variable named speed. In this sense it is a fallback default.