Tree Data Interface Help Topics
TDI VMS Help:

$ HELP/LIBRARY=MDS$ROOT:[SYSHLP]MDSPLUS.HLB TDISHR

C-like syntax case insensitive special functions for working with MDSplus objects ?can be invoked by putting call and args into an expression node in a tree, and then the actual TDI (compiled?) is found by looking in the sharable library pointed to by (TCL or MDS$TCL) SET LIBRARY ... or something like that

Variables


    Local variables are to be used to optimize code by not recalculating
and for
writing repeated or more complicated expressions. They should not be used to
carry information across trees because access is then order dependent.

>>>>>>>>>WARNING, they have side effects!!!

You may store any MDSplus data type in a variable and then reference it as you need it in other expressions.

>>>>>>>>>WARNING, the order of operations may not be clear (to you or the compiler), so be careful about assigning data to a variable and using the variable in the same expression. COMMA, VECTOR, and statements are left to right but argments of functions may be used in any order.

There are two forms of variables: private and public. The usual, private variables are seen only by your current FUN. Whereas, public variables can be seen by all programs. Anywhere a VAR like _X can be used, you may use PRIVATE _X or PUBLIC _X to distinguish the one you want. Otherwise on reading, _X looks for PRIVATE _X first and then PUBLIC _X. On writing, _X will be stored in the private list unless it was a modify operation like _X++ or _X+=6.

>>>>>>>>>WARNING, always use PUBLIC for public variables to help you analyze the code later.

All user variables should begin with an underscore (_); system variables will begin with a dollar sign ($). Names beginning with alphabetics look like tree members. The length must be less than 200. Upper and lower cases are not distinct, thus _a and _A are the same.

Literals

    Literals are constants written as text. Letters used to designate data type
and
base may be upper or lower case. 

Integers must begin with a number.

Prefixes designate base and are 0B for binary, 0O for octal, 0X for hexadecimal, and none for decimal.

Suffixes designated data type: BU for byte_unsigned, WU for word_unsigned, LU for long_unsigned, QU for quadword_unsigned, OU for octaword_unsigned, B for byte, W for word, L for long, Q for quadword, and O for octaword. No suffix is type L. You may use UB instead of BU for byte_unsigned and SB or BS instead of B for byte. After 0X use SB for signed bytes because the B looks like a digit.

Floating point numbers must have a decimal point or an exponent with following optionally signed digit or digits and at least one digit. The exponent designator is E or F for standard precision, D for double, G for wide-exponent double. Without an exponent, standard precision is assumed.

Complex numbers must be formed with the function CMPLX(real,imag). WARNING, you may specify D_COMPLEX and others but the precision of the arguments is determined by each exponent letter.

