aboutsummaryrefslogtreecommitdiff
path: root/sys/qpoe/QPOE.hlp
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /sys/qpoe/QPOE.hlp
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'sys/qpoe/QPOE.hlp')
-rw-r--r--sys/qpoe/QPOE.hlp1201
1 files changed, 1201 insertions, 0 deletions
diff --git a/sys/qpoe/QPOE.hlp b/sys/qpoe/QPOE.hlp
new file mode 100644
index 00000000..cbb0ee5b
--- /dev/null
+++ b/sys/qpoe/QPOE.hlp
@@ -0,0 +1,1201 @@
+.help QPOE Jun90 "Quick POE Design"
+.ce
+\fBQuick-POE (Position Ordered Event File) Interface Design\fR
+.ce
+Doug Tody
+.ce
+July, 1988
+
+.NH
+Introduction
+
+ The POE (Position Ordered Event file) facility is an interface and file
+structure used to store and access the event (photon) lists generated
+by event counting detectors. Each event is described by a unique position,
+time, energy, and possibly other parameters (e.g., polarization, position in
+other coordinate systems, or instrument related parameters). In the case of
+an imaging event counting detector, the "image" generated consists of this list
+of discrete events, rather than the regular matrix produced by a conventional
+sampling detector. Both types of detectors are fundamental to astronomy.
+
+The POE interface is a stand alone interface built upon the standard VOS
+interfaces DFIO (in a future release), PLIO, SYMTAB, FIO, and other lower
+level interfaces. The POE interface may be called directly by applications
+code to create and access POE datafiles, for event file specific processing.
+In addition, an IMIO image kernel is provided so that POE files may be
+accessed as (read only) images, allowing existing IRAF image tasks to be
+used to access POE files. The main function of the POE image kernel is to
+filter and sample the event list in real time, returning a conventional
+sampled grid (image matrix) to the high level applications code.
+The parameters controlling the filtering and sampling operations may be
+specified by the user when the image (POE file) is accessed, making runtime
+filtering of events possible in connection with any general image processing
+task.
+
+.NH 2
+Important Concepts
+
+ The primary object dealt with by this interface is the \fIevent file\fR,
+consisting of a free format \fIfile header\fR and the main \fIevent list\fR.
+The event list is a collection of \fIevent structures\fR, e.g., photons
+hitting an imaging detector during the period of observation recorded by the
+event file. Each event is characterized by a standard set of attributes such
+as the position of the event in detector, sky, or other coordinates, the time
+at which the event was recorded, the energy of the event, and so on, plus
+optionally additional instrument dependent attributes (in general the event
+structure cannot be fixed, and the nomenclature may vary depending upon the
+science being performed).
+
+The events may appear in the event list in any order, but since most access
+to image data tends to be spatial in nature, access will be most efficient if
+the event list is position ordered. This is the convention chosen by QPOE
+and hence the name \fIpoe\fRfile, or \fIp\fRosition \fIo\fRrdered \fIe\fRvent
+file. An important alternative ordering is time ordering, which preserves
+the order in which the events were originally recorded, but which requires
+a complete scan of the event list to accumulate the events in a region of
+interest during analysis. There are cases where time ordering might be
+preferable to position ordering, e.g., for time series analysis of a long
+observation.
+
+Of fundamental importance to the analysis of data from event counting
+detectors is the concept of \fIfiltering\fR. It is in the nature of event
+counting detectors that they are often used to observe very faint objects
+for very long periods of integration. The total amount of data (number of
+events) may be limited, so one wants to preserve all events, but since the
+quality of the data may vary both with time and with position, it is common
+to want to reject a portion of the data. Conversely, the analysis being
+performed may require one to examine only a portion of the data, e.g., only
+events with a certain range of energies or arrival times, occurring within a
+given region of the image. Often the analysis will be repeated many times
+wtih different filters.
+
+Hence, most analysis of event counting data typically involves both
+\fIrejection\fR and \fIregion of interest\fR filtering. Rejection filtering
+depends mostly upon the data itself, hence the rejection filter for an image
+is a part of the image and should be in effect by default whenever the image
+is accessed, although we would like to physically record all data and be able
+to change the rejection filter either temporarily or indefinitely if desired.
+Region of interest filtering, on the other hand, depends upon the scientific
+analysis being performed rather than upon the data, hence is highly variable
+and should be controlled by the user, independently of the data.
+
+.NH 2
+Interface Requirements
+
+ Given the description of the problem to be solved presented in the previous
+section, we can make the following observations regarding the POE interface:
+.ls 4 o
+A flexible binary file header supporting both scalar and variable length vector
+fields is essential. Examples of vector fields include the aspect and temporal
+records (actually arrays of records, or subtables), the processing history
+(probably stored as a single variable length text buffer), and the rejection
+and region of interest filters (PLIO external format byte sequences stored as
+opaque binary arrays).
+.le
+.ls o
+In the general case the details of the event structure depend upon the
+instrument for which data is being stored. The minimum requirement is that
+the event structure consist of a set of standard fields (x, y, time, energy)
+followed by a variable length, instrument dependent area (hence the size of
+the event structure, while fixed for a given datafile, should be allowed to
+vary depending upon the data). Ideally all fields should be named and
+accessible for filtering, the names chosen should be variables rather than
+constants, and the set of fields used to describe an event should be allowed
+to vary depending upon the data.
+.le
+.ls o
+Runtime access to the event list, including event-attribute and spatial
+filtering, should be as efficient as possible since this is likely to be
+by far the most time consuming part of the interface. Header access
+efficiency is much less important and is not expected to be a problem.
+.le
+.ls o
+For most efficient access the event list should be stored sorted upon some
+primary key, with an index maintained by the interface for that key,
+and used for efficient retrieval. The minimum requirement is that the primary
+or sort key be the Y coordinate (corresponding to image lines). Ideally it
+should be possible for the sort key to be any field of the event structure,
+or any combination of fields (e.g., Y+X, or T). Ideally the interface itself
+should be responsible for maintaining the event list in sort order; this is
+not a requirement since writing to event files is much less common than
+reading. Ideally it should be possible for the event list to be unordered,
+and it should be possible to transparently access the event list regardless
+of the ordering.
+.le
+.ls o
+Rejection filtering is typically required by the data, yet we wish to retain
+all the data and be able to override or replace the default rejection mask.
+The rejection filter is logically associated with the data and should be
+stored with the data. The minimum requirement is for the interface to be able
+to store all the data plus the rejection mask, and be able to return only
+the "good" data at runtime. The interface is not required to perform rejection
+filtering at runtime, although it would be desirable to be able to do so if
+the efficiency penalty were not too great. Alternatively, the event list
+could be prefiltered, and the "good" and "bad" events stored in different
+places in the datafile, requiring that the entire file be rebuilt to change
+the rejection filter.
+.le
+.ls o
+Region of interest filtering is a common operation for event data, and can be
+difficult to implement efficiently, hence should be supported directly by the
+interface. At a minimum it should be possible to filter events by defining a
+range of acceptable or unacceptable values for each of some subset of the event
+attributes (e.g., energy or time). Ideally it should also be possible to
+specify an arbitrarily long list of ranges of acceptable values. Ideally
+spatial filtering should be supported as well; this is required for rejection
+filtering, but is at most a desirable option for spatial region of interest
+filtering (there is nothing about spatial filtering which is unique to event
+data, hence it might be more appropriate to implement it at a higher level,
+but on the other hand it might be more efficient to implement it at the event
+i/o level since the event list is position ordered and can be very large).
+.le
+.ls o
+It should be possible to specify the various filtering options both
+transparently to applications programs (via a symbolic expression passed
+into the interface by the user as part of the file specification),
+or procedurally, via \fIset\fR-parameter calls issued by the client program.
+.le
+
+The above issues need to be adequately addressed in order to have a useful
+interface. In the longer term there are many other considerations, e.g.,
+it is also desirable for the data format to be machine independent, and the
+data format should be flexible, to accommodate the inevitable evolutionary
+revisions as well as to accommodate data from a variety of instruments or
+projects. The event files can be very large, hence efficiency is a major
+consideration for event i/o and filtering.
+
+.NH
+The QPOE Interface
+.NH 2
+Implementation Strategy
+
+ A two step operation is planned for implementing the POE interface within
+IRAF. The first step is the so called quick-POE interface. The objective of
+quick-POE is to provide the necessary functionality so that applications
+development can proceed immediately, without waiting for the general interface
+to be developed. Once quick-POE is in place development of the fully general
+POE interface can proceed at a more leisurely pace consistent with the plan to
+provide most of the functionality of the generalized POE interface with other
+standard IRAF facilities currently under development, most notably the datafile
+i/o interface (DFIO), a general purpose binary file record manager to be used
+in the new images structures project and elsewhere in IRAF.
+
+The main facilities provided by POE are for access to general header fields,
+access to the variable length aspect and temporal records, event list i/o,
+and event filtering. The POE header is a type of record, and the aspect and
+temporal "records" are arrays of records (tables), as is the event list itself.
+Any record access problem involving large records commonly involves the
+related problems of indexing and selection based on a user supplied predicate
+(boolean expression or filter in our case).
+
+In the general case, we would like the POE interface to be able to support
+data from a variety of detectors or instruments, not only those used in high
+energy astrophysics but those used in optical and radio observatories as well,
+hence the details of the data structures must be allowed to vary without
+affecting the interface itself. Ideally the POE files should be maintained
+in a machine independent format, and the applications programs using POE
+should not be affected by changes to the data format, and indeed should be
+usable directly with any of several similar data formats, or with data formats
+that evolve over time.
+
+All these observations lead us to conclude that a general implementation of
+the POE interface has much in common with the general record access problem,
+hence the association of POE with DFIO. Quick-POE will provide much the same
+functionality at the applications level but will be less general, i.e., the
+binary record structures as seen by applications will be mapped directly onto
+external storage (the main contribution of DFIO is data independence and
+flexibility). This means that initially the applications will be tied to
+a specific format datafile, changes to applications structures will require
+reformatting the data, and the datafiles will probably be machine dependent.
+
+This approach would be unacceptable in the long run, as the need arises to
+support a variety of instruments, but is viable for initial applications
+development provided a DFIO based implementation eventually replaces the
+initial interface. There should be little difference in terms of functionality
+and efficiency between QPOE and POE; in fact QPOE may have the edge over POE
+in terms of efficiency, since it will be less general. It is likely that
+applications developed for QPOE will be usable with POE with few if any
+changes, e.g., by reimplementing QPOE as a layer on top of the more general
+POE interface. The main motivation for implementing a DFIO based POE will be
+to provide increased data independence, a machine independent binary data
+format, and the ability to support a variety of instruments with a single
+interface.
+
+Although some throw away code will have to be written to implement the QPOE
+interface, most of the complexity of the interface lies in the event filtering
+code, which should be reusable in the final interface. Low level, custom
+(non-DFIO) selection code is required for POE due to the unusual requirements
+for region and temporal filtering, and the potentially extremely high data
+volume (>10**6 event records). This implies that DFIO itself will have to be
+a layered interface, supporting low level access to the packed data records
+for applications with unusual efficiency requirements (it will be). Finally,
+it is already evident that the low level file manager required by QPOE has
+much in common with the access method code planned for DFIO, hence can serve
+as a prototype for the DFIO file manager.
+
+The remainder of this document will deal only with the details of the
+QPOE interface. The DFIO interface has already been specified,
+including a sketch of a data definition for a POE file. See \fIThe IRAF
+Datafile I/O Interface\fR, February 1988. The region filtering
+code in POE will make use of the Pixel List I/O (PLIO) interface, described
+in \fIThe IRAF Pixel List Package\fR, February 1988. The latter interface
+has already been implemented, as have all other interfaces (e.g., SYMTAB)
+required by QPOE.
+
+.NH 2
+Architecture
+
+ The architecture of IRAF as it pertains to the QPOE (and POE) interface
+is summarized in the figure below.
+
+.ks
+.nf
+ IMIO
+ IKI
+ IK-POE
+ POE
+ PLIO
+ [DFIO]
+ SYMTAB
+ FIO
+.fi
+.ke
+
+As indicated in the figure, QPOE depends most heavily on the VOS interfaces
+PLIO (pixel list i/o), used for spatial filtering, SYMTAB (the general symbol
+table package), used to manage the file header and aspect and temporal records,
+and FIO (file i/o), used to access the binary file in
+which the QPOE data is stored (low level, unbuffered asynchronous i/o is
+used by the QPOE file manager). The QPOE interface is accessed both directly
+by applications code, and by the IMIO interface via an image kernel, shown
+as IK-POE in the figure. IK-POE and QPOE comprise the code to be written to
+implement the QPOE interface.
+
+The QPOE interface consists of the POE file itself, a binary data structure
+[largely] private to the QPOE interface, and a set of procedures for creating,
+writing into, and reading from POE files. The procedures fall into several
+categories, i.e.,
+.ls 4
+.ls o
+General QPOE file management procedures. These include routines for creating,
+deleting, renaming, opening, and closing POE files, plus set/stat routines
+for setting and querying the file parameters and interface options.
+.le
+.ls o
+General header access procedures. These include a conventional set of keyword
+driven typed scalar get/put routines, plus get/put routines for accessing
+variable length typed and opaque binary arrays (e.g., history records and the
+aspect and temporal records).
+.le
+.ls o
+Event i/o procedures. These are routines for initially preparing and
+subsequently reading (sequentially with seek) the main event list, e.g.,
+the raw "get next photon" routine.
+.le
+.ls o
+The selection subpackage. Included are routines for opening and incrementally
+compiling a user supplied selection predicate (filter) input as a formatted
+text string, and for testing individual event records to see whether they
+satisfy the given expression.
+.le
+.le
+
+All binary data structures other than simple scalar variables, e.g., the
+aspect and temporal records and the event structure, are described in QPOE
+by compile time bound SPP binary data structure definitions, provided in a
+standard interface include file (\fI<qpset.h>\fR) referenced by both QPOE and
+selected applications. When the interface is layered upon DFIO these
+structures could continue to be used, since DFIO will have the ability to
+define runtime mappings of conventional application defined structures onto
+the physical data datafile (POE file) structures.
+
+.NH 2
+Interface Specification
+
+ The quick-POE interface (QPOE, package prefix `qp') is a set of procedures
+for accessing \fIpoefiles\fR, or position ordered event files. Each poefile
+consists of a \fBheader\fR of arbitrary size and content containing zero or
+more named scalar or variable length (opaque, typeless) fields, plus an
+\fBevent list\fR consisting of zero or more event structures.
+The event structure is fixed at compile time via a conventional SPP structure
+declaration in the include file \fB<qpset.h>\fR.
+
+.NH 3
+Interface Procedures
+
+ The QPOE procedures fall into three main categories, the primary user
+interface procedures (general datafile management, header access, and filtered
+event i/o), the low level or raw event i/o procedures, and the low level
+selection expression compile and evaluate procedures.
+
+.NH 4
+Header Access Procedures
+
+ The routines described in this section are used to create, open, or
+otherwise manipulate poefiles, to define new header parameters or query the
+existing parameter set, and to read and write the values of both scalar and
+vector parameters of various standard and poefile-specific datatypes.
+These operators are summarized in the figure below.
+
+The function of most of these procedures should be obvious.
+The \fIqp_access\fR, \fIqp_delete\fR, \fIqp_rename\fR, and \fIqp_copy\fR
+operators perform the implied operation on the named poefile.
+The poefile may be rebuilt with \fIqp_rebuild\fR, recovering any unused
+space and rendering storage for the internal data structures (logically)
+contiguous in the process (a rebuild is just a copy/rename/delete).
+
+The \fIqp_open\fR procedure must be called to open or create a poefile,
+before it can be accessed. The NEW_FILE and NEW_COPY modes are supported
+for creating new files. If NEW_COPY mode is specified, a reference file
+may be specified (via the descriptor \fIo_qp\fR) from which the new file
+is to inherit the header but no data (no event list).
+The \fIqp_seti\fR and \fIqp_stati\fR procedures are used to set and stat
+any parameters affecting QPOE i/o, and \fIqp_sync\fR updates an opened
+poefile on disk.
+
+The \fIqp_get\fR and \fIqp_put\fR scalar functions behave as for the other
+VOS interfaces, e.g., they will abort if the named parameter does not exist,
+or if the implied datatype conversion is illegal. The \fIqp_add\fR
+procedures are equivalent to the \fIqp_put\fR procedures except that they
+will create the named parameter if it does not already exist (see also
+\fIqp_addf\fR, discussed below).
+
+.nf
+ yes|no = qp_access (poefile, mode)
+ qp_copy (poefile, newfile)
+ qp_rename (poefile, newfile)
+ qp_rebuild (poefile)
+ qp_delete (poefile)
+
+ qp = qp_open (poefile, mode, o_qp)
+ qp_seti (qp, param, ival)
+ ival = qp_stati (qp, param)
+ qp_sync (qp)
+ qp_close (qp)
+
+ val = qp_get[bcsilrdx] (qp, param)
+ qp_gstr (qp, param, outstr, maxch)
+ qp_put[bcsilrdx] (qp, param, val)
+ qp_pstr (qp, param, strval)
+ qp_add[bcsilrdx] (qp, param, defval, comment)
+ qp_astr (qp, param, strval, comment)
+
+ fd = qp_popen (qp, param, mode, type)
+ nelem = qp_read (qp, param, buf, nelem, first, dtype)
+ qp_write (qp, param, buf, nelem, first, dtype)
+
+ yes|no = qp_accessf (qp, param)
+ qp_deletef (qp, param)
+ qp_renamef (qp, param, newname)
+ qp_addf (qp, param, dtype, maxelem, comment, flags)
+ nelem = qp_queryf (qp, param, dtype, maxelem, comment, flags)
+
+ list = qp_ofnl[su] (qp, template)
+ nch|EOF = qp_gnfn (list, outstr, maxch)
+ qp_cfnl (list)
+.fi
+
+Array valued parameters may be randomly read with \fIqp_read\fR and
+written with \fIqp_write\fR; arrays may be any length, and will be
+automatically extended in a write. The only way to shorten an array
+parameter is to copy it and delete the old parameter. The typed read and
+write functions allow automatic type conversions, and external storage of
+the data in a machine independent form (should the interface choose to do so).
+In addition to the standard SPP types, QPOE supports the special types
+TY_EVENT, TY_ASPECT, and TY_TEMPORAL. Finally, the type TY_OPAQUE denotes
+an array of element size SZ_CHAR, which will be copied to and from external
+storage without the data being modified in any way (note that opaque data
+is machine independent only if the application encodes it that way).
+
+Alternatively, an array valued parameter may be opened as a random access
+\fIfile\fR with \fIqp_popen\fR, and then read or written with conventional
+FIO calls. The value of the \fItype\fR parameter must be TEXT_FILE or
+BINARY_FILE, as for a conventional file. If the type is TEXT_FILE then
+only text data may be stored in the file, and text data will be byte packed
+on disk. The BINARY_FILE type is equivalent to the QPOE type TY_OPAQUE.
+File i/o to a QPOE parameter is equivalent to file i/o to a conventional
+binary file in terms of both efficiency and semantics, i.e., the data is not
+modified in any way, and the "files" may be any size (the main semantic
+difference is that deleting the parameter does not immediately free the space).
+A parameter opened as a file with \fIqp_popen\fR is closed with the FIO
+\fIclose\fR routine.
+
+Although new parameters may be defined when first written to by calling one of
+the typed \fIqp_add\fR functions, the most general procedure for adding new
+parameters is \fIqp_addf\fR, which allows the datatype and vector length of
+the parameter to be explicitly specified, along with a comment describing the
+new parameter. The procedure \fIqp_accessf\fR tests if the named parameter
+exists, and \fIqp_deletef\fR and \fIqp_renamef\fR make it possible to delete
+and rename parameters, e.g., for implementing array copy procedures.
+The \fIqp_queryf\fR procedure returns the datatype, allocated vector length,
+current vector length, and comment field of the named parameter.
+
+The field name list procedures (\fIqp_ofnl[su]\fR etc.) are used to obtain
+the names of all header parameters matching the given template; a null or "*"
+template returns the names of all header parameters. This is the only way by
+which an application without apriori knowledge of the field names can determine
+what is in the header, e.g., to list or copy the header.
+
+.NH 4
+Filtered Event I/O Procedures
+
+ The \fBevent i/o\fR subpacke provides sequential i/o facilities for the
+main event list of the poefile. These procedures, known as the QPIO (QPOE
+event i/o) package, provide read or write (append) access to the event list,
+optionally filtered when reading to select events spatially or by event
+attribute.
+
+Under QPOE, an event list is stored as a variable length array (i.e., as a
+named header parameter) of type \fIevent\fR. The QPIO package takes this
+basic object and adds additional structure for more efficient i/o, e.g., events
+are blocked into large, fixed size \fIbuckets\fR of N events, the first two
+events of each bucket containing the minimum and maximum event values for that
+bucket. If the event list is sorted an \fIindex\fR may be maintained for the
+list; this index, plus the min/max event values maintained for a bucket, are
+used to optimize basic event i/o and filtering. During event i/o the raw
+event list may be filtered spatially or by event attribute. All this is
+transparent to the application, which merely opens the event list parameter
+and begins reading (or writing) blocks of events.
+
+Before i/o can take place the named event list parameter is opened with
+\fIqpio_open\fR. The selection filter to be used by QPIO may be specified
+via a selection expression passed in by the user at poefile open time (as
+part of the poefile name), at QPIO open time (as part of the parameter name),
+or in subsequent calls to \fIqp_addfilter\fR (each call incrementally modifies
+the current filter) or to \fIqp_setfilter\fR (each call replaces the affected
+portion of the current filter). A region mask may also be specified with
+\fIqp_setmask\fR; if no mask is specified, the default rejection mask is used
+(or more precisely, its inverse).
+
+.nf
+ qpio = qpio_open (qp, param, mode)
+ qpio_mkindex (qpio, key, nelem)
+ qpio_setrange (qpio, vs, ve, ndim)
+ qpio_[add|set]filter (qpio, selexpr)
+ nchars = qpio_getfilter (qpio, outstr, maxch)
+ qpio_setmask (qpio, pl)
+ pl = qpio_getmask (qpio)
+ nev|EOF = qpio_getevents (qpio, ev, maskval, maxevents)
+ qpio_putevents (qpio, ev, nevents)
+ qpio_readpix (qpio, obuf, vs, ve, dxim, xblock, yblock)
+ qpio_close (qpio)
+.fi
+
+Events are read sequentially with \fIqp_getevents\fR, which fills in the
+pointer array \fIev[maxevents]\fR with one or more pointers to event structs,
+returning the number of events read as the function value, or EOF when the
+event list is exhausted. Events are returned in the order in which they are
+stored in the main event list. If a region mask is used for spatial
+filtering, the mask value associated with the output events is returned in
+\fImaskval\fR. Filtering and subranges are supported only for reading;
+\fIqp_putevents\fR may only be used to append to the output poefile.
+At present, poefiles are not randomly updatable, as this would require
+runtime editing of the compressed event lists and it is not clear how useful
+such a feature would be.
+
+If less then the entire image is to be accessed then \fIqp_setrange\fR
+may be called to specify the region of the poe image from which events are
+to be read (the vector coordinates \fIvs\fR and \fIve\fR are specified
+relative to the predefined primary event coordinate system, i.e., the PO
+coordinates). Repeated calls to \fIqp_setrange\fR may be made to access
+multiple regions of the image, or to rewind the i/o pointer for a region.
+
+An alternative to event i/o is provided by \fIqp_readpix\fR, which samples
+the event list using the current filters and blocking factor,
+generating \fInpix\fR pixels beginning with the pixel at the image coordinates
+specified by the vector \fIv\fR. This is the routine used by the POE IMIO
+image kernel to read from a poefile. Only integer pixels are supported.
+On output, each pixel value is a count of the number of filtered events
+mapping into that pixel. A region mask may be used to filter the event list,
+but the ability to discriminate between different regions by the mask value
+is lost.
+
+A poefile may contain any number of event list parameters, although most
+files are expected to store only the main event list.
+As an alternative to QPIO, event-array parameters may be accessed directly
+via the normal header access parameters, e.g., \fIqp_read\fR, but i/o may be
+somewhat less efficient (due to the copyout), the bucket structure will be
+visible, and no filtering is possible. In short, the raw event list will
+be accessed as an array, returning the min/max events in each bucket along
+with the data events.
+
+In the current implementation, the event structure is a fixed, predefined
+binary structure, and all event i/o is expressed in terms of pointers to event
+structures. The event structure is defined in the include file
+\fB<qpset.h>\fR, discussed in the appendix.
+
+.NH 4
+Selection Subsystem Procedures
+
+ The \fBselection subsystem\fR is a facility used to perform runtime
+filtering of the event list, returning to the calling program only those
+events satisfying some user defined selection criteria. The selection
+subsystem is driven by a selection expression provided by the user as a
+formatted string, normally at image (poefile) open time. The selection
+expression syntax itself is independent of the procedural interface and is
+described separately in section 2.3.2. The selection procedures are
+summarized in the figure below.
+
+.nf
+ ex = qpex_open (qp, expr)
+ ok|err = qpex_modfilter (ex, exprlist)
+ nchars = qpex_getfilter (ex, outstr, maxch)
+ nev = qpex_evaluate (ex, i_ev, o_ev, nev)
+ qpex_close (ex)
+.fi
+
+A selection expression, input as the string \fIexpr\fR, is compiled with
+\fIqpex_open\fR, which returns a pointer to the runtime descriptor (filter)
+for the given compiled selection expression. If \fIexpr\fR is the null
+string the filter returned will pass all events.
+
+An active filter may be modified with \fIqpex_modfilter\fR, which combines
+the expression \fIexpr\fR into the current filter, allowing complex
+filters to be built up in several calls, or allowing an application to modify
+a base filter without knowledge of the base filter. The expression consists
+of a list of comma delimited "attribute = exprlist" terms. If the assignment
+is specified as "=" the term for the given attribute is replaced; if the
+assignment is "+=" the term for the given attribute is further qualified.
+A text representation for the current filter may be obtained at any time with
+\fIqpex_getfilter\fR. The boolean function \fIqpex_evaluate\fR is called to
+test whether a specific event meets the selection criteria, i.e., to test
+whether or not \fIexpr\fR is true for the given event.
+
+Selection is normally performed transparently to the application by the QPIO
+interface, which calls the routines described in this section to create and
+apply event-attribute filters.
+
+.NH 3
+Spatial and Event Attribute Filtering
+.NH 4
+Selection Syntax
+
+ Selection expressions are used to construct \fIfilters\fR to specify the
+rejection mask and region of interest filters before reading the event list
+via QPIO. Due to the complexity of event attribute selection, selection
+predicates are specified syntactically, i.e., as an expression input as a
+text string. These filters may be input by the user as part of the image
+or poefile specification (object name), transparently to applications code,
+or they may be constructed by the application via calls to the QPIO or
+selection routines. Complex or frequently referenced filters may be stored
+in text files and referenced by filename if desired. It does not matter
+whether a filter is input all at once, or compiled incrementally.
+
+An event attribute filter consists of a set of filters for each event
+attribute. By default, i.e., if no filter is specified, all attribute values
+are passed. If a filter is specified for an attribute, the filter specifies
+either a bitwise mask value, or a list of acceptable values or ranges of values
+for the attribute. An event is passed if and only if all event attribute
+filters pass the event. If a list of acceptable values are specified, the
+list may be any length, with little impact on filtering efficiency.
+
+The basic event attribute filter syntax consists of a list of attribute
+filters, e.g.:
+
+ attribute = values [, attribute = values ...]
+
+where \fIattribute\fR is the attribute name, e.g., a position attribute,
+time, energy, and so on, and \fIvalues\fR is a mask or list of values.
+Mask values are integers prefixed by `%', e.g.,
+
+ attribute = %1003B
+
+Note that the mask may be specified in decimal (the default), octal (`b' or
+`B' suffix), or hex (`x' or `X' suffix), in accord with the usual IRAF
+conventions. The meta-characters used in selection expressions have been
+selected to avoid or at least minimize the need to quote such expressions
+in CL commands.
+
+A specific value or list of values may be specified as a
+simple integer constant, or comma delimited list of constants, e.g.:
+
+.nf
+ attribute = 3
+or
+ attribute = 3, 5, 20X
+.fi
+
+Ranges are specified using the `:' notation, e.g.,
+
+ attribute = 3, 5, 8:11
+
+A `!' may be prepended to indicate the opposite, i.e., "everything but":
+
+.nf
+ attribute = !%14B
+or
+ attribute = 3, !1:10
+.fi
+
+Open ended ranges may be used to indicate that the range includes all values
+less than or equal to or greater than or equal to the given value, e.g.,
+
+ attribute = :100
+
+denotes all values less than or equal to 100.
+
+File inclusion or \fImacro expansion\fR is denoted by a C-like function call
+notation, e.g.,
+
+.nf
+ macro()
+or
+ macro(a,b)
+.fi
+
+Any arguments are expanded via string substitution when the text of the macro
+or include file is expanded. Include files should have the extension ".qpm".
+Macros are permitted only if the variable \fBqpinit\fR is defined in the user's
+environment, the string value consisting if the filename of the user's QPOE
+macro file. In a reference to a macro \fImacro\fR, QPOE will look first in
+the macro definitions file pointed to by \fIqpinit\fR for the named macro,
+then it will look for the file "\fImacro\fR.qpm" in the current directory.
+
+Parenthesis are optional and may be included to, for example, make attribute
+value lists more easily identifiable. If a line ends in a comma or backslash
+continuation is assumed; blank lines and comment lines are ignored.
+The syntax for attributes with floating point values is identical to that
+for integers except that mask values are not allowed.
+
+.NH 4
+Region Specification
+
+ QPOE does not itself contain any syntax-level support for specifying
+region masks, e.g., via a list of include and exclude circles and other
+shapes. The reason for this is that it is too difficult to come up with
+a sufficiently general scheme at the level of an interface like QPOE;
+there are too many ways to specify regions, hence in general such region
+specification must be done at the applications level. QPOE does however
+include very general and efficient support for region analysis provided the
+region mask is input already encoded into a PLIO binary mask. Since PLIO
+includes high level primitives for defining masks in terms of include and
+exclude circles, boxes, lines, polygons, etc., it is easy to extend QPOE at
+the applications level to include support for a region specification language
+tailored to the specific application.
+
+While QPOE cannot itself process a user defined region description to create
+new region masks, it is possible to \fIselect\fR from any number of region
+masks if these are prepared in advance using other systems facilities or
+applications programs. PLIO region masks may be stored in the QPOE header
+as named parameters of type opaque binary array, or they may be stored in
+external binary files. The region mask to be used may be specified by
+including an assignment of the form
+
+ mask=[\fIparam\fR|\fIfile\fR.pl]
+
+in the selection expression. Unless otherwise specified, this region mask
+will be combined with the default rejection mask for the poefile (the final
+mask will be the region mask \fIand\fR-ed with the \fInot\fR of the rejection
+mask).
+
+.NH 4
+Predefined Selection Keywords
+
+ While the syntax of a selection expression is an inherent part of the
+QPOE interface, the names of the event attributes used in selection
+expressions are logically part of the event structure, and ideally should
+be stored with the data and used by the interface only to determine the
+attribute datatypes and offsets into the event structure when the selection
+expression is compiled at runtime. We should not really be documenting the
+specifics of the POE external data structures here, but in QPOE these data
+structures are wired into the interface, so it is appropriate to do so.
+
+The following \fIstandard event attributes\fR are defined. Minimum match
+abbreviations are of course permitted. The keyword \fIpi\fR is an acceptable
+alias for \fIenergy\fR (\fIpi\fR and \fIpha\fR are examples of discipline
+dependent terminology which should be associated with the data and not the
+interface).
+
+.nf
+ X short range in X (PO coords)
+ Y short range in Y (PO coords)
+ TIME real time event was recorded
+ ENERGY,PI int energy of event
+ PHA int pulse height
+.fi
+
+The event attributes may also be referred to using the generic notation
+[\fIsir\fR]\fIN\fR, which refers to each attribute by its datatype and
+struct offset (byte units, zero indexed) rather than by name. For example,
+if the event attributes shown above are assumed to be shown in the order
+in which the fields are stored in the event struct, the \fItime\fR field
+could also be referred to as \fIR4\fR, and \fIpha\fR as \fII10\fR. This
+crude but effective technique may be used to reference any private
+(nonstandard) fields of the event struct in selection expressions.
+
+The following additional, non-event keywords are defined:
+
+.nf
+ BLOCK int \fIqp_readpix\fR blocking factor
+ MASK string region mask to be used
+ FILTER string region filter to be used
+ REJMASK string rejection mask to be used
+ REJFILTER string rejection filter to be used
+.fi
+
+The default values for these parameters are taken from datafile header
+parameters of the same name, if such are found. Masks are specified either
+by the name of a header parameter of type opaque binary array (containing
+an encoded PLIO mask), or by the name of a PLIO mask file, extension ".pl".
+Named filters are specified by the name of a header parameter of type char
+array, or by the name of a text file (extension ".qpf"), where in either
+case the named object contains the selection expression text.
+
+.NH 3
+Interface Set/Stat Parameters
+
+ The internal parameters for the QPOE interface, and all user accessible
+data structures, e.g., the event and other structures, are defined in the
+global system include file \fB<qpset.h>\fR. This file should be referred to
+for up to date documentation on these definitions and structures; the
+discussion which follows may not be kept up to date.
+
+The following interface parameters may be accessed via the \fIqp_seti\fR and
+\fIqp_stati\fR procedures:
+
+.nf
+ QP_XRESOLUTION resolution of an event x-coordinate
+ QP_YRESOLUTION resolution of an event y-coordinate
+ QP_LENEVENT length of an event structure
+ QP_LENINDEX resolution of the event list index
+ QP_BUCKETSIZE event list bucket size, nevents
+ QP_PAGESIZE datafile page size, bytes
+ QP_CACHESIZE number of buffers in data buffer cache
+ QP_MAXFILES max lfiles in datafile (fixed)
+ QP_NFILES query number of lfiles in datafile
+ QP_NPAGES query number of pages in datafile
+ QP_FREEPAGES query number of free pages in datafile
+.fi
+
+The parameters shown above may be set only at datafile creation time.
+The X and Y resolution parameters define the range of event x,y coordinates.
+The resolution of the event list index is set by QP_LENINDEX, and may be less
+than the full resolution of the event pixel Y-coordinate.
+The remaining parameters control how storage is physically allocated in the
+datafile and in any event lists.
+
+.NH 2
+Detailed Design
+.NH 3
+Event Attribute Filtering
+
+ The point of event-attribute filtering is to test an event to see if it
+satisfies a user defined event selection expression. A selection expression
+may be decomposed into a list of simple, independent expressions for the
+individual event attributes; the event satisfies the full expression only
+if the value of each event attribute satisfies the associated attribute
+expression. Currently, attribute expressions are limited to bitmasks, lists
+of acceptable values, or lists of ranges (inclusive) of acceptable values.
+
+ attr1=expr, attr2=expr, ...
+
+The highly constrained nature of event-attribute expressions makes expression
+evaluation straightforward and fast. Expression evaluation is implemented
+by logically negating each attribute expression and testing each in turn;
+expression evaluation ends either when an attribute test fails, in which case
+the event is rejected, or when the end of the attribute expression list is
+reached, in which case the event is passed.
+
+The obvious way to implement such an expression evaluator is with a simple
+interpreter. The expression is parsed and compiled to produce a simple
+interpreter program, using the instructions shown in the figure below.
+
+.ks
+.nf
+ \fIinstruction arguments\fR
+
+ MSK[sir] offset maskval bitwise mask test
+ EQL[sir] offset value equality test
+ LEQ[sir] offset value less than or equal
+ GEQ[sir] offset value greater than or equal
+ RNG[sir] offset lowval highval range test (inclusive)
+ LUT[sir] offset lut lookup table
+ NOT invert test
+ RET return, pass event
+.fi
+.ke
+
+An interpreter program consists of a series of these instructions. The
+\fIoffset\fR argument gives the offset of the event attribute (field) to
+be tested; the datatype of this field must match that of the instruction
+and of the data argument or arguments, if any. Only event attributes for
+which restricted values were specified are tested, hence the cost of the
+evaluator depends only upon the complexity of the expression to be evaluated.
+An interpreter of this type can be coded very efficiently as a switch-case
+statement (jump table) within an optimized DO-loop.
+
+Simple attribute value tests are most efficiently coded as several \fIMSK\fR,
+\fIEQL\fR, etc., instructions. The only case of any complexity is where the
+attribute has a long list of acceptable values or ranges of values. This is
+most efficiently coded using a lookup table, using the \fILUT\fR instruction
+shown in the figure. A lookup table test may be preceded by a range test to
+limit the size of the lookup table required. For an integer or short integer
+attribute, the lookup table will be a \fIboolean\fR table containing one entry
+for each possible value of the attribute in the range spanned by the table.
+
+Use of a lookup table for floating point attributes is more difficult since
+an enormous lookup table might be required to preserve the resolution of
+the floating point numbers used to define ranges. The solution is to employ
+an \fIinteger\fR (rather than boolean) lookup table of \fIreduced resolution\fR.
+The floating point value of the attribute to be tested is mapped into a bin of
+the lookup table. The integer value of the table entry has one of the
+following values:
+
+.ks
+.nf
+ 0 Reject all FP numbers mapping to this bin.
+ 1 Accept all FP numbers mapping to this bin.
+
+ N Some of the FP numbers mapping to this bin are
+ legal, and some are not. The value N is the
+ address of a segment of interpreter code to be
+ executed to test a FP value mapped to this bin.
+.fi
+.ke
+
+The performance of this algorithm for floating point table lookup depends
+upon the frequency with which 0 or 1 is encountered as the table value during
+lookup; if 0 or 1 is encountered most of the time, then a floating point LUT
+test is comparable in expense to an integer LUT test. But since we already
+have to map a floating point number into an integer space of reduced
+resolution, we can easily vary the resolution of the lookup table,
+increasing the resolution of the table until the desired level of efficiency
+is reached (the interpreter execution time for case N is pretty fast in any
+case, so this is not critical).
+
+In summary, the expense of event-attribute filtering is directly proportional
+to the number of attribute tests to be performed. An arbitrary number of
+values or ranges of values may be specified for an attribute with little if
+any affect on performance, even for floating point attributes (e.g., for
+time-tagged quality filtering).
+
+.NH 3
+Region Filtering
+
+ Region filtering is implemented in QPOE by the PLIO interface, which is
+documented elsewhere. PLIO permits regions of arbitrary complexity to be
+described and used for event filtering, with little overhead beyond that
+already present for i/o on a large event list with no region filtering.
+This assumes only that the event list is position ordered, and that the
+region mask is specified in the PO (position ordered) coordinate system.
+This makes it possible for QPIO to use the mask to reduce the number of
+events to be examined; event attribute filtering is performed only on those
+events read through the region mask (this is similar to masked image i/o,
+i.e., the MIO package).
+
+If the event structure supports multiple coordinate systems and the region
+mask refers to a non-PO coordinate system, then the only approach is to first
+perform event-attribute filtering on the non-positional event attributes,
+then for each event passing the event-attribute filter, fetch the mask value
+corresponding to the x,y coordinates of the event. This is still an efficient
+technique since only mask pixel lookup is required (no complicated region
+list traversal is involved), but it will be significantly less efficient than
+PO region filtering since we cannot take advantage of position ordering to
+reduce the number of events to be examined, and the overhead of accessing
+the region mask will be greater.
+
+.NH 3
+Datafile Layout and Access
+.NH 4
+File Structure
+
+ The QPOE file structure is private to the QPOE interface and is discussed
+here only for the purpose of detailing (and documenting) the design of the
+interface. The QPOE file is a random access, dynamically extendable, binary
+file. Under QPOE these files will be partially, but not completely, machine
+independent, hence file sharing by machines of different architectures will
+not be provided initially. This will be rectified when management of the
+datafile is later turned over to DFIO.
+
+To provide a reasonable degree of flexibility, QPOE contains many
+variable length data structures, e.g., there may be any number of header
+parameters, including array valued parameters of arbitrary size. New header
+parameters may be added at any time, and new data may be appended to array
+parameters at any time. This flexibility places certain demands upon the
+low level file manager used to maintain these data structures in the datafile.
+
+All access to the physical datafile is via a low level binary
+\fIfile manager\fR. The purpose of the file manager is to implement a
+restricted implementation of the binary file abstraction upon a single host
+level binary file. This provides the "lightweight" binary file mechanism we
+need for QPOE. Since the file manager is a low level facility, it is
+implemented using only the low level asynchronous i/o facilities provided
+by FIO to read and write file pages, once the file has been opened.
+
+The file manager provides routines for creating new datafiles, and for
+creating, deleting, etc., \fIlightweight files\fR (lfiles) within a datafile.
+Storage for lfiles is allocated in units of datafile \fIpages\fR. For each
+data page in the datafile there is an entry in the datafile \fIpage table\fR.
+The page table itself is stored as an lfile (\fIlfile zero\fR) in the data
+pages. Files at the file manager level are known only by their file number;
+association of these file numbers with file names is left up to the higher
+level code, and in the case of QPOE is done with the symbol table (which is
+also stored as an lfile).
+
+.ks
+.nf
+ +-----------------+
+ datafile header fixed size
+ +-----------------+
+ file table fixed size
+ +-----------------+
+ |
+ data pages data and page table pages
+ | (arbitrarily large)
+ v
+.fi
+.ke
+
+The page table is a vector mapping datafile pages by file offset onto lfile
+file numbers; the value of each page table entry is the file number of the
+lfile to which the page is assigned. When the file manager opens an lfile
+it scans the page table, extracting the page numbers of the pages assigned
+to the lfile, to form a vector mapping lfile page offsets directly onto
+datafile page offsets. New pages are always allocated at the end of the
+datafile, and new lfiles are always allocated at the end of the file table,
+hence lfile deletion will leave "holes" (unused storage) in both the datafile
+pages and file table. A \fIrebuild\fR operation is required to reclaim the
+space occupied by these holes. Deleted files are recoverable by merely
+revalidating their file table entries.
+
+Every variable size object managed by QPOE is stored in the datafile as a
+distinct lfile. Since storage for lfiles is allocated in units of file pages,
+the minimum amount of storage used by a variable length object is 0 or 1 page.
+Examples of variable size objects are the SYMTAB symbol table
+used to describe the contents of the datafile header (and any other symbols
+used by QPOE), the static data storage area (used to store the values of
+scalar and static array valued header parameters), and individual variable
+length arrays. Note that each variable length array is stored in the datafile
+as a separate lfile; if the maximum size of an array is less then the page
+size, it will be more efficient to store it as a static array.
+
+The most important example of a variable length array is the main event list
+of the poefile. To improve i/o efficiency and speed selection, the event
+structs stored in an event list are grouped together into \fIbuckets\fR,
+as discussed earlier in section 2.3.1.2. Each bucket will always occupy an
+integral number of file pages. Storage for buckets is allocated contiguously
+in the datafile, and buckets are always read and written to disk in a single
+i/o transfer.
+
+The most important physical datafile parameters are hence the page size and
+the bucket size. A larger page size can improve i/o efficiency and reduce the
+size of the page table, but can lead to significant wasted space if there are
+many variable length arrays. Since the i/o system will move entire large
+blocks of pages to and from disk whenever possible, use of a small page is
+normally preferred. A large bucket size improves i/o efficiency for event
+lists, but if the bucket size is too large then bucket searching takes longer,
+and selection efficiency may decrease.
+
+.NH 4
+File Manager
+
+ The function of the file manager is to map a set of lfiles onto a single
+random access host binary file. The file manager must keep track of the size
+and type of each file, and whether or not it has been deleted.
+In addition, the file manager must maintain a page table for the entire
+datafile, noting the lfile to which each page is assigned. While an lfile
+is open the file manager must maintain the page vector for that lfile so that
+lfile offsets may be mapped directly onto datafile offsets.
+
+The number of lfiles is fixed at datafile creation time, and lfiles are
+referred to by file number. File number zero is the datafile page table;
+the first user lfile is number one. A datafile with a max file count of one
+would actually contain two lfiles, counting the page table.
+
+The file manager interface is summarized in the figure below. A new datafile
+may be created or an existing datafile opened with \fIfm_open\fR.
+If a new datafile is being created the page size and max file count may be
+changed from their default values with calls to \fIfm_seti\fR, and the values
+of these and other parameters may be queried at any time with \fIfm_stati\fR.
+An opened datafile may be copied with \fIfm_copyo\fR, omitting deleted lfiles
+and rendering file segments contiguous. The page size and max file count
+may be changed in a copy operation if desired.
+
+The \fIfm_access\fR, \fIfm_rename\fR, and \fIfm_delete\fR routines perform
+the indicated operation upon the named datafile. The \fIfm_rebuild\fR
+routine rebuilds a datafile, discarding deleted structures and coalescing
+storage for objects. This routine, as well as \fIfm_copy\fR, are built upon
+on the lower level routine \fIfm_copyo\fR, which does the real work, and
+which allows the structural attributes of the new datafile to be specified
+in \fIfm_seti\fR cals.
+
+All i/o to lfiles is via the six routines beginning with \fIfm_lfopen\fR in
+the figure below. These routines constitute a FIO binary file driver for
+lfiles, and may be called directly, or passed to the FIO routine \fIfopnbf\fR
+to open an lfile as a binary file (\fIfm_lfname\fR should be called first
+to construct a pseudo-filename for the lfile so that \fIfm_lfopen\fR can
+reconstruct the file manager descriptor, lfile number, and lfile type).
+Note that the lfile driver routines are unbuffered and (potentially)
+asynchronous, and that i/o must be in units of datafile pages.
+(See the buffer cache routines described in the next section for a higher
+level facility for i/o to lfiles).
+
+.nf
+ yes|no = fm_access (datafile, mode)
+ fm_rename (datafile, newname)
+ fm_copy (datafile, newname)
+ fm_delete (datafile)
+ fm_rebuild (datafile)
+
+ fm = fm_open (datafile, mode)
+ fm_seti (fm, param, ival)
+ ival = fm_stati (fm, param)
+ fm_debug (fm, out, what)
+ fm_copyo (fm, fm_to)
+ fm_sync (fm)
+ fm_close (fm)
+
+ lfile = fm_nextlfile (fm)
+ fm_lfname (fm, lfile, type, lfname, maxch)
+
+ fm_lfopen (lfname, mode, lf)
+ fm_lfstati (lf, param, ival)
+ fm_lfaread (lf, buf, nbytes, offset, status)
+ fm_lfawrite (lf, buf, nbytes, offset, status)
+ fm_lfawait (lf, status)
+ fm_lfclose (lf, status)
+
+ fm_lfstat (fm, lfile, statbuf)
+ fm_lfdelete (fm, lfile)
+ fm_lfundelete (fm, lfile)
+.fi
+
+In a sense, all lfiles exist as zero length files when the datafile is
+created, since the lfile descriptors are preallocated and the files are
+known only by number. Lfiles become interesting when they are opened as
+files with \fIfm_lfopen\fR, and data is written into the file. An lfile
+may be deleted with \fIfm_lfstat\fR. All this does is set the delete bit
+in the lfile descriptor, hence a deleted lfile may later be undeleted with
+\fIfm_lfundelete\fR. The data in a deleted lfile is not lost until the lfile
+is again opened and written into, or the datafile is rebuilt. Information
+on a specific lfile (size, type, etc.) may be obtained with \fIfm_lfstat\fR.
+
+There is nothing about the file manager which is specific to QPOE, so it is
+implemented as a separate, standalone facility, and may be used in applications
+other than QPOE.
+
+.NH 4
+Buffer Cache
+
+ For reasons of efficiency, QPOE maintains portions of the datafile in
+memory buffers while a datafile is open. The main QPOE descriptor, symbol
+table, and file manager descriptor and page table are maintained in special
+runtime data structures internal to the respective interfaces. All other
+data is stored in lfiles and accessed only upon demand. In particular,
+storage for all static (non variable length) QPOE header parameters is
+maintained in a single lfile, and storage for each variable length parameter
+is allocated in a separate lfile.
+
+Since most access to QPOE header parameters is via simple gets and puts to
+named parameters, lfile access is handled by QPOE transparently to the client
+applications program. To avoid excessive disk i/o when randomly accessing
+the datafile, it is desirable for QPOE to maintain a cache of several lfile
+data buffers, e.g., so that accesses to a series of static parameters or
+repeated accesses to read or write different parts of an array parameter
+should incur minimal disk accesses. This buffer cache is implemented in
+QPOE by simply opening each lfile as a file under FIO, leaving it up to FIO to
+manage the file buffer, and maintaining a LRU cache of open lfiles in QPOE.
+The number of buffers (open lfiles) is controlled by the QP_CACHESIZE
+parameter. Since the lfile buffer cache is a general datafile related
+facility, it is implemented by the file manager.
+
+.ks
+.nf
+ fd = fm_getfd (fm, lfile, mode, type)
+ fm_retfd (fm, lfile)
+ fm_lockout (fm, lfile)
+ fm_debugfd (fm, out)
+.fi
+.ke
+
+The \fIfm_getfd\fR routine maps an lfile onto a file descriptor. A file
+descriptor is opened on the lfile only when necessary. Once opened, an lfile
+remains in the cache until forced out by the LRU replacement algorithm,
+or the datafile is closed. Removal of an lfile from the cache (closing the
+associated file descriptor) is permitted only after a call to \fIfm_retfd\fR;
+calling this routine does not immediately close the file, it only permits it
+to be closed. Most calls to \fIfm_getfd\fR should return a file descriptor
+immediately, with very little overhead, with an already active file buffer,
+hence repeated calls to the cache manager and FIO may be made without
+incurring any disk accesses.
+
+Note that lfiles may be opened on file descriptors via direct calls to the
+file manager, regardless of whether these lfiles are already open in the
+buffer cache. This allows two or more independent file buffers to be
+simultaneously active on the same lfile, but opens the possibility of loss
+of data if the buffers overlap. If this is a problem, the routine
+\fIfm_lockoutfd\fR may be called to prevent inadvertent use of an lfile by
+the cache. This should be followed by a call to \fIfm_retfd\fR to clear the
+lockout bit once the reason for the lockout (usually a noncached lfile open)
+is gone. The routine \fIfm_debugfd\fR will print information on \fIout\fR
+describing the contents of the buffer cache.
+
+.tp 24
+.NH 3
+Interface Structure
+.NH 4 1
+Header Access Package (QP Routines)
+
+ The structure of the general QPOE routines (mostly header access) is
+illustrated in the figure below.
+
+.ks
+.nf
+ +--------+
+ | QP |
+ +--------+
+ / \
+ / \
+ +--------+ +--------+
+ | SYMTAB | | BCACHE |
+ +--------+ +--------+
+ |
+ +--------------+
+ | FILE MANAGER |
+ +--------------+
+
+ Figure 1. Structure of the Header Access Routines
+.fi
+.ke
+
+To fulfill a get or put header access, QPOE will access the symbol table
+(SYMTAB) to lookup the symbol name and determine the symbol datatype, nelem,
+lfile number, and lfile file offset where the value is stored. The buffer
+cache (BCACHE) and FIO are then called to access the value of the parameter
+in the datafile.
+
+.NH 4
+Filtered Event I/O Package (QPIO)
+
+ The structure of the filtered event i/o package (QPIO) is illustrated in
+the figure below.
+
+.ks
+.nf
+ +--------+
+ | QPIO |
+ +--------+
+ / | \
+ __________/ | \__________
+ / | \
+ +--------+ +--------+ +--------+
+ | PLIO | | QPEX | | BCACHE |
+ +--------+ +--------+ +--------+
+ | |
+ +--------+ +--------------+
+ | SYMTAB | | FILE MANAGER |
+ +--------+ +--------------+
+
+ Figure 2. Structure of QPIO Routines
+.fi
+.ke
+
+In the typical \fIgetevents\fR call, QPIO will call PLIO to determine the
+next region of the stored image (event list) to access, then if the event
+data is not already in a data buffer, FIO is called to read the data (bucket),
+using the event list index, an integer array valued parameter, to determine
+what bucket to read. The events in the bucket are then examined and optionally
+filtered via calls to QPEX, returning pointers to the passed events in an
+output argument. This process terminates when either the mask value changes
+or at least one event has been returned and a new bucket is required to
+continue reading.