summaryrefslogtreecommitdiffstats
path: root/man/man1/funcalc.1
diff options
context:
space:
mode:
Diffstat (limited to 'man/man1/funcalc.1')
-rw-r--r--man/man1/funcalc.1622
1 files changed, 622 insertions, 0 deletions
diff --git a/man/man1/funcalc.1 b/man/man1/funcalc.1
new file mode 100644
index 0000000..b864865
--- /dev/null
+++ b/man/man1/funcalc.1
@@ -0,0 +1,622 @@
+.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. | will give a
+.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to
+.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C'
+.\" expand to `' in nroff, nothing in troff, for use with C<>.
+.tr \(*W-|\(bv\*(Tr
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. nr % 0
+. rr F
+.\}
+.\"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "funcalc 1"
+.TH funcalc 1 "April 14, 2011" "version 1.4.5" "SAORD Documentation"
+.SH "NAME"
+funcalc \- Funtools calculator (for binary tables)
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBfuncalc\fR [\-n] [\-a argstr] [\-e expr] [\-f file] [\-l link] [\-p prog] <iname> [oname [columns]]
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+.Vb 7
+\& \-a argstr # user arguments to pass to the compiled program
+\& \-e expr # funcalc expression
+\& \-f file # file containing funcalc expression
+\& \-l libs # libs to add to link command
+\& \-n # output generated code instead of compiling and executing
+\& \-p prog # generate named program, no execution
+\& \-u # die if any variable is undeclared (don't auto-declare)
+.Ve
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBfuncalc\fR is a calculator program that allows arbitrary
+expressions to be constructed, compiled, and executed on columns in a
+Funtools table (\s-1FITS\s0 binary table or raw event file). It works by
+integrating user-supplied expression(s) into a template C program,
+then compiling and executing the program. \fBfuncalc\fR expressions
+are C statements, although some important simplifications (such
+as automatic declaration of variables) are supported.
+.PP
+\&\fBfuncalc\fR expressions can be specified in three ways: on the
+command line using the \fB\-e [expression]\fR switch, in a file using
+the \fB\-f [file]\fR switch, or from stdin (if neither \fB\-e\fR nor
+\&\fB\-f\fR is specified). Of course a file containing \fBfuncalc\fR
+expressions can be read from stdin.
+.PP
+Each invocation of \fBfuncalc\fR requires an input Funtools table
+file to be specified as the first command line argument. The output
+Funtools table file is the second optional argument. It is needed only
+if an output \s-1FITS\s0 file is being created (i.e., in cases where the
+\&\fBfuncalc\fR expression only prints values, no output file is
+needed). If input and output file are both specified, a third optional
+argument can specify the list of columns to activate (using
+\&\fIFunColumnActivate()\fR). Note
+that \fBfuncalc\fR determines whether or not to generate code for
+writing an output file based on the presence or absence of an
+output file argument.
+.PP
+A \fBfuncalc\fR expression executes on each row of a table and
+consists of one or more C statements that operate on the columns of
+that row (possibly using temporary variables). Within an expression,
+reference is made to a column of the \fBcurrent\fR row using the C
+struct syntax \fBcur\-\fR[colname]>, e.g. cur\->x, cur\->pha, etc.
+Local scalar variables can be defined using C declarations at very the
+beginning of the expression, or else they can be defined automatically
+by \fBfuncalc\fR (to be of type double). Thus, for example, a swap of
+columns x and y in a table can be performed using either of the
+following equivalent \fBfuncalc\fR expressions:
+.PP
+.Vb 4
+\& double temp;
+\& temp = cur->x;
+\& cur->x = cur->y;
+\& cur->y = temp;
+.Ve
+.PP
+or:
+.PP
+.Vb 3
+\& temp = cur->x;
+\& cur->x = cur->y;
+\& cur->y = temp;
+.Ve
+.PP
+When this expression is executed using a command such as:
+.PP
+.Vb 1
+\& funcalc \-f swap.expr itest.ev otest.ev
+.Ve
+.PP
+the resulting file will have values of the x and y columns swapped.
+.PP
+By default, the data type of the variable for a column is the same as
+the data type of the column as stored in the file. This can be changed
+by appending \*(L":[dtype]\*(R" to the first reference to that column. In the
+example above, to force x and y to be output as doubles, specify the
+type 'D' explicitly:
+.PP
+.Vb 3
+\& temp = cur->x:D;
+\& cur->x = cur->y:D;
+\& cur->y = temp;
+.Ve
+.PP
+Data type specifiers follow standard \s-1FITS\s0 table syntax for defining
+columns using \s-1TFORM:\s0
+.IP "\(bu" 4
+A: \s-1ASCII\s0 characters
+.IP "\(bu" 4
+B: unsigned 8-bit char
+.IP "\(bu" 4
+I: signed 16-bit int
+.IP "\(bu" 4
+U: unsigned 16-bit int (not standard \s-1FITS\s0)
+.IP "\(bu" 4
+J: signed 32-bit int
+.IP "\(bu" 4
+V: unsigned 32-bit int (not standard \s-1FITS\s0)
+.IP "\(bu" 4
+E: 32-bit float
+.IP "\(bu" 4
+D: 64-bit float
+.IP "\(bu" 4
+X: bits (treated as an array of chars)
+.PP
+Note that only the first reference to a column should contain the
+explicit data type specifier.
+.PP
+Of course, it is important to handle the data type of the columns
+correctly. One of the most frequent cause of error in \fBfuncalc\fR
+programming is the implicit use of the wrong data type for a column in
+expression. For example, the calculation:
+.PP
+.Vb 1
+\& dx = (cur->x - cur->y)/(cur->x + cur->y);
+.Ve
+.PP
+usually needs to be performed using floating point arithmetic. In
+cases where the x and y columns are integers, this can be done by
+reading the columns as doubles using an explicit type specification:
+.PP
+.Vb 1
+\& dx = (cur->x:D - cur->y:D)/(cur->x + cur->y);
+.Ve
+.PP
+Alternatively, it can be done using C type-casting in the expression:
+.PP
+.Vb 1
+\& dx = ((double)cur->x - (double)cur->y)/((double)cur->x + (double)cur->y);
+.Ve
+.PP
+In addition to accessing columns in the current row, reference also
+can be made to the \fBprevious\fR row using \fBprev\-\fR[colname]>,
+and to the \fBnext\fR row using \fBnext\-\fR[colname]>. Note that if
+\&\fBprev\-\fR[colname]> is specified in the \fBfuncalc\fR
+expression, the very first row is not processed. If
+\&\fBnext\-\fR[colname]> is specified in the \fBfuncalc\fR
+expression, the very last row is not processed. In this way,
+\&\fBprev\fR and \fBnext\fR are guaranteed always to point to valid
+rows. For example, to print out the values of the current x column
+and the previous y column, use the C fprintf function in a
+\&\fBfuncalc\fR expression:
+.PP
+.Vb 1
+\& fprintf(stdout, "%d %d\en", cur->x, prev->y);
+.Ve
+.PP
+New columns can be specified using the same \fBcur\-\fR[colname]>
+syntax by appending the column type (and optional tlmin/tlmax/binsiz
+specifiers), separated by colons. For example, cur\->avg:D will define
+a new column of type double. Type specifiers are the same those
+used above to specify new data types for existing columns.
+.PP
+For example, to create and output a new column that is the average value of the
+x and y columns, a new \*(L"avg\*(R" column can be defined:
+.PP
+.Vb 1
+\& cur->avg:D = (cur->x + cur->y)/2.0
+.Ve
+.PP
+Note that the final ';' is not required for single-line expressions.
+.PP
+As with \s-1FITS\s0 \s-1TFORM\s0 data type specification, the column data type
+specifier can be preceded by a numeric count to define an array, e.g.,
+\&\*(L"10I\*(R" means a vector of 10 short ints, \*(L"2E\*(R" means two single precision
+floats, etc. A new column only needs to be defined once in a
+\&\fBfuncalc\fR expression, after which it can be used without
+re-specifying the type. This includes reference to elements of a
+column array:
+.PP
+.Vb 2
+\& cur->avg[0]:2D = (cur->x + cur->y)/2.0;
+\& cur->avg[1] = (cur->x - cur->y)/2.0;
+.Ve
+.PP
+The 'X' (bits) data type is treated as a char array of dimension
+(numeric_count/8), i.e., 16X is processed as a 2\-byte char array. Each
+8-bit array element is accessed separately:
+.PP
+.Vb 2
+\& cur->stat[0]:16X = 1;
+\& cur->stat[1] = 2;
+.Ve
+.PP
+Here, a 16-bit column is created with the \s-1MSB\s0 is set to 1 and the \s-1LSB\s0 set to 2.
+.PP
+By default, all processed rows are written to the specified output
+file. If you want to skip writing certain rows, simply execute the C
+\&\*(L"continue\*(R" statement at the end of the \fBfuncalc\fR expression,
+since the writing of the row is performed immediately after the
+expression is executed. For example, to skip writing rows whose
+average is the same as the current x value:
+.PP
+.Vb 4
+\& cur->avg[0]:2D = (cur->x + cur->y)/2.0;
+\& cur->avg[1] = (cur->x - cur->y)/2.0;
+\& if( cur->avg[0] == cur->x )
+\& continue;
+.Ve
+.PP
+If no output file argument is specified on the \fBfuncalc\fR command
+line, no output file is opened and no rows are written. This is useful
+in expressions that simply print output results instead of generating
+a new file:
+.PP
+.Vb 5
+\& fpv = (cur->av3:D-cur->av1:D)/(cur->av1+cur->av2:D+cur->av3);
+\& fbv = cur->av2/(cur->av1+cur->av2+cur->av3);
+\& fpu = ((double)cur->au3-cur->au1)/((double)cur->au1+cur->au2+cur->au3);
+\& fbu = cur->au2/(double)(cur->au1+cur->au2+cur->au3);
+\& fprintf(stdout, "%f\et%f\et%f\et%f\en", fpv, fbv, fpu, fbu);
+.Ve
+.PP
+In the above example, we use both explicit type specification
+(for \*(L"av\*(R" columns) and type casting (for \*(L"au\*(R" columns) to ensure that
+all operations are performed in double precision.
+.PP
+When an output file is specified, the selected input table is
+processed and output rows are copied to the output file. Note that
+the output file can be specified as \*(L"stdout\*(R" in order to write the
+output rows to the standard output. If the output file argument is
+passed, an optional third argument also can be passed to specify which
+columns to process.
+.PP
+In a \s-1FITS\s0 binary table, it sometimes is desirable to copy all of the
+other \s-1FITS\s0 extensions to the output file as well. This can be done by
+appending a '+' sign to the name of the extension in the input file
+name. See \fBfuntable\fR for a related example.
+.PP
+\&\fBfuncalc\fR works by integrating the user-specified expression
+into a template C program called tabcalc.c.
+The completed program then is compiled and executed. Variable
+declarations that begin the \fBfuncalc\fR expression are placed in
+the local declaration section of the template main program. All other
+lines are placed in the template main program's inner processing
+loop. Other details of program generation are handled
+automatically. For example, column specifiers are analyzed to build a
+C struct for processing rows, which is passed to
+\&\fIFunColumnSelect()\fR and used
+in \fIFunTableRowGet()\fR. If
+an unknown variable is used in the expression, resulting in a
+compilation error, the program build is retried after defining the
+unknown variable to be of type double.
+.PP
+Normally, \fBfuncalc\fR expression code is added to
+\&\fBfuncalc\fR row processing loop. It is possible to add code
+to other parts of the program by placing this code inside
+special directives of the form:
+.PP
+.Vb 3
+\& [directive name]
+\& ... code goes here ...
+\& end
+.Ve
+.PP
+The directives are:
+.IP "\(bu" 4
+\&\fBglobal\fR add code and declarations in global space, before the main routine.
+.IP "\(bu" 4
+\&\fBlocal\fR add declarations (and code) just after the local declarations in
+main
+.IP "\(bu" 4
+\&\fBbefore\fR add code just before entering the main row processing loop
+.IP "\(bu" 4
+\&\fBafter\fR add code just after exiting the main row processing loop
+.PP
+Thus, the following \fBfuncalc\fR expression will declare global
+variables and make subroutine calls just before and just after the
+main processing loop:
+.PP
+.Vb 16
+\& global
+\& double v1, v2;
+\& double init(void);
+\& double finish(double v);
+\& end
+\& before
+\& v1 = init();
+\& end
+\& ... process rows, with calculations using v1 ...
+\& after
+\& v2 = finish(v1);
+\& if( v2 < 0.0 ){
+\& fprintf(stderr, "processing failed %g -> %g\en", v1, v2);
+\& exit(1);
+\& }
+\& end
+.Ve
+.PP
+Routines such as \fIinit()\fR and \fIfinish()\fR above are passed to the generated
+program for linking using the \fB\-l [link directives ...]\fR
+switch. The string specified by this switch will be added to the link
+line used to build the program (before the funtools library). For
+example, assuming that \fIinit()\fR and \fIfinish()\fR are in the library
+libmysubs.a in the /opt/special/lib directory, use:
+.PP
+.Vb 1
+\& funcalc \-l "\-L/opt/special/lib \-lmysubs" ...
+.Ve
+.PP
+User arguments can be passed to a compiled funcalc program using a string
+argument to the \*(L"\-a\*(R" switch. The string should contain all of the
+user arguments. For example, to pass the integers 1 and 2, use:
+.PP
+.Vb 1
+\& funcalc \-a "1 2" ...
+.Ve
+.PP
+The arguments are stored in an internal array and are accessed as
+strings via the \s-1ARGV\s0(n) macro. For example, consider the following
+expression:
+.PP
+.Vb 3
+\& local
+\& int pmin, pmax;
+\& end
+.Ve
+.PP
+.Vb 4
+\& before
+\& pmin=atoi(ARGV(0));
+\& pmax=atoi(ARGV(1));
+\& end
+.Ve
+.PP
+.Vb 2
+\& if( (cur->pha >= pmin) && (cur->pha <= pmax) )
+\& fprintf(stderr, "%d %d %d\en", cur->x, cur->y, cur->pha);
+.Ve
+.PP
+This expression will print out x, y, and pha values for all rows in which
+the pha value is between the two user-input values:
+.PP
+.Vb 6
+\& funcalc \-a '1 12' \-f foo snr.ev'[cir 512 512 .1]'
+\& 512 512 6
+\& 512 512 8
+\& 512 512 5
+\& 512 512 5
+\& 512 512 8
+.Ve
+.PP
+.Vb 4
+\& funcalc \-a '5 6' \-f foo snr.ev'[cir 512 512 .1]'
+\& 512 512 6
+\& 512 512 5
+\& 512 512 5
+.Ve
+.PP
+Note that it is the user's responsibility to ensure that the correct
+number of arguments are passed. The \s-1ARGV\s0(n) macro returns a \s-1NULL\s0 if a
+requested argument is outside the limits of the actual number of args,
+usually resulting in a \s-1SEGV\s0 if processed blindly. To check the
+argument count, use the \s-1ARGC\s0 macro:
+.PP
+.Vb 4
+\& local
+\& long int seed=1;
+\& double limit=0.8;
+\& end
+.Ve
+.PP
+.Vb 5
+\& before
+\& if( ARGC >= 1 ) seed = atol(ARGV(0));
+\& if( ARGC >= 2 ) limit = atof(ARGV(1));
+\& srand48(seed);
+\& end
+.Ve
+.PP
+.Vb 1
+\& if ( drand48() > limit ) continue;
+.Ve
+.PP
+The macro \s-1WRITE_ROW\s0 expands to the \fIFunTableRowPut()\fR call that writes
+the current row. It can be used to write the row more than once. In
+addition, the macro \s-1NROW\s0 expands to the row number currently being
+processed. Use of these two macros is shown in the following example:
+.PP
+.Vb 7
+\& if( cur->pha:I == cur->pi:I ) continue;
+\& a = cur->pha;
+\& cur->pha = cur->pi;
+\& cur->pi = a;
+\& cur->AVG:E = (cur->pha+cur->pi)/2.0;
+\& cur->NR:I = NROW;
+\& if( NROW < 10 ) WRITE_ROW;
+.Ve
+.PP
+If the \fB\-p [prog]\fR switch is specified, the expression is not
+executed. Rather, the generated executable is saved with the specified
+program name for later use.
+.PP
+If the \fB\-n\fR switch is specified, the expression is not
+executed. Rather, the generated code is written to stdout. This is
+especially useful if you want to generate a skeleton file and add your
+own code, or if you need to check compilation errors. Note that the
+comment at the start of the output gives the compiler command needed
+to build the program on that platform. (The command can change from
+platform to platform because of the use of different libraries,
+compiler switches, etc.)
+.PP
+As mentioned previously, \fBfuncalc\fR will declare a scalar
+variable automatically (as a double) if that variable has been used
+but not declared. This facility is implemented using a sed script
+named funcalc.sed, which processes the
+compiler output to sense an undeclared variable error. This script
+has been seeded with the appropriate error information for gcc, and for
+cc on Solaris, DecAlpha, and \s-1SGI\s0 platforms. If you find that automatic
+declaration of scalars is not working on your platform, check this sed
+script; it might be necessary to add to or edit some of the error
+messages it senses.
+.PP
+In order to keep the lexical analysis of \fBfuncalc\fR expressions
+(reasonably) simple, we chose to accept some limitations on how
+accurately C comments, spaces, and new-lines are placed in the
+generated program. In particular, comments associated with local
+variables declared at the beginning of an expression (i.e., not in a
+\&\fBlocal...end\fR block) will usually end up in the inner loop, not
+with the local declarations:
+.PP
+.Vb 8
+\& /* this comment will end up in the wrong place (i.e, inner loop) */
+\& double a; /* also in wrong place */
+\& /* this will be in the the right place (inner loop) */
+\& if( cur->x:D == cur->y:D ) continue; /* also in right place */
+\& a = cur->x;
+\& cur->x = cur->y;
+\& cur->y = a;
+\& cur->avg:E = (cur->x+cur->y)/2.0;
+.Ve
+.PP
+Similarly, spaces and new-lines sometimes are omitted or added in a
+seemingly arbitrary manner. Of course, none of these stylistic
+blemishes affect the correctness of the generated code.
+.PP
+Because \fBfuncalc\fR must analyze the user expression using the data
+file(s) passed on the command line, the input file(s) must be opened
+and read twice: once during program generation and once during
+execution. As a result, it is not possible to use stdin for the
+input file: \fBfuncalc\fR cannot be used as a filter. We will
+consider removing this restriction at a later time.
+.PP
+Along with C comments, \fBfuncalc\fR expressions can have one-line
+internal comments that are not passed on to the generated C
+program. These internal comment start with the \fB#\fR character and
+continue up to the new\-line:
+.PP
+.Vb 7
+\& double a; # this is not passed to the generated C file
+\& # nor is this
+\& a = cur->x;
+\& cur->x = cur->y;
+\& cur->y = a;
+\& /* this comment is passed to the C file */
+\& cur->avg:E = (cur->x+cur->y)/2.0;
+.Ve
+.PP
+As previously mentioned, input columns normally are identified by
+their being used within the inner event loop. There are rare cases
+where you might want to read a column and process it outside the main
+loop. For example, qsort might use a column in its sort comparison
+routine that is not processed inside the inner loop (and therefore not
+implicitly specified as a column to be read). To ensure that such a
+column is read by the event loop, use the \fBexplicit\fR keyword.
+The arguments to this keyword specify columns that should be read into
+the input record structure even though they are not mentioned in the
+inner loop. For example:
+.PP
+.Vb 1
+\& explicit pi pha
+.Ve
+.PP
+will ensure that the pi and pha columns are read for each row,
+even if they are not processed in the inner event loop. The \fBexplicit\fR
+statement can be placed anywhere.
+.PP
+Finally, note that \fBfuncalc\fR currently works on expressions
+involving \s-1FITS\s0 binary tables and raw event files. We will consider
+adding support for image expressions at a later point, if there is
+demand for such support from the community.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+See funtools(7) for a list of Funtools help pages