User

Call user-written functions (VMS only):
Format:
SPECTRA> us$*$er [/fn] id1 [id2]

Description:
The user function takes id1 as input and produces the result id2. If id2 is missing, id1 is replaced by the result.
/f$n$
One of the five user functions are selected:
f0 gra_user_function(...) (default)
f1 gra_user_function_1(...)
f2 gra_user_function_2(...)
f3 gra_user_function_3(...)
f4 gra_user_function_4(...)
/max=np
This qualifier determines the number of points that can be stored in id1 or id2. Even if id2 is not specified, the value of max can be greater than the number of points of id1 (the replacement of id1 is not done `in place').
/u$i$=val, $i$ $\in$ [1,10]
The values of the qualifiers u1...u10 are passed to the function via the argument list in the parameter array (see the example below). They are interpreted as floating point numbers.

The directory gra_examples: contains an example of a user function: gra_user_example.com.

$ 
$ create test_function.for
c... 
c... n - number of points 
c... n_max - maximum number of points, qualifier MAX 
c... x - array of x-values 
c... y - array of y-values 
c... n_par - number of parameters 
c... par - parameter array (real$*$4) 
c... 
 function gra_user_function( n, n_max, x, y, n_par, par) 
 
 implicit none 
 integer *4 gra_user_function 
 integer *4 n, i, n_max, n_par
 real x(n_max), y(n_max), par(10)

 do i=1, n 
  y(i) = y(i) * par(1)
 end do
c... 0 indicates an error 
 gra_user_function = 1
 return 
 end 
$ 
$ fort test_function
$
$ link/shareable=test_function test_function, -
sys$input/opt 
cluster=dummy,,,gra_library:gra_tuser
gsmatch=always,0,0
$
$ def gra_user_function my_dir:test_function
$

The user has to replace my_dir by his directory name. If you want to use more than one user function, you have to write a second function called gra_user_function_1, link it with gra_tuser_1 instead of gra_tuser and define the logical gra_user_function_1 before you start SPECTRA.

When SPECTRA is started, the image activator resolves the shared image references via logical names. There are logical names for dummy user functions in the LNM$SYSTEM_TABLE. The user avoids the call of the dummy functions by defining his own logicals for the functions. They are stored in the LNM$PROCESS_TABLE which has higher precedence than the system table.

If the user function returns 0, no queue element is created nor replaced.

Since the user function is linked as a shared image, care has to be taken, if common blocks are included. One of the default attributes of a FORTRAN common block is SHR. It has to be changed, like it is done in the following example:

$ 
$ link/shareable=test_function test_function, -
sys$input/opt
psect_attr=private_common, noshr 
cluster=dummy,,,gra_library:gra_tuser
gsmatch=always,0,0
$
The user has to replace private_common by his common name. In case one of your common blocks is still classified as shr, when you start SPECTRA, the image activator will be pleased to let you know.

Don't worry, if you have problems to remember the names of your common blocks involved. Just link the user function with the additional qualifier /MAP and look at the program section synopsis part of the link map. The program sections which have the attributes shr and wrt cause the trouble.

If the user function calls a subroutine from SPECTRA, the link command has to modified:

$
$ link/shareable=test_function  -
sys$input/opt 
cluster=dum1,,,gra_library:gra_tuser
cluster=dum2,,,my_dir:test_function
cluster=dum3,,,gra_library:gra/lib
gsmatch=always,0,0
$
$ def gra_user_function my_dir:test_function
$
The order of the input file specifications is important.

When the link command is executed, the linker will complain about the doubly defined symbol gra_user_function. That is only natural, because SPECTRA has to provide the default user function. The user can ignore the warning message.