NIRC Scripting Examples

Scripting in the new NIRC software is basically scripting in the UNIX shell. We cannot pretend to cover all of the ins and outs of this topic, but fortunately there are many excellent books on the subject.

The simplest user scripts will consist simply of lists of existing NIRC commands, just the way you would type them in if you were to enter them one by one on the command line. In this case all you need is the line #!/bin/csh -f at the start of your script.

A more complicated script will use UNIX commands to do more than automate what you would type at the comand line. It is advisable to use as an example an existing script as a starting point. You will likely be able to find a "facility" script that contains most of what you need. In that spirit we will dissect a small number of facility scripts, starting below with the dithering command bxy9. Remember that the best technique to use in UNIX is to try out questionable lines one-by-one. You can often tell how a variable substitution or a command substitution will work by trying it at first on a line by itself, possibly adding echo to the beginning to print the line without executing it. Also, complicated expressions can be built up piece by piece, checking the functionality as each new piece is added. On to our first dissection…

#!/bin/csh -f
#
# bxy9 x y moves the telescope in a 9-position box pattern, using
# offsets of x arcsec and y arcsec in detector coordinates.
#
# Pattern is:       2  8  4
#                   6  1  7
#                   3  9  5
#
if (${#argv} == 2) then  
  set x = $1
  set y = $2

# Set matrix of offset values.

  set xoff = ( 1  0 -2  0  2 -2  1  0  0)
  set yoff = (-1  2 -2  2 -1  0 -1  2 -1)
  foreach pos (1 2 3 4 5 6 7 8 9)
    goi
    mxy `echo "$xoff[$pos] * $x" | bc -lm` `echo "$yoff[$pos] * $y" | bc -lm`
    odiff >& /dev/null &
  end
else
  echo "Usage: bxy9 x y"
endif

The first line of the script, #!/bin/csh -f, tells the computer that we will be using the csh shell. This is the default for all of the NIRC facility scripts, although you could run any number of programs, shells, and languages. Note the -f after the shell name. This tells the shell not to run the .cshrc file, which will speed up the script.

The # signs are comment statements (unless followed by "!" as is the first line of the script). The if statement tests to see whether two arguments have been passed. #argv is a variable containing the number of arguments, the {} are delimiters used to make sure that the variable is clear to the script, and the $ is a variable substitution. Note that if bxy9 is not provided with two variables the else section of the if block is run, which merely prints out a reminder of the usage of the script.

The command set x = $1 sets the variable x to the script's first argument, represented by $1. Similarly y is set to the second argument. Next two one-dimensional arrays, xoff and yoff, are defined. These will be the offset positions.

The foreach statement sets the variable pos to each value enclosed in parantheses, in this case the integers 1 through 9. These values will be used as array indices later.

At each position (pos), an image is taken by calling goi. The telescope is then moved to the next position, which is offset from the previous position by the arrays xoff and yoff.

Note that the move command mxy takes two arguments, the offset in x and the offset in y. The scale factor for the offset in x is given by xoff, and the specific value of xoff is given by the position index, pos. Hence the scale factor if $xoff[$pos], where the $ again implies variable substitution, and the square brackets specifies the index of the array. This values is inside an echo statement, which also includes an asterisk, denoting multiplication, and the value of the argument for the pattern's step size in x, given by x. The asterisk is a special UNIX character, which generally is treated as a wildcard character. In this case we have avoided this treatment by putting it in double quotes, in which case it is treated simply as an asterisk.

This echo statement will send a string to the standard output (normally your terminal) consisting of the appropriate xoffset scale factor, and asterisk, and the box pattern x size. The pipe character, |, takes this string and diverts it from the terminal into the bc -lm command. The bc command performs math on the string; the -lm qualifier makes sure it performs floating point math! In bc the asterisk implies multiplication, so the result is the product of xoff and x. This again is normally sent to the standard output, but the back quotes again intercept it and place it on the mxy line. Back quotes mean "substitute the result of this command or command sequence."

The odiff command displays the difference of the last two files. Note the "&" at the end of the line; this spawns the odiff command as a separate process, letting the dither pattern get on with its data-taking while the difference is being calculated and displayed. This saves several seconds of time during the entire bxy9 script.

The next script we will dissect is one used to take linearity data. Rather than discuss each line, we only point out a number of interesting constructions.

#!/bin/csh -f
#
# linearity start end step, measures the linearity of the detector with
#           the loaded timing pattern and other parameters, by taking
#           exposures of length "start" to length "end," with steps
#           of "step" in between.  After each exposure, statistics on
#           a subsection of the image are printed.
#
if (${#argv} == 3) then
  set start = $1
  set end = $2
  set step = $3

# Because UNIX can't deal elegantly with floating point numbers, we will
# convert to microseconds here.

  set start = `echo $start \* 1000000 | bc -lm | sed "s/\..*//"`
  set end = `echo $end \* 1000000 | bc -lm | sed "s/\..*//"`
  set step = `echo $step \* 1000000 | bc -lm | sed "s/\..*//"`

  while ($start <= $end)
    echo tint = `echo $start / 1000000 | bc -lm`
    tint `echo $start / 1000000 | bc -lm`
    goi
    pstat `lastfile` 10 10 246 246
    set start = `expr $start + $step`
  end

else
  echo "Usage: linearity start end step"
endif

In the math in this script, note that the echo statements do not use double quotes. In this case the asterick must be escaped by prepending a "\". Following the echo and the bc parts of the math, sed is used to truncate the integration times to microseconds. In the sed quotation marks, the initial "s" means we will substitute what is between the first "/" marks with what is between the second and third. The first string is "\..*" which contains several special characters. The "\" escapes the first ".", meaning the period (or decimal point, in this context) character. The second "." is unescaped, hence stands for any character. The "*" at the end indicates any number of following characters, in other words the rest of the string. Hence sed is matching the decimal point and everything after it. It then replaces it with nothing, since there is nothing between the second and third "/" marks. Thus the floating point number is effectively truncated.

The pstat command has five arguments: the file number, for which the script uses the results of the "lastfile" command, a starting (x,y) pair, and an ending (x,y) pair. "lastfile" returns the (numeric) value of the last file written. With only one argument, pstat will calculate statistics over the whole image. The last four arguments restrict the statistics window to pixel (10,10) through pixel (246,246). This is because the NIRC detector often has unusual characeristics around its edge.

A third script shows the use of array math by invoking IDL. It is the foc8 script, which will step through 8 secondary focus positions, taking images at each focus, subtracting the appropriate region from a sky frame, and reassemble the central strips of the 8 images into a single frame, showing the strips stacked on top of each other. The observer is then meant to choose the strip with the best image quality, setting the secondary to the appropriate focus.

#!/bin/csh -f
#
# foc8 f df takes 8 frames, starting with secondary focus of f and
#           incrementing focus by df each time.  IDL is used for most
#           of the procedure.
#

setenv IDL_ARG1 $1
setenv IDL_ARG2 $2

idl <<'endofinput' |& egrep -v \
            "4.0|Copyright|All|Installation|Lic|Compiled|READFITS"
  foc8
'endofinput'
dlp

In order to pass arguments to IDL, we set UNIX environment variables: IDL_ARG1 and IDL_ARG2. (These are not IDL-specific variables by nature, but you want to assure that the names are unique enough that you don't accidentally write over other important environment variables.)

IDL is then invoked; the <<'endofinput' construct tells the script to pass everything from that point until the line containing only 'endofinput' is reached. This latter line must be left justified; do not indent it even if the IDL call is in the midst of other indented lines.

The |& egrep … part of the IDL call is a means of trapping some of the header and introductory text that IDL normally prints out when it is started. This is not strictly necessary, but it makes the script's output more concise and less confusing to the user.

Finally, the single command foc8, which refers to a file foc8.pro within the IDL path, is performed within IDL. We show that below…

;
; Focus loop for NIRC.
;
pro foc8
    fstart = float(GETENV('IDL_ARG1'))
    df = float(GETENV('IDL_ARG2'))
    focus = fstart
    ystart = 0
;
; take a sky frame
;
    com = 'tosky'
    spawn,com,/noshell
    goibuf = 'goibuf'
    spawn,goibuf,/noshell
    com = 'fromsky'
    spawn,com,/noshell
    sky = readfits( '/scratch/buf1.fits',header )
    focim = sky - sky
;
    for i=1,8 do begin
        com = 'modify -s dcs telfocus='+string(focus)+' secmove=1 '
        spawn,com
        spawn,goibuf,/noshell
        temp = readfits( '/scratch/buf1.fits' ) - sky
        focim(0:255,ystart:ystart+31) = temp(0:255,112:143)
        focus = focus + df
        ystart = ystart + 32
    endfor
    writefits,'/scratch/buf1.fits',focim,header
    com = 'p3path ; wd1'
    spawn,com
end

In this document we won't go into any IDL details, other than the interaction with the script parameters and with the UNIX shell. The former is demonstrated by the line containing GETENV('IDL_ARG1'), which gets the environment variable set in the foc8 script. Note that such variables may require type adjustment; they are brought into IDL as strings, but may be needed as numeric variables.

This IDL script shows two methods for interacting with the UNIX shell while inside IDL. The spawn command can be used to send UNIX commands; but make sure you use the /noshell qualifier if you need to run NIRC commands. Otherwise the PATH will be set to the login default, which doesn't include the NIRC commands. Another technique is shown towards the end, where the command sent to the UNIX shell includes a command, p3path, which sets the appropriate PATH; in this case you do not need the /noshell qualifier.

Some other comments on programming in the NIRC P3 software… There is always a possibility that you will use a variable name in one script which then calls a second script, which also contains a (different) variable with that name. This may be a particular problem in calling facility scripts, which you may never have seen, so you may not know what variables they contain. This is a potential source of bugs which you should keep in mind.

Also, UNIX caches executable commands. What this means is that if you have set your user directory using the "user xyz" command, and then create a new command in that directory and faithfully chmod it to have execute permission, you may type the command name and get a "command not found" error. This is because UNIX is using its "hash table," the cache or table of executables which it created previously, and which does not contain the new command. To reload the hash table, type rehash. Then your command should be accessible.

Significantly, you do not have to limit yourself to csh scripts with an occassional IDL script to do array math. You can write C or Fortran code, Perl scripts, tcl/tk scripts, or whatever UNIX tools you want.

Popular Links


Send questions or comments to: