It is possible in the Gifa program to write command files (macros). The macro is then invoked by the command :
Gifa> @file_name
or simply
Gifa> file_name
In UNIX the macro name is the file name, sometime names with a .g extension are chosen (used to be .gif before the v4 version, but has been changed to separate from the popular graphic file format .gif). Any characters (but the blank) can be used in macro name, so ../test/my_macro or /usr/local/gifa/macro/startup.g are valid names.
A macro consists of a series of regular Gifa commands used as in the interactive mode. Up to 9 recursive calls may be nested (i.e. you can call a macro from within a macro, down to 9 nested levels). The macro execution can always be stopped with the ^C command.
Note that
Gifa> @file_name
When calling a macro, the file first searched in the local working deirectory, and then is searched in a series of directories called the GifaPath. The default search order in the Gifapath is : the macro sub-directory of the home directory of the user ($HOME/macro in UNIX) and finally the standard directory : /usr/local/gifa/macro in UNIX. However the Gifapath can be modified at will (shortened or extended) with the SETPATH command. The current GifaPath can be examined with the $GIFAPATH context.
This is reminiscent with the notion of path in UNIX. This permits to build a library of macros, available for every Gifa user, as well as a set of commands personal to each user and to each project. The local directory is always searched first, so it is useless to add "." in the GifaPath.
When the Gifa program is first entered, it tries to execute the macro file called : startup.g, the file is searched in the GifaPath as any regular macro. Thus you can easily set-up you own environment. For instance your startup.g file (in your home directory, or in your working directory) may look like :
...any personal set-up
disp1d 1
/usr/local/gifa/macro/startup.g ; to be sure to have general set-up
You will find a comprehensive library of such macros in the /usr/local/gifa/macro sub-directory of the distribution kit.
The following commands are available for efficient command programming:
REFMACRO (0 or 1)
depending on the value of this context, display will be refreshed at the end of each macro line (REFMACRO 1) as for regular processing; or only at the end of the macro execution (REFMACRO 0). Default value is 0; a value of 1 is useful only for interactive macros, or for debugging.
SETVAL i {j { k } } val
will set the value of the ith point in the current buffer to val. The number of parameters for determining the point to be set depends on the value of DIM.
Similarly SETPEAK and SETPEAK2 permit to change the coordinate of a peak table entry.
There are several control structures in the Gifa language. They are all pretty classical, and should not make you any problems.
FOR var_name = initial TO final { STEP step}
.. some Gifa code
ENDFOR
This construction permits to write loops. The variable called var_name, will be created local to the macro if it does not yet exist, set to the value initial, and incremented by 1 for each loop. The increment can be different from 1 (but always numeric) with the optional field STEP step. step can even be negative, in which case the variable will be decremented. In any case, the test performed to determine whether the loop is finished or not is (var_name > final) if step is positive or (var_name < final) if step is negative.
FOREACH var_name IN array_name
.. some Gifa code
ENDFOR
Equivalent to FOR .. ENDFOR, but here var_name will take successively all the value possible for an index in the array array_name. Thus $array_name[$var_name] will take all the value of the array. array_name has to be, either a user associative array, or a dbm bound array. FOREACH does not work for context arrays (such as $ZOOM[] ).
WHILE some_value_to_be_evaluated
.. some Gifa code
ENDWHILE
The Gifa code will executed as long as some_value_to_be_evaluated is true (is non zero). The value to be evaluated can be a variable or a complex evaluated expression into parentheses.
The IF command has two distinctive syntaxes : a one-line IF without possible nesting nor else; and a complete IF .. THEN construct with ELSIF and ELSE possibilities.
The multi-line IF is as follow :
IF test THEN
..commands on several lines
{ ELSIF test2 THEN
..commands } (eventually many exclusive tests )
{ ELSE (default case)
..commands }
ENDIF
The different commands will executed conditionally on the value of the tests. Any non-zero value is considered as true. If may be nested, with no limit on the number of nesting.
The one-line IF is as follow :
IF logical_value ...remaining of the line ...
All the commands on the remaining of the command line are executed only if logical_value holds true (is non-zero).
examples :
IF ($X =< 0) GOTO SKIP
print 'Hello' IF ($ITYPE_1D == 1) set x = ($x+1)
IF (!eof(input)) print 'Still reading the file' \
set line = (%+1) \
IF ($line<$linemax) goto continue
tests to be used are described in the "evaluated expression" paragraph.
GOTO label
will redirect the execution of the macro to the symbol =label appearing somewhere else in the file.
Example
=loop
...any kind of processing...
goto loop
GOTO should not be used to jump into FOR or WHILE loops, nor into IF .. THEN structures, Unpredictable execution will occur.
All these commands may freely nested. However, except for GOTO and the one-line IF, these commands (FOR, FOREACH, ENDFOR, WHILE, ENDWHILE, =label) should appear alone on one line, with no code preceding nor following the command (or the label), but eventually followed by a comment.
These two commands are meant for accessing (dbm) arrays storing coordinate information such as peaks for instance. The common structure of such arrays will be that the coordinates have to be stored first in the array.
Then the FIND command, given an array name, the number of coordinates to search for, and a target point, will return the index of the closest entry in the array. Returned values are in the contexts $FND_PK which give the index of the found entry, and in $FND_PK_DST which gives the distance to target.
Let's give two examples of arrays with coordinates set in the beginning of each entry :
SET chem[1] = "1.1 spin_name1"
SET chem[2] = "2.5 spin_name2"
etc..
SET peak[1] = "1.1 1.1 peak_name 1"
SET peak[2] = "1.1 2.5 peak_name 2"
SET peak[3] = "2.5 3.6 peak_name 2"
etc..
FIND chem 1 1.3
then $FND_PK is 1 and $FND_PK_DST is 0.2
FIND peak 2 1.3 2.2
then $FND_PK is 2 and $FND_PK_DST is 0.36 (cartesian distance)
With the same kind of array, it is possible to restrict the scanning performed with the FOREACH command to a given zone :
FOREACH var_name IN array_name WITHIN dim (range values)
.. some Gifa code
ENDFOR
var_name will only scan the index in array_name, that fall inside the range given as argument to WITHIN.
These two command have been designed for the assignment modules, and you will find many examples of their use in it.
These 2 commands permits to build a bar showing the progress of the current command of the form :
In Progress : 0%....25%....50%....75%....100%
with a dot every 1/2Oth of the process
INITINPROGRESS tells Gifa how many iterations are to go, INPROGRESS actually does the display. INPROGRESS can be called at any rate, there is no need to do arithmetic to call INPROGRESS.
It is to note that, for a clean result, no terminal output should be performed during a INITINPROGRESS INPROGESS pair
Example :
set max = 1000
initinprogress $max
for i = 1 to $max
... do something
inprogress $i
endfor
We have seen above that the SETPATH permits to modify the path used for searching macro files. There is also a SETPROMPT command, which permits to modify the prompt which is given to the user in the text window. Together with the macro and graphic capabilities, this permits to build easyly some applications, which does not even have to related with NMR. Some examples of this can be found in the contrib directory of the ftp server.
During macro execution, it is possible to get input from the user in several ways :
* if a command misses a parameter, the user will be prompt for it, even if
the macro is called deep in a nested loop. The user will be prompted with the
current value. e.g.
print 'Enter new size' chsize
(actually the message is not really needed, since the command CHSIZE will issue one)
If the macro is called from the graphic interface (with BUTTONBOX), either directly or indirectly called, a dialogue box will be used to prompt the user for the value, the message from the command (here chsize) will be in the dialogue box.
* by the same token, it is possible to assign the input into a variable :
set b = 10 print 'Enter new value' set b =
The user here will be prompted with the value 10 as default for b.
The command MESSAGE permits to put the message in the dialogue box if the macro is called from a menu button, and on the terminal if called from the prompt. Thus this is a better construct :
set b = 10 message 'Enter new value' set b =
* It is possible to get mouse coordinates with the MONOPOINT
commands and the $POINTX[] and $POINTY[] variables. The ALERT command permits
to build alert boxes, and BUTTONBOX and FORMBOX permit to build more
sophisticate graphic interfaces.
Parameters can be sent to macros when called by following the call with the parameters to pass; within the macro file, these parameters will be obtain with the pseudo variable $_. each use of $_ "consume" one parameter on the call line. If no parameter is available on the calling line, the $_ pseudo variable will prompt the user directly. The variable $arg permits to test the presence of a value obtainable with $_.
For instance, if the file test_arg is as follow :
; to test argument passing
print $_
set b = $_ print (2*$b)
set c = $_
the following call
test_arg hello 3
will produce the following output
hello
6
and will prompt for the value to be applied to c. Thus $_ can be used to both the command line or the user, much in the same way as regular Gifa commands do. It is even possible to have an optional message, depending whether there is a parameter available or not, with the variable $arg :
if (!$arg) print 'Enter new value'
set b = $_
The MESSAGE command, has similar built-in mechanism, the string is sent to the user only if no parameters are available on the calling line. It is better to use the MESSAGE command, since the message will then go to a dialogue box if the macro is called from the graphic interface.
message 'Enter new value'
set b = $_
The PRINT command permits to output to the user a string. If you want to show more than a single line you can always use sh :sh 'more text_file' ; UNIX
As an example the 2D Fourier Transform could be written
; do the 2D FT in macro (specially silly),
if ($dim != 2) error 'Only in 2D' ; do some checking
if ($itype_2d != 3) error 'Only on hypercomplex data-sets'
if ($si1_2d*$si2_2d) > 1024k error 'too big for 4 times z-f'
print 'Processing in F2'
chsize % (2*power2(%)) ; zero-filling in F2
initinprogress $si1_2d ; set up in progress bar
for i = 1 to $si1_2d ; loop over rows
row $i dim 1 ; get ith row in 1D buffer
ft ; process it
dim 2 put row $i ; put it back
inprogress $i ; display in progress bar
endfor
print 'Processing in F1'
chsize (2*power2(%)) % ; zero-filling in F1
initinprogress $si2_2d
for i = 1 to $si2_2d ; loop over cols
col $i dim 1 ; get ith col in 1D buffer
ft ; process it
dim 2 put col $i ; put it back
inprogress $i
endfor
exit
but don't try that one for real processing, it would be really slow!
A more useful example :
; do contour plotting in colours, 1 colour per level
; using scale, level and loga
if ($level>8) error 'Too many levels, should be <= 8'
set loc_lev = $level level 1
set loc_sca = $scale
for i = 1 to $level
pen $i % plot %
if ($loga!=1) scale (%/$loga)
if ($loga==1) scale ( (%*$i) / ($i+1))
endfor
pen 1 % page %
scale $loc_sca level $loc_lev
exit
Another example showing how you can build a special apodisation function in the window buffer and then use it :
; this macro builds a cosine roll-off apodisation function
; and applies it to the current data set
; works in 1D !
; in 2D, build the WINDOW only once and loop APPLY WINDOW on the 2D
put data ; keep data aside
chsize (%/8) one sqsin 0
chsize (%*8) addbase 1 mult -1 reverse ; build apodisation
put window
get data apply window ; apply apodisation
Here is a small (silly) interactive example :
; to compute the square root of a given number
sh 'more intro.txt' ; some greeting message'
set i = 1 ;i should be set here for the following test to work!
while ($i <> 0)
print 'Enter your number (0 to end)'
set i = 0 ; pre-set the value and ask for it
set i =
if ($i>0) then
print ('Square root of';$i;'is';sqrt($i))
elsif ($i<0) then
print 'No real square root !'
endif
endwhile
exit
For speed consideration it is always better, when working on a large macro, to make a small file for a very repetitive piece of work and call it. The looping as well as the parsing may get slow on a large file (typical on VMS systems). It is also slightly faster to call a macro with the @file syntax.