Frank Delaglio, Ph.D.

19804 Maycrest Way
Germantown MD 20876 USA

301 806-0867
delaglio@nmrscience.com



NMRPipe Processing Functions
MACRO: Slice-Processing Macro.

Flag Argument Default Description
 -macro mFile M-Language MACRO File.
 -var vList Variable Name/Value Pairs.
 -str sList String Name/Text Pairs.
 -all Use all slice codes.

MAC is a macro interpreter which executes the contents of the given macro file once for each 1D vector in the data stream. It is used to create custom processing functions and data shuffling schemes. The macro language, which is called M, is based on a subset of the C programming language, augmented by a collection of vector processing functions. In addition to use as a processing function of nmrPipe, the macro language R". also be used interactively via the stand-alone program M.

When a macro is invoked via the nmrPipe MAC function, the arrays rdata[] and idata[] will contain the real and imaginary parts of the current 1D vector. After the macro is executed, the contents of arrays rdata[] and idata[] will be written to the output stream automatically by nmrPipe.

The macro language allows data to be manipulated directly on a point-by-point basis, or by use of vector functions. For example, this 6-line macro would swap the reals and imaginaries on a point-by-point basis:

        for( i = 0; i < size; i++ )
           {
            temp     = rdata[i];
            rdata[i] = idata[i];
            idata[i] = temp;
           }
whereas this one-line macro would perform the same task more quickly using a built-in vector function:
        (void) vvSwap( rdata, idata, size );
The macro language includes special pre-defined variables, overall data and the current data vector. Other variables are created automatically when used, such as variables "i" and "temp" in the example above.

Once a macro is entered into a text file, it can be used to process data in the same way as other nmrPipe processing functions. For example, if either macro above is entered into the text file "swap.M", a scheme like the following could be used to exchange real and imaginary data before a Fourier transform:

        nmrPipe -in test.fid            \
        | nmrPipe -fn MAC -macro swap.M \
        | nmrPipe -fn FT                \
          -out test.ft1 -verb -ov
As the examples above imply, the macro language has many similarities to the C programming language. Some of these include:
  • Variable names are case-sensitive.
  • Statements are terminated by the ';' semicolon character.
  • Array subscripts are enclosed by '[' and ']' square brackets.
  • Statement lists are enclosed by '{' and '}' curly braces.
  • Multi-line comments are enclosed by /* and */ character pairs.
More details are given below. In the outlines that follow var is scalar variable or a subscripted array variable, and expr is a mathematical expression.

VARIABLES

In the current implementation, the macro language supports three types of variables:

  1. Scalar variables, as double-precision floats.
  2. One-dimensional arrays, as single-precision floats.
  3. Character arrays.

Array index values start at zero, as in C.

Array variables of a specific length can be created using a "float" statement, such as:

        float gReal[size*4], gImag[size*4];
        char  outName[256];
Scalar variables are created automatically when used. The value of an uninitialized variable is undefined.

READING AND WRITING DATA

Some macro applications may require the option of reading or 1D vector at a time. In these cases, the automatic read/write performed by nmrPipe can be suppressed by use of the arguments -noRd and -noWr. In these cases, the macro will be responsible for performing its own reading and writing, via functions such as dReadB() and dWrite() described below.

HEADER VALUES

The pre-defined array fdata[512] contains the file header information from the current data. The functions getParm() and setParm() can be used to get or set values in the header. For example, some macro applications may alter the size of the output data. In these cases it will be necessary to adjust the output file header accordingly before processing to indicate the new size.

When the -all flag is used, the macro will be invoked twice before any processing is required, to provide an opportunity to perform initialization such as updating the header if needed. If the -all flag is used, the macro will also be invoked once after all processing is finished. The action to perform at any given invocation will be indicated by variable "sliceCode" (see below). If the -all flag is not used, the macro will only be called to process data, never to perform initialization or exit procedures.

PREDEFINED VARIABLES

rdata[size]
Real part of current 1D vector.

idata[size]
Imaginary part of current 1D vector, if any.

fdata[512]
Header array from current data.

xSize
Size of current X-Axis, complex points.

ySize
Size of current Y-Axis, total points for hypercomplex data, complex points otherwise.

zSize
Size of current Z-Axis, total points.

aSize
Size of current A-Axis, total points.

size
Same as "xSize"

specnum
Same as "ySize"

quadState
If this value is 1, the current dimension is being read as real-only data, and therefore the idata[size] array has no imaginary contents.

If this value is 2, the current dimension is being treated as complex, and the array idata[size] contains the imaginary data.

sliceCode
1D Vector number or code number (see below). A value greater than zero indicates that a 1D vector should be processed. A value less than zero indicates that an initialization or shutdown step should be performed.

sliceCount
Total 1D slices to process.