Characters or text may be enclosed in single quotes (apostrophes) or double quotes. TDISHR uses the CC-style designation of

        control characters (\001 or \n),
        the quoting character (\' or \"),
        and the backslash (\\) itself.

Hexadecimal control characters (\x8c) must be used with care, because they stop on the first non-hexadecimal character.

Octal controls are limited to three digits or the first non-octal one.

Adjacent text strings (possibly with white space between) are concatenated. This allows breaking of strings across more than one line. Otherwise, two literals may not be adjacent--bad syntax.

Glossary

array... A collection of scalars in a multidimensional rectangle.
axis.... The independent variable.
bounds.. Array subscript limits, lower and upper.
byte.... Eight bits of information, one character, an integer.
C$LIBRARY A logical definition of a .TLB for #include files.
call.... To invoke a subroutine during program execution.
CC...... The C-language compiler.
class... The class of a block of memory, static, dynamic, array.
complex. Real and imaginary parts joined.
conforming The matching of shapes, a scalar matches any shape.
descrip. The header file defining VMS descriptor, dtype, class.
descriptor The description of the contents of a memory block.
dimension An independent axis of an array.
dtype... The kind of a block of memory. A data type like long, usually a byte code.
dynamic. Data whose memory location is changable.
evaluate To remove references like NIDs, PATHs, and FUNCTIONs.
F90..... The Fortran 90 standard (as originally proposed).
float... A floating-point number, esp. a single-precision real.
function An opcode and arguments to determine a value.
include. A file .H for CC, .FOR for Fortran with definitions.
index... A subscript value.
integer. Whole numbers.
kind.... The data type of a block of memory. A data type like long, usually a byte code.
length.. The number of bytes in an element.
logical. Variable with two states: true or false; low bit tested. As opposed to CC-style that tests for zero.
matrix.. A two-dimensional array, usually.
MDSplus. The programs and libraries for data taking and analysis.
MDSLIB.. Routines easily called from VAX Fortran or IDL, etc.
MDSSHR.. Routines common to several MDSplus libraries.
missing. An omitted argument.
multiplier Array subscript number of values, upper-lower+1.
NID..... A node identifier, a number used in references in trees.
node.... A element of a tree with data and/or links to nodes.
numeric. Integer, real, or complex number.
OPC$.... Operation codes for TDISHR functions.
opcode.. An operation code identifying the action to take.
param... An independent value with textual and validation info.
path.... The textual name of a tree element.
pointer. The address of a memory object.
precedence The order operations are done without parentheses.
rank.... Dimensionality of an array. A scalar is rank 0.
real... An approximate number with exponent and fraction.
record.. A class-R descriptor or a data block on disk.
ROPRAND. The floating point reserved operand, a bad number. Similar to Not-A-Number in Unix. Infinity exists on both systems.
scalar.. A single value.
shape... The extent of all dimensions of an object.
signal.. Data, including the raw data, and independent axes.
signal_VMS To notify routines of some condition like an error.
signed.. Integer forms with positive and negative numbers.
size.... The number of elements of an array; sometimes bytes.
static.. Data with fixed memory location.
status.. An integer identifying severity and text of an error.
subscript The offset along a dimension of an array.
tdescrip The header file defining MDS descriptor, dtype, class.
TDISHR.. Tree Data Interface sharable library.
tree.... A linked collection of nodes.
units... The physical measure associated with a number.
unsigned Integer forms ranging from 0 to 2^(number of bits)-1.
vector.. A linearly ordered list of scalars. A rank-one array.
window.. The region of an axis that is viewed.
word.... Two bytes of information, an integer.
XD...... A class of descriptor for dynamic storage.

CC-use

    The easiest calls are the MDSLIB routines.

To eliminate using the compiler you could write functions to be evaluated. This involves many descriptors and pointers, see OPC$.

Between the inefficiency of compilation and the difficulty of function coding is the method of direct calls to the TDISHR library. Like

        status = TDI$ADD(&first_dsc, &second_dsc, &output_dsc);

Other than special calls directly into TDISHR, you call routines by names like TDI$xxx, where xxx is the function to be performed. Each routine returns a VMS-type status code as its function value. The arguments are the addresses of descriptors of each input with the final argument being the one output descriptor.

Operations like + have special names like TDI$ADD, see Precedence.

Calls

      As an example of TDISHR calls we will add 2 and a tree element.

        #include descrip
        int call_test(struct dsc$descriptor *out_dsc_ptr)
        {
            static int const two = 2;
            static struct dsc$descriptor two_dsc
                      = {0,DSC$K_DTYPE_L,DSC$K_CLASS_S,&two};
            static $DESCRIPTOR(const elem_dsc, "\\TOP.XRAY.CHAN_1:GAIN");
            int status;

            status = TDI$ADD(&two_dsc, &elem_dsc, out_dsc_ptr);
            return status;
        }

This example would be easier to code in VAX Fortran.

MDSLIB

      As an example of MDSLIB calls we will add 2 and a tree element. The
      experiment and shot are assumed identified elsewhere.

        #include descrip
        int call_test(struct dsc$descriptor *out_dsc_ptr)
       {
            static $DESCRIPTOR(const expression,
                      "2+\\TOP.XRAY.CHAN_01:GAIN");
            int status;

            status = MDS$VALUE(&expression, out_dsc_ptr);
            return status;
        }
(This example would be easier to code in VAX Fortran.)

OPC$

      The most difficult form of coding is to define all relationships with
pointers in special (class-R) descriptors to other descriptors of VMS and
MDSplus data. As an example, we will add 2 and a tree element. Use DCL to

DEFINE C$LIBRARY MDS$ROOT:[SYSLIB]MDSDEF.TLB

before compiling with CC the following code excerpt:

        #include descrip
        #include tdescrip
        int opc_test(struct dsc$descriptor *out_dsc_ptr)
       {
            globalref unsigned short OPC$ADD;
            static int const two = 2;
            static struct dsc$descriptor const two_dsc
                    = {sizeof(two),DSC$K_DTYPE_L,DSC$K_CLASS_S,&two};

            static $DESCRIPTOR(const elem_dsc, "\\TOP.XRAY.CHAN_1:GAIN");
            static struct dsc$descriptor_r const add_dsc
                    = {2,DSC$K_DTYPE_FUNCTION,DSC$K_CLASS_R,&OPC$ADD,2,0,
                       &two_dsc,&elem_dsc};
            int status;

            status = TDI$EVALUATE(&add_dsc, out_dsc_ptr);
            return status;
        }

The included files define the descriptor structures, descrip from VAXCDEF and tdescrip from MDSDEF. The global reference is to TDISHR and the function number is used by EVALUATE to do the operation. The node's data is fetched and its data type, and possibly two's data type, are converted to match. The addition is done and the result is embedded in units and signal descriptions as needed. The result is then matched to the output descriptor's data class and type. The output descriptor must be class-XD if the result is more complicated than a standard scalar. The input arguments could be "static const" because they are read only.

Status

      Each TDISHR routine returns a longword VMS-type status.
      The lowest bit is set (status & 1) if the operation succeeded.
      Otherwise, the error may be signaled by LIB$SIGNAL(status) or its text
fetched by SYS$GETMSG(status, &length_ret, &text_dsc, 15, 0).
Fortran-use

    The easiest calls are the MDSLIB routines.

To eliminate using the compiler you could write functions to be evaluated. This involves many descriptors and pointers, see OPC$.

Between the inefficiency of compilation and the difficulty of function coding is the method of direct calls to the TDISHR library.

status = TDI$ADD(%DESCR(first), %DESCR(second), output_dsc)

Other than special calls directly into TDISHR, you call routines by names like TDI$xxx, where xxx is the function to be performed. Each routine returns a VMS-type status code as its function value. The arguments are the addresses of descriptors of each input with the final argument being the one output descriptor.

Operations like + have special names like TDI$ADD, see Precedence. WARNING each TDI routine must be declared as an Integer*4. WARNING (Today, Fortran include file tdescrip does not exist.)

Calls

      As an example of TDISHR calls we will add 2 and a tree element.

        Integer function call_test(out_dsc)
        Include 'FORSYSDEF.TLB($DSCDEF)'
        Record /DSCDEF1/ out_dsc
        Integer two /2/
        Character*21 elem = '\TOP.XRAY.CHAN_1:GAIN'

        call_test = TDI$ADD(%descr(two), %descr(elem), out_dsc);
        Return
        End

We could also have used

TDI$ADD(%descr(2), '\TOP.XRAY.CHAN_1:GAIN', out_dsc)

MDSLIB


      As an example of MDSLIB calls we will add 2 and a tree element. The

experiment and shot are assumed identified elsewhere.  

        Integer function mds_test(dataid)
        Integer dataid

        mds_test = MDS$GET('2+\TOP.XRAY.CHAN_01:GAIN', dataid);
        Return
        End
OPC$

      The most difficult form of coding is to define all relationships with
pointers in special (class-R) descriptors to other descriptors of VMS and
MDSplus data. As an example, we will add 2 and a tree element. As of this
writing, there is no TDESCRIP definitions for Fortran use.  

        Integer Function opc_test(out_dsc)
        Include 'FORSYSDEF.TLB($DSCDEF)'
        Include 'FORMDSDEF.TLB(tdescrip)'
        Record /DSCDEF1/ out_dsc
        External OPC$ADD
        Integer two = 2
        Character*21 elem = '\TOP.XRAY.CHAN_1:GAIN'
        Record /DSC$DESCRIPTOR_R2/ add_dsc

        add_dsc.dsc$w_length = 2
        add_dsc.dsc$b_dtype = DSC$K_DTYPE_FUNCTION
        add_dsc.dsc$b_class = DSC$K_CLASS_R
        add_dsc.dsc$a_pointer = %loc(OPC$ADD)
        add_dsc.dsc$b_ndesc = 2
        add_dsc.dsc$a_dscptrs(1) = %loc(%descr(2))
        add_dsc.dsc$a_dscptrs(2) = %loc(%descr(elem))
        opc_test = TDI$EVALUATE(add_dsc, out_dsc);
        Return
        End

The included files define the descriptor structures. The external reference is satisfied by TDISHR and the function number is used by EVALUATE to do the operation. The node's data is fetched and its data type, and possibly two's data type, are converted to match. The addition is done and the result is embedded in units and signal descriptions as needed. The result is then matched to the output descriptor's data class and type. The output descriptor must be class-XD if the result is more complicated than a standard scalar.

There is no way in VAX Fortran to "Data" (initialize) a record. This is better done in C, if it is done at all.

Status

      Each TDISHR routine returns a longword VMS-type status. The lowest
bit is set (status .AND. 1) if the operation succeeded. Otherwise, the error
may be signaled by LIB$SIGNAL(%val(status)) or its text fetched by 

SYS$GETMSG(%val(status), length_ret, text_ret, %val(15), ).

Precedence

    TDISHR supports many syntactical forms having different precedence.
    Precedence determines the order operations are done when operators
are on both sides of a resolved portion of an expression. Thus, precedence
makes 2+3*4 have value 14 and not 20. 

Operators with equal precedence are evaluated left to right (LR) or right to left (RL). You may use F90 (/ for [, /) for ], and /= for !=.

group          function name symbol
(highest precedence)
-- grouping (none) (x)
LR postfix CALL(i,r,[x]...) i->r:type(x,...)
POST_DEC(v) v--
POST_INC(v) v++
SUBSCRIPT(x,y,...) x[y,...], x(/y,.../)
VECTOR(x,y,...) [x,y,...], (/x,y,.../)
RL unary INOT(x) ~x
NOT(x) !x, NOT x
PRE_DEC(v) --v
PRE_INC(v) ++v
UNARY_MINUS(x) -x
UNARY_PLUS(x) +x
RL power POWER(x,y) x^y, x**y
LR multiply MULTIPLY(x,y) x*y
DIVIDE(x,y) x/y
MOD(x,y) x MOD y
LR addition ADD(x,y) x+y
SUBTRACT(x,y) x-y
LR shift SHIFT_LEFT(x,y) x<<y
SHIFT_RIGHT(x,y) x>>y
LR concatenate CONCAT(x,y) x//y
LR subset IS_IN(x,y) x IS_IN y
LR inequality GE(x,y) x>=y, x GE y
GT(x,y) x>y, x GT y
LE(x,y) x<=y, x LE y
LT(x,y) x<y   x LT y
LR equality EQ(x,y) x==y, x EQ y
NE(x,y) x!=y, x<>y, x/=y, x NE y
LR bit-AND IAND(x,y) x&y (see IAND etc.)
LR bit-EOR (see IEOR etc.)
LR bit-OR IOR(x,y) x|y (see IOR etc.)
LR equivalence EQV(x,y) x EQV y
NEQV(x,y) x NEQV y
LR logical-OR OR(x,y) x && y, x OR y
OR_NOT(x,y) x OR_NOT y
NOR(x,y) x NOR y
NOR_NOT(x,y) x NOR_NOT y
LR logical-AND AND(x,y) x || y, x AND y
AND_NOT(x,y) x AND_NOT y
NAND(x,y) x NAND y
NAND_NOT(x,y) x NAND_NOT y
RL promotion PROMOTE(x,y) x@y
RL conditional CONDITIONAL(y,z,x) x?y:z
RL range BUILD_RANGE(x,y,[z])x..y, x..y..z, x:y, x:y:z
RL assignment EQUALS(v,x) v=x
EQUALS_FIRST(ADD(v,x)) v+=x, ... v MOD=x, ...
LR comma COMMA(x,y,...) x,y,...
LR statement (none) x;
STATEMENT(s,...) {s ...}
BREAK() BREAK;
CASE(x,s,...) CASE(x)s
CONTINUE() CONTINUE;
DEFAULT(s,...) CASE DEFAULT s
DO(x,s,...) DO{s...}WHILE(x);
FOR([x],[y],[z],s,...)FOR(x;y;z)s
FUN(f,s,v...) FUN f(v,...)s
PRIVATE FUN f(v,...)s
PUBLIC FUN f(v,...)s
GOTO(x) GOTO x;
IF(x,s,se) IF(x)s
IF(x)s ELSE se
LABEL(v,s,...) LABEL v: s
RETURN([x]) RETURN(x);
SWITCH(x,s,...) SWITCH(x) s
WHILE(x,s,...) WHILE(x)s
(lowest precedence)
where x, y, or z are resolved expressions, f and v are variables, and s and se are statements. Think about "-2.^-3^4". (Answer: -2.417852E24.)

Signals

    A signal is data with its source (RAW is usually an intermediate
expression) and its DIMENSIONs. The dimensions are the independent axes
of the dependent data. For example, a waveform is a function of time and
the dimension is the time points at which the waveform was recorded.
Often this axis is a simple expression that can be expressed as a SLOPE or
RANGE. 

In combining expressions with signals, generally a single signal will dominate. When more than one signal is combined, only one signal can be chosen. The signal selected will be the one with the smaller number of elements as this limits the size of the result.

Units

    Units can be added to any data field by the WITH_UNITS descriptor. 
    Units are the "dimensions". (Be careful not to confuse this with the
    word for the independent axis.) Units are like meters and seconds.

Spell out units with lowercase or better yet use the abbreviation. Proper names are spelled in lowercase or abbreviated in uppercase.

The basic unit names are:

        m       meter           kg      kilogram        s       second
        A       ampere          K       kelvin          mol     mole
        cd      candela

The supplementary unit names are:

        rad     radian          sr      steradian
Derived unit names are:

        Hz      hertz        	J    	joule        	N       newton
        Pa      pascal       	W   	 watt       	C       coulomb
        V       volt         	(Omega) ohm     	S       siemens
        F       farad        	Wb  	weber      	H       henry
        T       tesla        	lm   	lumen       	lx      lux
        Bq      becquerel	Gy   	gray
Use star (*) for multiplication. Use caret (^) to mark powers. Use positive powers and precede negative ones by a slash (/).

The use of nonstandard names, like sec for second, will inhibit the use of later (to be written) unit handling. It is unlikely that Pa/torr will be recognized as unit-less, it will be hard enough to see that V*A is W.

Restrain the use of multipliers. If you do use them, then:

        f for femto, p for pico, n for nano, u for micro,
        m for milli, k for kilo, M for mega, G for giga, and
        T for tera are OK. (Micro is a Greek mu but u is readable.)

>>>>>>>>>WARNING, use the preferred SI units:

Avoid cm for centimeter, use mm or m. Avoid G or gauss, use T. (1T = 10000G, 1mT = 10G.) Use of eV for electron volt may be necessary. The abbreviation of millitorr is mtorr.

Conversions and simple arithmetic operations do not change the units. For example, BYTE, ABS, and UNARY_MINUS keep the units.

The argument of mathematical operations like SIN(x) should not have units because the number must be dimensionless. Degrees are not recognized--Use SIND(x).

The units of a result are defined for some binary operations: Addition and subtraction retain the units of a single WITH_UNITS or if the units match. Otherwise, the result is an error and is given the units "?".

Multiplication and division try to combine units. Problems exist with SQRT, POWER, and PRODUCT. PRODUCT may have an ill defined number of terms. (It depends on the MASK and the number of $ROPRANDs.)

TDI_direct_calls

    These routines directly enter TDISHR and have less error checking.
    They do return a long status and must be declared as INTEGER*4 in
    Fortran programs.

Additional information available:

TDI$CONVERT(%descr(IN),%descr(OUT)) TDI$CVT_DX_DX(%descr(IN),%ref(DTYPE),%descr(XD)) TDI$FAULT_CLEAR([%ref(NEW)]) TDI$FAULT_HANDLER(%ref(SIG_ARGS),%ref(MECH_ARGS)) TDI$GET_DATA(%ref(OMITS),%descr(IN),%descr(XD)) TDI$GET_FLOAT(%descr(IN),%ref(OUT)) TDI$GET_LONG(%descr(IN),%ref(OUT)) TDI$GET_NID(%descr(IN),%ref(OUT)) TDI$$INTRINSIC(%val(OPCODE),%val(NARG),%ref(LIST),%descr(OUT))

Restrictions

    Trouble words for tree node names without preceding . or : are the
names of standard operations: NOT BREAK CONTINUE ELSE ELSEWHERE. 

It is highly recommended that child or member nodes be marked.

Partial implementation:

No IO nor DECODE/ENCODE/STRING. Statements not written: ON_ERROR WHERE. Elementals: BITS NEAREST IS_IN. F90: CSHIFT EOSHIFT PROJECT RANDOM_SEED RESHAPE TRANSFER UNPACK F90 system: DATE_AND_TIME SYSTEM_CLOCK. Cross-element: CONVOLVE DERIVATIVE FFT INTEGRAL MEDIAN RC_DROOP INTERSECT SMOOTH. Matrix: INVERSE MATMUL SOLVE TRANSPOSE. Interpolation: INTERPOL MAT_ROT MAT_ROT_INT REBIN. No SUBSCRIPTS for variable store. Axes are not propagated for most transforms. No text to numerics, no Abs("123"). Numbers compiled OK. Subscript should immediately follow name. Watch NOT[sub]. [non-VMS] generates VECTOR not APD. APD is evaluated by VECTOR requiring DATA of objects. No units for POWER SQRT and some transforms. Quirk: -128b is illegal because it is negative of "bad" 128b, etc.

APD: Array of Pointers to Descriptors

About TDISHR

Software version: 9-Oct-1991. Help version: 9-Oct-1991.

The information in these texts is subject to change without notice and should not be construed as a commitment for development by the MDSplus development team.

The software described in these texts is furnished under a license and may be used or copied only under the terms of such license.

The Tree Data Interface shared library is mostly written by

        Kenneth A. Klare
        Group P-24, MS E526 (retired, contract)
        Los Alamos National Laboratory 
	kklare@mac.com

All rights reserved, 1989, 1990, 1991.