User Defined Functions (UDFs)

Overview of User Defined Functions
The user defined function table
Format of the function data transfer file
Format of the function result file
Example: Linear Regression Function

Users may write their own GrADS functions in the computer language of their choice, and have them available from the GrADS expression facility (via the display command). Some possible user defined functions might be:

You may write a function that can be invoked via the GrADs expression facility. This function may be written in any computer language, and may perform any desired I/O, calculations, etc. Please read the following documentation carefully to understand the restrictions to this capability.

Overview of User Defined Functions

The steps that GrADS uses to invoke a user defined function are:

  1. When GrADS is first started, it reads a file that describes the user defined functions. This file is called the 'user defined function table'.

  2. When a user function is invoked via the display command expression, GrADS parses the arguments to the functions, obtains the results of any expressions, and writes the resultant data to a 'function data transfer file'.

    Please note that in a user-defined function adding the double quote ("") around a char argument passes the string directly without the usual conversion to lower case and removal of blanks, e.g.,

    d grhilo(slp,F8.2,"This is the Label",0.25)

    Here F8.2 is passed as f8.2, but the second character string would not be converted to thisisthelabel.

  3. A user written program is then invoked. This program may read the function data transfer file, do any desired processing, then write the result into a function result file.

  4. GrADS will read the function result file and generate the internal objects necessary for this result to participate in the remainder of the expression evaluation.

The user defined function table

The user defined function table (UDFT) is a simple text file that contains information about each user defined function. There are five records for each defined function, and the file may contains descriptions for any number of functions. The 5 records are:

The user function definition table itself is pointed to by the environment variable GAUDFT. If this variable is not set, the function table will not be read. An example of setting this variable is:

setenv GAUDFT /usr/local/grads/udft

User defined functions have precedence over GrADS intrinsic functions, thus a user defined function can be set up to replace a GrADS function. Be sure you do not do this inadvertently by choosing a function name already in use by GrADS.

Format of the function data transfer file

The function data transfer file contains a header record plus one or more records representing each argument to the function. The user function routine will know what data types to expect (since they will be specified in the UDFT), and can read the file in a predictable way.

Header record: The header record always contains 20 floating point numbers. The record will always be the same size. Values defined in this record are:

Argument records: The argument records are written out in the order that the arguments are presented. The contents of the argument records depends on the data type of the argument: value, character string, or expression. Each of these data types will result in a different argument record being written out:

Format of the function result file

The function result file returns the result of the user defined function to GrADS. It is the responsibility of the function program to write this file in the proper format. A file written out in an improper format may cause GrADS to crash, or to produce incorrect results.

The result of a function is always a grid. Thus, the format of the function result file is as follows:

Header record: The header record should always contain 20 floating point numbers. The record will always be the same size. Values defined in this record are:

Grid records: The grid records should be written in the same order and format as the expr argument record in the data transfer file, with one important exception: the 3rd and 4th records containing the world coordinate values for each grid element in the i and j dimensions are written out to the function result file only if the scaling is non-linear. Thus the transfer file and the result file are not symmetric: GrADS writes a transfer file with record #3 and #4 always included, but it does NOT like to see record #3 and #4 in the result file if the dimensions are linear.

The linear/non-linear scaling of the grid dimensions is determined by examining the grid header contents -- values 6 and 7 contain the idim and jdim linear flags. Note that the time dimension is always linear.

Example: Linear Regression Function

This is a simple example of what a user defined function might look like in FORTRAN. This is a simple linear regression function, which only handles a 1-D grid and takes one argument, and expression.

First, the user defined function table (UDFT):

The source code for the FORTRAN program linreg is:

      real vals(20),ovals(20) 
      real x(10000),y(10000) 
      open (8,file='/mnt/grads/linreg.out',form='unformatted') 
      open (10,file='/mnt/grads/',form='unformatted') 
      read (8)
      read (8) vals 
      idim = vals(2) 
      jdim = vals(3) 
c  If this is not a 1-D grid, write error message and exit 
      if (idim.eq.-1 .or. then 
        write (6,*) 'Error: Invalid dimension environment'
        vals(1) = 1 
        write (10) vals 
c  If the grid is too big, write error message and exit 
      isiz = vals(4) 
      if ( then 
        write (6,*) 'Error from linreg: Grid too big' 
        vals(1) = 1 
        write (10) vals 
c  Read the data 
      read (8) (y(i),i=1,isiz) 
c  Read non-linear scaling if necessary 
      ilin = vals(6) 
      if (ilin.eq.0) then 
        read (8) (x(i),i=1,isiz) 
        do 100 i=1,isiz
          x(i) = i  
100     continue
c  Do linear regression 
      call fit (x,y,isiz,a,b) 
c  Fill in data values 
      do 110 i=1,isiz 
        y(i) = a+x(i)*b  
110   continue 
c  Write out return info.  
c  The header and the non-linear scaling 
c  info will be the same as what GrADs gave us. 
      ovals(1) = 0.0 
      write (10) ovals 
      write (10) vals 
      write (10) (y(i),i=1,isiz) 
      if (ilin.eq.0) write(10) (x(i),i=1,isiz) 
c A is the intercept 
c B is the slope 
      SX = 0. 
      SY = 0. 
      ST2 = 0.
      B = 0. 
      DO 12 I = 1, NDATA 
        SX = SX + X(I) 
        SY = SY + Y(I)  
      SS = FLOAT(NDATA) 
      SXOSS = SX/SS
      DO 14 I = 1, NDATA 
        T = X(I) - SXOSS 
        ST2 = ST2 + T * T 
        B = B + T * Y(I)  
      B = B/ST2 
      A = (SY - SX * B)/SS