yLoc
Location of current 1D slice in Y-Axis.

zLoc
Location of current 1D slice in Z-Axis.

aLoc
Location of current 1D slice in A-Axis.

inUnit
File ID for current 1D input data.

outUnit
File ID for current output data.

SPECIAL CONSTANTS

BUFLEN
Default array length (1024).

wordLen
Number of bytes per word (4).

PI
The constant pi.

E
The constant e.

NULL_DIM
Used to define dimCode for getParm/setParm below (=0).

CUR_XDIM
Used to define dimCode for getParm/setParm below (=1).

CUR_YDIM
Used to define dimCode for getParm/setParm below (=2).

CUR_ZDIM
Used to define dimCode for getParm/setParm below (=3).

CUR_ADIM
Used to define dimCode for getParm/setParm below (=4).

NDSIZE
Code for SIZE parameter in header, as taken from "fdatap.h"; used as a parmCode for getParm/setParm below. Other predefined parameter codes might be added in future implementations; in the mean time, parameter codes can be defined "manually" in a macro using values listing in "fdatap.h" or in the fdatap manual page.

VALUES FOR SLICECODE

The following codes will only be used when the -all option is specified:

CODE_ARGS
When sliceCode == CODE_ARGS, the macro is being invoked to extract any command line arguments required. At this stage, the data arrays (rdata[size] and idata[size) and the header array (fdata[512]) cannot be accessed.

CODE_INIT
When sliceCode == CODE_INIT, the macro is being invoked to perform any initialization required for processing. At this time, the header should be updated by the macro if needed.

CODE_DONE
When sliceCode == CODE_DONE, the processing is finished. The macro should perform any exit procedures (final summary, etc.) needed. At this stage, the data arrays (rdata[size] and idata[size) cannot be accessed.

ASSIGNMENT OPERATORS

The MAC language supports these C-style assignmemnt operators:

        var   = expr;   /* Assignment                 */
        var  += expr;   /* Increment var by expr.     */
        var  -= expr;   /* Decrement var by expr.     */
        var  *= expr;   /* Multiple var by expr.      */
        var  /= expr;   /* Divide var by expr.        */
MATH OPERATORS

Note that unlike C, this implementation defines an exponentiation operator '^':


        var = expr + expr;  /* Addition.         */
        var = expr - expr;  /* Subtraction.      */
        var = expr * expr;  /* Multiplication.   */
        var = expr / expr;  /* Division.         */
        var = expr % expr;  /* Modulus.          */
        var = expr ^ expr;  /* Exponentiation.   */

        var = -expr;        /* Negative.         */

        ++var;              /* Increment var, return new value.      */
        var++;              /* Increment var, return original value. */
        --var;              /* Decrement var, return new value.      */
        var--;              /* Decrement var, return original value. */

LOGICAL OPERATORS In the current implementation, both sides of binary logical operators are always evaluated, unlike C, where only the left-side argument may be evaluated.

        expr >  expr            /* Greater than
        expr >= expr            /* Greater than or equal to
        expr <  expr            /* Less than
        expr <= expr            /* Less than or equal to
        expr == expr            /* Equal to
        expr != expr            /* Not equal to

        expr && expr             /* Logical AND
        expr || expr             /* Logical OR
        !expr                    /* Logical NOT

SPECIAL ITEMS

(void)
Ignore (don't print) function return value. If this prefix is not used before a function call, the function's return value will be printed.

exit( expr );
Exit the macro with the given status.

print printList;
Print the given list of data; printList is a list of comma-separated variables or string constants.

float arrayList;
Define and allocate the given arrays; arrayList is a list of comma-separated arrays with subscripts defining their sizes.

near( x1, x2, d );
Returns 1 if the absolute difference between x1 and x2 is less than the absolute value of d.

angleNear( x1, x2, d );
Returns 1 if the absolute difference between angles x1 and x2 is less than the absolute value of d. The angles are expressed in degrees.

LOOP STATEMENTS
Loop statements in the macro language must have their body enclosed in '{' and '}' curly braces. Only two types of loop. for and while loops, are availble:

The general form of the loops is the same as in C, but with the requirement that statement list in the loop body is always enclosed in curly braces:

        while( condition )
           {
            statementList;
           }

        for( initExpr; condition; incrExpr )
           {
            statementList;
           }

CONDITIONAL STATEMENTS

Conditional statements in the macro language differ from the usual C syntax in two ways:

  1. The statement bodies in the if statement must be enclosed by '{' and '}' curly braces.
  2. The if statement must be terminated by a ';' character.
        if (condition)
           {
            statementList;
           };

        if (condition)
           {
            statementList;
           }
        else
           {
            statementList;
           };

        if (condition1)
           {
            statementList;
           }
        else if (condition2)
           {
            statementList;
           }
        else
           {
            statementList;
           };

SCALAR FUNCTIONS

The MAC language provides several "scalar" math functions, which in many cases invoke the C functions of the same name. Angular functions use values in radians:

        sin()      Sine
        cos()      Cosine
        tan()      Tangent

        acos()     Inverse Cosine
        atan()     Inverse Tangent
        log()      Log Base-e
        log10()    Log Base-10
        exp()      Exponential
        erf()      Error function
        sqrt()     Square root
        integer()  Truncate to integer
        abs()      Absolute value
        randX()    Uniform random number
        gRandX()   Gaussian random number
        rseed()    Sets random number seed
        readV()    Read a variable
        nthArg()   Extract the Nth string from the command-line.
        debug()    Set debug mode

        getByteSwap()  Return current data current byte swap status.
        setByteSwap()  Set current byte swap status.
        getAutoSwap()  Return current auto byte-swap status.
        setAutoSwap()  Set current auto byte-swap status.
SELECTED VECTOR AND FUNCTION CALLS
printf( string );
Print the given string, as with the C version of printf().

printf( formatString, argList );
Print the given data, as with the C version of printf(); Note Well: in the current implementation, all variables are treated by this printf as C type "float", so fomat statements must be specified accordingly. fprintf( fileID, string ); Print the given string to a file, as with the C version of fprintf(). The fileID should be a value returned by dOpen().

fprintf( fileID, formatString, argList );
Print the given data, as with the C version of fprintf(); Note Well: in the current implementation, all variables are treated by this printf as C type "float", so fomat statements must be specified accordingly. The fileID should be a value returned by dOpen(). sprintf( charArray, string ); Print the given string into the given character array, as with the C version of sprintf(). The character array should be created using the "char" statement.

sprintf( charArray, formatString, argList );
Print the given data, as with the C version of sprintf(); Note Well: in the current implementation, all variables are treated by this printf as C type "float", so fomat statements must be specified accordingly. The character array should be created using the "char" statement.

strcpy( charArray, string );
Copy the string to the given character array, as with be created using the "char" statement.

strcat( charArray, string );
Catenate the string to the given character array, as with the C version of strcat(). The character array should be created using the "char" statement.

strcmp( string1, string2 );
Compare the given strings, as with the C version of strcmp(). The value returned is either negative, zero, or positive depending on whether string1 is lexically less than, equal to, or greater than string2.

strcasecmp( string1, string2 );
Compare the given strings, in case-insensitive mode, as with the C version of strcasecmp(). The value returned is either negative, zero, or positive depending on whether string1 is lexically less than, equal to, or greater than string2.

strexpr( string, regexpr );
Return 1 if the given string matches the given regular expression "regexpr". The usual rules of regular expression matching apply.

strcpy( charArray, string );
Copy the string to the given character array, as with the C version of strcpy(). The character array should be created using the "char" statement.

argTest( string );
True if string was found in argv[] command line list.

argVal( string );
Returns the value following string in argv[] command line list.

getParm( fdata, parmCode, dimCode );
Gets a parameter from the given file header array fdata according to its parameter code and dimension code. Values of parmCode are listed in the file fdatap.h; values of dimCode are listed above.

setParm( fdata, parmCode, value, dimCode );
Sets a parameter in the header array fdata according to its parameter code and dimension code. Values of parmCode are listed in the file fdatap.h; values of dimCode are listed above.

pnt2spec( fdata, dimCode, pntVal, unitString );
Returns a location in spectral units corresponding to varies from 1 to N, where N is the number of points in the given dimension (dimCode). The spectral units (unitString) are specified as "ppm", "hz", "pts", or "%".

spec2pnt( fdata, dimCode, specString );
Returns a location in points corresponding to the given spectral location. The spectral location is specified as a string (specString) which contains a position with a spectral units label, such as "7.4ppm".

dOpen( fileName, modeString );
Opens the give file, and returns a file ID for reading or writing, using the open() UNIX system call. If mode is "r", the file will be opened read-only. If mode is "w", the file will be created if needed, truncated to zero length, and opened for writing. If mode is "rw", the file will be opened for both reading and writing. Alternatively, the mode string can contain combinations of the following characters to use as flags for the open() UNIX system call:

             Character     UNIX open() Flag

                r             O_RDONLY
                w             O_WRONLY
                d             O_NDELAY
                y             O_NOCTTY
                s             O_SYNC
                a             O_APPEND
                c             O_CREAT
                t             O_TRUNC
                e             O_EXCL

dClose( fileID );
Closes the given file.

dSeek( fileID, byteLoc );
Positions the given file; this cannot be used for pipeline data.

vvCopy( destArray, srcArray, length );
Copy contents of srcArray to destArray.

vvCopyOff( destArray, srcArray, length, destOffset, srcOffset );
Copy srcArray[srcOffset...] to destArray[destOffset...]

dReadB( fileID, array, byteCount );
Read given byte count from the given file.

dWrite( fileID, array, byteCount );
Write given byte count from the given file.

dReadB( fileID, array, byteCount );
Read given byte count from the given file (blocking version, which waits until all data have been read). Use this function to read data from a pipeline.

dReadHdr( fileID, array, byteCount );

dWriteB( fileID, array, byteCount );
Write given byte count from the given file (blocking version, which waits until all data have been written).

vvAdd( array1, array2, length );
array1 = array1 + array2

vvSub( array1, array2, length );
array1 = array1 - array2

vvMult( array1, array2, length );
array1 = array1 * array2

vvDiv( array1, array2, length );
array1 = array1 / array2

vvSwap( array1, array2, length );
Swap contents of array1 and array2

vsAdd( array, length, val );
array = array + val

vsMult( array, length, val );
array = array * val

vsSet( array, length, val );
array = val

lShift( array, length, lsVal );
Left-shift array by lsVal points.

rShift( array, length, rsVal );
Right-shift array by lsVal points.

vShow( array, length );
Print contents of array.

vNeg( array, length );
Negate contents of array.

reverse( array, length );

phase( rdata, idata, length, p0, p1 );
Apply a phase correction.

fft( rdata, idata, length );
Apply a forward Fourier transform.

ift( rdata, idata, length );
Apply an inverse Fourier transform.

vSim1D( rdata, idata, tSize, fSize, x0, xfw, hi );
vSim1D( rdata, idata, tSize, fSize, x0, xfw, hi, p0, p1 );
Add a simulated 1D time-domain data to the given real/imaginary array. Arguments tSize and fSize are the time-domain size and anticipated frequency-domain size in points. Argument x0 is the position of the signal in the corresponding frequency-domain, in points. Argument xfw is the full-width in points in the corresponding frequency-domain. Argument hi is the time-domain amplitude, and optional arguments p0 and p1 are the desired phase for the signal in degrees.

COMMAND-LINE OPTIONS

-macro macroFile
Specifies the macro file to execute, relative to the current directory. This is a required argument.

-var vList
Specifies a space-separated list of variable/value pairs, which allows variables to be initialized at the command line before the macro is executed.

-str sList
Specifies a space-separated list of variable/string pairs, which allows character arrays to be created and initialized at the command line before the macro is executed.

-all
(nmrPipe only) If this flag is used, the macro will be invoked to perform initialization and exist steps, as well as processing steps. If the -all is not used, the macro will only be invoked for processing steps. The action that the macro is expected to perform is indicated by the variable "sliceCode", explained above.

-quit
(M stand-alone interpreter only). If this flag is included, the stand-alone program M will exit after all macro files on the command line have been executed. If the flag is not included, the program will enter an interactive mode after all macro files have been executed.

EXAMPLES
Various examples can be found the the nmrtxt directory of the NMRPipe installation ($NMRTXT/*.M).

This example shows a custom window function which expects parameters settings from the command line (in this case, the variables called LB and GB) , and exracts the sweep width from the current data in order to interpret the requested window function parameters. This function will be called repeatedly, once for every 1D vector in the data.

The macro uses the following pre-defined variables:

   fdata[]    Parameter Header from the Current Spectrum
   rdata[]    Array of real values for the currect vector.
   idata[]    Array of imaginary vectors for the current vector.

   size       Number of points in the current vector.

   CUR_XDIM   A pre-defined constant for referring to the X-Axis. 
   PI         The pre-defined constant pi.
The contents of the macro can also be found in the file $NMRTXT/gmb.M:
    /* Bruker's GM function; requires LB and GB from command-line: */
    /* | nmrPipe -fn MAC -macro gmb.M -var LB 2 GB 8 \             */

    NDSW = 1003;

    sw   = getParm( fdata, NDSW, CUR_XDIM );
    aq   = size/sw;

    a    = PI*LB;
    b    = -a/(2.0*GB*aq);

    (void) printf( "sw: %f\n", sw );

    for( i = 0; i < size; i++ )
       {
        t = i/sw;
        g = exp( -a*t - b*t*t );
    
        rdata[i] *= g;
        idata[i] *= g;
       }
For other examples, see the NMRPipe macros in the $NMRTXT directory:
        ranceY.M   Rance-Kay mode 2D gradient shuffling.
        ranceZ.M   Rance-Kay mode 3D gradient shuffling.
        shuf3D.M   Adjust non-standard 3D acquisition order.
        rrii.M     Adjust non-standard Chemagnetics data.
as well as the following stand-alone M macros:
        xz.M       Extract XZ 2D Plane from 3D/4D data.
        xa.M       Extract XA 2D Plane from 4D data.