Expressions - The TDI Language
All interfaces to MDSplus data are based on the evaluation of expressions. These expressions are written in a language called TDI (tree data interface) which supports a large number of functions and commands. TDI language has several hundred commands and programming constructs, fortunately, most users need only a handful of these. The simplest expressions are just node names and the evaluation returns the data in that node. Simple mathematical and logical operations are supported, along with string manipulation, simple programming instructions and commands to analyze or create specific MDSplus constructs. External routines written in other programming languages can be invoked, providing almost limitless flexibility. This capability has been widely used to provide access to legacy data through the MDSplus API.
Expressions are strings which can be evaluated by
or using the tag name
ip = mdsvalue('\ip')
will return an array containing the plasma current for the currently open shot. To get the time base for this data use the TDI function
t = mdsvalue('dim_of(\ip)')
For signals with more than one dimension,
x = mdsvalue('dim_of(\sig_name,0)') t = mdsvalue('dim_of(\sig_name,1)')
For many applications, this is all the knowledge of TDI that is needed. However, it is often convenient to use additional features.
mdsvalue('2+2') = 4 mdsvalue('2-2') = 0 mdsvalue('2*3') = 6 mdsvalue('6/2') = 3 mdsvalue('3^2') = 9
Thus calibration or normalization factors can be applied to data:
mdsvalue('\ip/1.e6') converts Ip from Amps to MAmps
A number of basic mathematical functions are built into TDI as well, including trigonometric, logarithmic, exponential, modulo, complex conjugate, and absolute value functions. Sums and products of arrays are available along with minima, maxima, and means. Logical operations, string manipulation, bitwise operations and variable type conversions can also be carried out. (See TDI manual for complete list.)
a = mdsvalue('sin(\x)') b = mdsvalue('sum(\y)') c = mdsvalue('mean(\z)') d = mdsvalue('abs(\w)')
Arrays of sequential integers or floats can be created:
mdsvalue('0:10') will yield [0,1,2,3,4,5,6,7,8,9,10]
String concatenation is useful for labeling plots in the SCOPE utility
mdsvalue('"abc" // "def"') = "abcdef"
TDI will attempt to reconcile mathematical operations with variables of different type or shape. Multiplying a scalar times a vector will return a vector. Adding an integer to a complex number returns a complex number. Specific details can be found in the TDI reference manual.
For convenience and to improve performance, intermediate results can be cached in memory using TDI VARIABLES. These variables are global in scope - that is they are available to all modules of an application. TDI variables are also useful for writing multi-line expressions
TDI variables always begin with the underscore character for example:
ip = mdsvalue('_ip = \ip') t = mdsvalue('dim_of(_ip)')
Note that commas are used to separate "lines" in TDI code. So that the example above could be written:
t = mdsvalue('_ip = \ip, dim_of(_ip)')
Where TDI returns the value of the last "line" in the expression.
For convenience, a set of mathematical and physical constants are built into TDI. These are preceded by a
mdsvalue('$pi') = 3.14159 mdsvalue('$qe') = 1.60218e-19 (electron charge)
Information on the current MDSplus session is available with the same syntax. The currently open shot, tree and the default node can be retrieved as follows:
mdsvalue('$shot') = 1234 mdsvalue('$expt') = magnetics mdsvalue('$default') = \magnetics::top
Arrays of any type can be subscripted to obtain particular values or subarrays.
mdsvalue('_x = 10*(0:10)') mdsvalue('_x') = 30 mdsvalue('_x[3:6]') = [30, 40, 50, 60]
If the variable being subscripted is a signal, the subscripting is carried out not with indices but in terms of the independent variables. For example the signal \ip as defined in our tree example has an independent dimension time in units of seconds:
mdsvalue('\ip[1.2]') yields the value of ip at 1.2 seconds
Note: subscripting on left side of equivalence statements is not allowed.
Passing Parameters to TDI Expressions
It is often necessary or useful to pass arguments from a program or procedure into a TDI expression. This is most commonly used when creating composite variable types as described in the next section. Parameters to be substituted are indicated by a "$" sign in the TDI expression. The arguments are passed to the
b = 3 mdsvalue('_a = 0:4') mdsvalue('_a*$',b) = [0, 3, 6, 9, 12]
The order in which external arguments are used can be defined explicitly by numbering the "$" signs. Consider the following examples
mdsvalue('$-$',2,1) = 1 mdsvalue('$-$',1,2) = -1 mdsvalue('$1-$2',2,1) = 1 mdsvalue('$2-$1',2,1) = -1
Creating Signals, Units
Composite variable types are built with TDI expressions. The most useful of these types are signals and data "with units" and are created with:
Where DATA is any expression including TDI variables. Often parameter substitution is used to pass arrays into these functions. UNITS is a character string containing the units label. RAW is an optional component of a signal and is generally used to store the "counts" from a piece of data acquisition hardware. A "*" symbol is used when this argument is not supplied.
A typical use of these commands would be:
. code to define variables x which is a position measured in meters and its independent variable t measured in seconds . . mdsvalue('_x = make_with_units($,"meters")',x) mdsvalue('_t = make_with_units($,"seconds")',t) mdsvalue('_a = make_signal(_x,*,_t)')
Resulting in the signal _a.
Retrieving Components of Composite Datatypes
TDI functions exist which retrieve individual components of composite datatypes like signals. We've already been introduced to one of these
mdsvalue('dim_of(signal[,n])') returns the nth dimension of a signal, defaults to 0th dimension mdsvalue('data(signal)') returns the data part of a signal mdsvalue('units(a)') returns the units of data with units mdsvalue('units(signal)') returns the units of a signal mdsvalue('units(dim_of(signal)') returns units of the dimension of a signal mdsvalue('raw_of(signal)') returns the raw part of a signal (if it exists)
Getting Information on Arrays
A number of functions are available to get the size and shape of multidimensional arrays. For example, given a, a node containing a floating point array with 10 x 24 elements:
mdsvalue('size(a)') = 240 (total number of elements) mdsvalue('sizeof(a)') = 960 (total number of bytes) mdsvalue('shape(a)') = 10, 24 (number of elements in each dimension)
Getting MDSplus Metadata
The TDI function
NODE Usually a string containing a fully qualified node name but may also be a node's numerical id (NID) or an array of NIDs. If not present, this argument defaults to the current default node. Wildcards may be used in the path name. See users manual section on tree syntax for details.
STRING A case-insensitive character scalar chosen from the table below. The string may be abbreviated in upper or lower case to any unique form.
USAGE A character scalar or array. This optional argument limits the search of NODE names. It must be a valid usage name like "SIGNAL", or "TEXT". "ANY" will cause nodes of all usage types to be searched.
The STRING names by returned type follow. Type of data returned STRING Metadata returned --------------------- ------ ----------------- Character FULLPATH path from top of tree MINPATH shortest relative path NODE_NAME last part of pathname PATH path from top or tag Logicals IS_CHILD parent relationship IS_MEMBER parent relationship PARENT_STATE parent on or off STATE on or off Long DEPTH tree parents above LENGTH data size NID_NUMBER tree logical offset NUMBER_OF_CHILDREN number of child nodes NUMBER_OF_MEMBERS number of member nodes PARENT_RELATIONSHIP child or member Long unsigned OWNER_ID rights identifier STATUS status Node data RECORD actual data Quadword unsigned TIME_INSERTED encoded date and time
Some examples of the getnci function (refering to tree in section?):
Get the full path corresponding to the tag name "ip" mdsvalue('getnci(\ip,"fullpath")') = '\MAGNETICS::TOP.PROCESSED.CURRENT_DATA:IP'
Get the depth of \ip in the magnetics tree hierarchy (see note 2) mdsvalue('getnci("\\ip","depth")') = 4
Same command using argument substitution mdsvalue('getnci($,"depth")',"\\ip") = 4 mdsvalue('getnci(\ip,"nid_number")') = 1299 mdsvalue('getnci(1299,"fullpath")') = '\MAGNETICS::TOP.PROCESSED.CURRENT_DATA:IP'
Note 1: If a node is itself an expression, getnci(node,"length") will return the size of the expression not the size of the array.
Note 2: Node references are usually not quoted. However getnci will accept this argument as a text string. In this case the double backslash is needed since \ is a reserved character in the C language (which MDSplus is written in). For more details see the discussion on "Node Spec or Character String?" in users guide.
Calling External Routines
TDI functionality can be extended via calls to external routines. These may be written in the TDI language itself and saved in files with the extension
Specific details for this process will differ between operating systems. Details can be found in the users guide.