\section{Focal Plane}
\label{sec:focalplane}

\subsection{Overview}

In PSLib, we have defined a basic container for a single 2D collection
of pixels (\code{psImage}), along with basic operations to manipulate
the image pixels.  For astronomical applications, this data structure
is insufficient for two reasons.  First, it does not provide
sufficient additional metadata to describe the data in detail.
Second, astronomy applications frequently involve multiple, related
images.  For Pan-STARRS, and for general astronomical applications, we
require a richer collection of data structures which describe a very
general image concept.  We have defined several layers in the
hierarchy which are necessary to describe the image data which will be
produced by the Pan-STARRS GigaPixel Cameras as well as other standard
astronomical images.

A simple 2D image is the basic data unit for much of astronomical
imaging: if we consider various optical and IR array cameras, a single
readout of the detector produces a collection of pixel measurements
which is well represented as a single 2D image.  We define our
lowest-level astronomical image structure, \code{pmReadout}, to
contain the pixels produced by a single readout of the detector, along
with metadata needed to define that readout: the origin and binning of
the image relative to the original detector pixels explicitly in the
structure, and pointers to the general metadata and derived objects,
if any.

A single detector may be read multiple times in sequence.  For
example, infrared detectors frequently produce an image immediately
after the detector is reset followed by an image after the basic
exposure is complete.  Both readouts correspond to the same pixels,
though the binning or rastering may be different between the two
readouts.  Another example is the video sequence produced by the
Pan-STARRS GigaPixel Camera guide cells, each of which represents a
series of many images from a subraster of pixels in the detector
readout portion.  The second level of our image container hierarchy,
\code{pmCell}, consists of a collection of readouts from a single
detector.

In the Pan-STARRS GigaPixel camera, the basic readout region is a
fraction of the full imaging area of a single CCD chip.  The chip is
divided into 64 cells, any fraction of which may have been readout for
a given exposure.  In other cameras, such as Megacam at CFHT, the
individual CCDs have multiple amplifiers addressing contiguous
portions of the detector.  In such cameras, each amplifier produces a
separate collection of pixels.  In the third level of our image
container hierarchy, the data structure \code{pmChip} represents a
collection of different cells.

The top level of our image container hierarchy is a complete focal
plane array (\code{pmFPA}).  This structure represents the collection
of chips in the camera, all of which are read out in a given exposure.

For example, take a mosaic camera consisting of eight $2k\times 4k$
CCDs, each of which is read out through two amplifiers.  Then there
would be sixteen cells in total, each of which is presumably $1k\times
4k$.  There would be eight chips, each consisting of two cells, and
the focal plane consists of these eight chips.

As another example, consider an observation by PS-1.  The focal plane
would consist of 60 chips, each of which consist of 64 cells (or less;
a few cells may be dead).  Some cells (those containing guide stars
for the orthogonal transfer) will contain multiple readouts.

These data structures represent containers with which to carry around
the collection of related image data.  There is no requirement on the
functions or the structures that each instance of one of these data
structures represent the physical hardware.  For example, it is not
necessary that an instance of \code{pmFPA} always carry the data for
all 60 GigaPixel Camera OTAs.  The usage of these structures is such
that all astronomical operations which apply to a CCD image should be
performed on an instance of \code{pmFPA}.  If a particular
circumstance only requires a single 2D image, then that is represented
by an instance of \code{pmFPA} with one \code{pmChip}, which in turn
has one \code{pmCell}, which in turn has one \code{pmReadout}.

The data structures defined below provide two additional features
beyond the hierarchy of relationships.  First, each level of the
hierarchy includes hooks for carrying metadata to provide the PS
concepts and analysis metadata that would be appropriate for that
level.  The functions within PSLib do not specify the contents of
those metadata containers.

\subsection{Focal Plane Hierarchy}

Here we specify the contents of the focal plane hierarchy:
\code{pmReadout}, \code{pmCell}, \code{pmChip} and \code{pmFPA}.

\subsubsection{A Readout}

A readout corresponds to an individual read of a cell (e.g., a single
image as part of a video sequence, or one of multiple coadds).  It
contains the actual pixels used in analysis (along with mask and
weight maps).  When reading from a FITS file, the images are subimages
(from CELL.TRIMSEC) of the pixels read from the appropriate HDU (at
the FPA, chip or cell level).  The readout also contains a list of
bias sections (prescans or overscans, or otherwise), a summary of
analysis tasks that have been performed, status flags, and the offsets
used for reading a FITS file incrementally.

\begin{verbatim}
typedef struct {
    int col0;                           ///< Column offset; non-zero if reading in columns incrementally
    int row0;                           ///< Row offset; non-zero if reading in rows incrementally
    psImage *image;                     ///< Imaging area of readout (corresponds to CELL.TRIMSEC region)
    psImage *mask;                      ///< Mask of input image (corresponds to CELL.TRIMSEC region)
    psImage *weight;                    ///< Weight of input image (corresponds to CELL.TRIMSEC region)
    psList *bias;                       ///< List of bias (prescan/overscan) images
    psMetadata *analysis;               ///< Readout-level analysis metadata
    pmCell *parent;                     ///< Parent cell
    bool process;                       ///< Do we bother about reading and working with this readout?
    bool file_exists;                   ///< Does the file for this readout exist (read case only)?
    bool data_exists;                   ///< Does the data for this readout exist (read case only)?
} pmReadout;
\end{verbatim}    

The constructor for \code{pmReadout} is:
\begin{verbatim}
pmReadout *pmReadoutAlloc(pmCell *cell  ///< Parent cell, or NULL
                          );
\end{verbatim}
The constructor shall make an empty \code{pmReadout}.  The metadata
container and the \code{bias} list shall be allocated.  All other
pointers in the structure shall be initialized to \code{NULL}.
Processing is on by default; the existence flags are initially set to
\code{false}.

All data within a \code{pmReadout} may be freed:
\begin{prototype}
void pmReadoutFreeData(pmReadout *readout ///< Readout for which to free data
                      );
\end{prototype}

\subsubsection{A Cell}

A cell is the lowest-level camera structure, being part of a chip
(e.g., an amplifier).  It may consist of one or more readouts, which
are individual reads of the cell.  It also contains the concepts
metadata appropriate to this level, the cell configuration information
(for convenience) from the camera configuration, a summary of analysis
tasks that have been performed, status flags, and any HDU that
corresponds to this level for the file of interest

\begin{verbatim}
typedef struct {
    psMetadata *concepts;               ///< Cell-level concepts
    unsigned int conceptsRead;          ///< Which concepts have been read; see pmConceptsSource
    psMetadata *config;                 ///< Cell configuration information (from CELLS in the camera config)
    psMetadata *analysis;               ///< Cell-level analysis metadata
    psArray *readouts;                  ///< The component readouts
    pmChip *parent;                     ///< Parent chip
    bool process;                       ///< Do we bother about reading and working with this cell?
    bool file_exists;                   ///< Does the file for this cell exist (read case only)?
    bool data_exists;                   ///< Does the data for this cell exist (read case only)?
    pmHDU *hdu;                         ///< FITS header data unit of interest
} pmCell;
\end{verbatim}

The constructor for \code{pmCell} shall be:
\begin{verbatim}
pmCell *pmCellAlloc(pmChip *chip,       ///< Parent chip, or NULL
                    const char *name    ///< Name of cell, for CELL.NAME
                   );
\end{verbatim}
The constructor shall make an empty \code{pmCell}.  The
\code{readouts} array shall be allocated with a zero size, and the
metadata containers constructed.  Processing is on by default; the
existence flags are initially set to \code{false}.  The \code{name} is
used to set \code{CELL.NAME} in the \code{concepts}.  All other
pointers in the structure are initialized to \code{NULL}.

All readouts, or all data (readouts and metadata) within a cell may be
freed:
\begin{prototype}
void pmCellFreeReadouts(pmCell *cell    ///< Cell for which to free readouts
                       );
void pmCellFreeData(pmCell *cell        ///< Cell for which to free data
                   );
\end{prototype}

\subsubsection{A Chip}

The chip is the mid-level camera structure, being part of an FPA, and
consisting of one or more cells (e.g., a CCD).  It also contains the
concepts metadata appropriate to this level, a summary of analysis
tasks that have been performed, status flags, any HDU that corresponds
to this level for the file of interest, and astrometric
transformations.  The astrometric transformations provide transforms
between the chip and FPA coordinates and back.

\tbd{The astrometric transformations will likely disappear into the
analysis metadata in the future.}

\begin{verbatim}
typedef struct {
    // Astrometric transformations
    psPlaneTransform *toFPA;            ///< Transformation from chip to FPA coordinates, or NULL
    psPlaneTransform *fromFPA;          ///< Transformation from FPA to chip coordinates, or NULL
    // Information
    psMetadata *concepts;               ///< Chip-level concepts
    unsigned int conceptsRead;          ///< Which concepts have been read; see pmConceptsSource
    psMetadata *analysis;               ///< Chip-level analysis metadata
    psArray *cells;                     ///< The component cells
    pmFPA *parent;                      ///< Parent FPA
    bool process;                       ///< Do we bother about reading and working with this chip?
    bool file_exists;                   ///< Does the file for this chip exist (read case only)?
    bool data_exists;                   ///< Does the data for this chip exist (read case only)?
    pmHDU *hdu;                         ///< FITS header data unit of interest,
} pmChip;
\end{verbatim}

The constructor for \code{pmChip} shall be:
\begin{verbatim}
pmChip *pmChipAlloc(pmFPA *fpa,         ///< Parent FPA, or NULL
                    const char *name    ///< Name of cell, for CELL.NAME
                   );
\end{verbatim}
The constructor shall make an empty \code{pmChip}.  The \code{cells}
array shall be allocated with a zero size and the metadata containers
constructed.  Processing is on by default; the existence flags are
initially set to \code{false}.  The \code{name} shall be used to set
\code{CHIP.NAME} in the \code{concepts}.  All other pointers in the
structure shall be initialized to \code{NULL}.

All cells, or all data (cells and metadata) within a chip may be
freed:
\begin{prototype}
void pmChipFreeCells(pmChip *chip       ///< Chip for which to free cells
                    );
void pmChipFreeData(pmChip *chip        ///< Chip for which to free data
                   );
\end{prototype}

\subsubsection{A Focal Plane}

The FPA is the top-level camera structure, and consists of one or more
chips.  It also contains the concepts metadata appropriate to this
level, a summary of analysis tasks that have been performed, the
camera configuration information, any HDU that corresponds to this
level for the file of interest, and astrometric transformations.  The
astrometric transformations encode how to transform from the tangent
plane to the sky, and back.

It is expected that the astrometric transformation will consist of two
4D polynomials (i.e.\ a function of two coordinates in position, the
magnitude of the object, and the color of the object) in order to
correct for optical distortions and the effects of the atmosphere;
hence we think that it is prudent to include a reverse transformation
which will be derived from numerically inverting the forward
transformation.

\tbd{The astrometric transformations will likely disappear into the
analysis metadata in the future.}

\begin{verbatim}
typedef struct {
    // Astrometric transformations
    psPlaneDistort *fromTangentPlane;   ///< Transformation from tangent plane to focal plane, or NULL
    psPlaneDistort *toTangentPlane;     ///< Transformation from focal plane to tangent plane, or NULL
    psProjection *projection;           ///< Projection from tangent plane to sky, or NULL
    // Information
    psMetadata *concepts;               ///< FPA-level concepts
    unsigned int conceptsRead;          ///< Which concepts have been read; see pmConceptsSource
    psMetadata *analysis;               ///< FPA-level analysis metadata
    const psMetadata *camera;           ///< Camera configuration
    psArray *chips;                     ///< The component chips
    pmHDU *hdu;                         ///< FITS header data unit of interest, or NULL
} pmFPA;
\end{verbatim}

The constructor for \code{pmFPA} shall be:
\begin{verbatim}
pmFPA *pmFPAAlloc(const psMetadata *camera ///< Camera configuration (to store in FPA)
                 );
\end{verbatim}
The constructor shall make an empty \code{pmFPA}.  The \code{chips}
array shall be allocated with a zero size, the \code{camera} pointer
set to the value provided, and the \code{concepts} metadata
constructed.  All other pointers in the structure shall be initialized
to \code{NULL}.

All data (chips and metadata) within an FPA may be freed:
\begin{prototype}
void pmFPAFreeData(pmFPA *fpa           ///< FPA for which to free data
                  );
\end{prototype}

\subsubsection{Links between levels}

The inclusion of hierarchical links pointing both down (via the
arrays) and up (via the \code{parent}) could make for difficulties.
For this reason, we specify a utility function to manage the
collection of upward-pointing links:
\begin{prototype}
bool pmFPACheckParents(pmFPA *fpa);
\end{prototype}
This function checks the validity of the \code{parent} links in the
FPA hierarchy.  If any \code{parent} link in the (entire) hierarchy is
not set (or not set correctly), it is corrected, and the function
shall return \code{false}.  If all the \code{parent} pointers were
correct, the function shall return \code{true}.

\subsubsection{Levels}

The level within an FPA hierarchy may be specified by an enumerated
type:
\begin{datatype}
typedef enum {
    PM_FPA_LEVEL_NONE,                  ///< No particular level specified
    PM_FPA_LEVEL_FPA,                   ///< Level corresponds to an FPA
    PM_FPA_LEVEL_CHIP,                  ///< Level corresponds to a Chip
    PM_FPA_LEVEL_CELL,                  ///< Level corresponds to a Cell
    PM_FPA_LEVEL_READOUT                ///< Level corresponds to a Readout
} pmFPALevel;
\end{datatype}

The following functions are provided to convert between the enumerated type
and string representation of the level:
\begin{prototype}
const char *pmFPALevelToName(pmFPALevel level ///< Level enum
                            );
pmFPALevel pmFPALevelFromName(const char *name ///< Level name
                             );
\end{prototype}

The string representations are \code{FPA}, \code{CHIP}, \code{CELL}
and \code{READOUT} (case insensitive).

\subsubsection{Flags}

The following functions are provided to set and check the \code{file_exists}
and \code{data_exists} status flags within the FPA hierarchy:
\begin{prototype}
bool pmFPASetFileStatus(pmFPA *fpa,     ///< FPA for which to set status
                        bool status     ///< Status to set
                       );
bool pmChipSetFileStatus(pmChip *chip,  ///< Chip for which to set status
                         bool status    ///< Status to set
                        );
bool pmCellSetFileStatus(pmCell *cell,  ///< Cell for which to set status
                         bool status    ///< Status to set
                        );
bool pmFPACheckFileStatus(const pmFPA *fpa ///< FPA for which to check status
                         );
bool pmChipCheckFileStatus(const pmChip *chip ///< Chip for which to check status
                          );
bool pmCellCheckFileStatus(const pmCell *cell ///< Cell for which to check status
                          );
bool pmFPASetDataStatus(pmFPA *fpa,     ///< FPA for which to set status
                        bool status     ///< Status to set
                       );
bool pmChipSetDataStatus(pmChip *chip,  ///< Chip for which to set status
                         bool status    ///< Status to set
                        );
bool pmCellSetDataStatus(pmCell *cell,  ///< Cell for which to set status
                         bool status    ///< Status to set
                        );
\end{prototype}

The following functions set the \code{process} flag within the FPA
hierarchy, either selecting a component for processing, or excluding
it from processing:
\begin{prototype}
bool pmFPASelectChip(pmFPA *fpa,        ///< FPA containing the chip of interest
                     int chipNum,       ///< Chip number to select
                     bool exclusive     ///< Process this chip exclusive of the others?
                    );
bool pmChipSelectCell(pmChip *chip,     ///< Chip containing the cell of interest
                      int cellNum,      ///< Cell number to select
                      bool exclusive    ///< Process this cell exclusive of the others?
                     );
int pmFPAExcludeChip(pmFPA *fpa,        ///< FPA containing the chip of interest
                     int chipNum        ///< Chip number to exclude
                    );
int pmChipExcludeCell(pmChip *chip,     ///< Chip containing the chip of interest
                      int cellNum       ///< Cell number to exclude
                     );
\end{prototype}

The \code{Select} functions, set the specified component to be the
only component (at that level) to be processed if \code{exclusive} is
\code{true}.  A negative value for the component number is valid, and
if \code{exclusive} is \code{true}, de-selects all components at the
appropriate level.


\subsubsection{Finding a component by name}

A component may be found by its symbolic name (the concepts
\code{CHIP.NAME} or \code{CELL.NAME}, as appropriate).  The following
functions return the index of the component that matches the provided
name, or -1 if none was found:

\begin{prototype}
int pmFPAFindChip(const pmFPA *fpa,     ///< FPA in which to find the chip
                  const char *name      ///< Name of the chip
                 );
int pmChipFindCell(const pmChip *chip,  // Chip in which to find the cell
                   const char *name     // Name of the cell
                  );
\end{prototype}


\subsection{Header Data Units}

Each of the levels in the hierarchy have a place to hold a
\code{pmHDU}, which is the representation of a FITS ``header data
unit'':
\begin{datatype}
typedef struct {
    psString extname;                   ///< The extension name
    bool blankPHU;                      ///< Is this a blank FITS Primary Header Unit, i.e., no data?
    psMetadata *format;                 ///< The camera format
    psMetadata *header;                 ///< The FITS header, or NULL if primary for FITS; or section info
    psArray *images;                    ///< The pixel data
    psArray *weights;                   ///< The pixel data
    psArray *masks;                     ///< The pixel data
} pmHDU;
\end{datatype}

The \code{pmHDU} simplifies the input/output from/to FITS files, since
it is, for the most part, a representation of the HDU on disk.  Of
course, it is not an exact replica of a FITS HDU --- they have no mask
and weight data, but these are stored here for convenience --- it
keeps all the relevant data about the image in one place.

The allocator is:
\begin{prototype}
pmHDU *pmHDUAlloc(const char *extname   ///< Extension name, or NULL for PHU
                 );
\end{prototype}


\subsubsection{HDU I/O}

The following function moves to the appropriate extension and reads
the FITS header into the \code{pmHDU.header} member:
\begin{prototype}
bool pmHDUReadHeader(pmHDU *hdu,        ///< HDU for which to read header
                     psFits *fits       ///< FITS file from which to read
                    );
\end{prototype}

The following function moves to the appropriate extension and reads
the FITS header and pixels into the \code{pmHDU}:
\begin{prototype}
bool pmHDURead(pmHDU *hdu,              ///< HDU to read
               psFits *fits             ///< FITS file to read from
              );
\end{prototype}

The following function writes the HDU header and pixels to the end of
the FITS file:
\begin{prototype}
bool pmHDUWrite(pmHDU *hdu,             ///< HDU to write
                psFits *fits            ///< FITS file to write to
               );
\end{prototype}


\subsubsection{HDU Utilities}

The following functions return the appropriate HDU, given a member of
the focal plane hierarchy.  If no HDU is present at the particular
level, it searches the next highest level.  If no HDU can be found,
the function returns \code{NULL}.

\begin{prototype}
pmHDU *pmHDUFromFPA(const pmFPA *fpa    ///< FPA for which to find HDU
                   );
pmHDU *pmHDUFromChip(const pmChip *chip ///< Chip for which to find HDU
                    );
pmHDU *pmHDUFromCell(const pmCell *cell ///< Cell for which to find HDU
                    );
pmHDU *pmHDUFromReadout(const pmReadout *readout ///< Readout for which to find HDU
                       );
\end{prototype}

The following functions take multiple components of a focal plane
hierarchy, and return the HDU at the lowest/highest level of the
components passed to the function.  If components at all levels are
supplied, the lowest HDU in the hierarchy is the one with the actual
pixels, while the highest HDU is the PHU.
\begin{prototype}
pmHDU *pmHDUGetLowest(const pmFPA *fpa, ///< The FPA
                      const pmChip *chip, ///< The chip, or NULL
                      const pmCell *cell ///< The cell, or NULL
                     );
pmHDU *pmHDUGetHighest(const pmFPA *fpa, ///< The FPA
                       const pmChip *chip, ///< The chip, or NULL
                       const pmCell *cell ///< The cell, or NULL
                      );
\end{prototype}

The following function prints details about an HDU: the extension
name, headers (if requested), and image sizes.  This function is
intended for testing or development use.

\begin{prototype}
void pmHDUPrint(FILE *fd,               ///< File descriptor to which to print
                const pmHDU *hdu,       ///< HDU to print
                int level,              ///< Level at which to print
                bool header             ///< Print header?
               );
\end{prototype}


\subsection{FPA View}

The following structure allows the identification of a single
component of the focal plane hierarchy (or multiple, if we consider
selecting all those components below the selected component).
Components are identified on the basis of their chip, cell, readout
index.  An index of -1 means all components at that level.
Additionally, since readouts may be read piecemeal, there are
additional indices for these.
\begin{datatype}
typedef struct {
    int chip;                           // Number of the chip, or -1 for all
    int cell;                           // Number of the cell, or -1 for all
    int readout;                        // Number of the readout, or -1 for all
    int nRows;                          // Maximum number of rows per readout segment read, or 0 for all
    int iRows;                          // Starting point for this read
} pmFPAview;
\end{datatype}

The allocator is:
\begin{prototype}
pmFPAview *pmFPAviewAlloc(int nRows     ///< Maximum number of rows per readout segment read, or 0 for all
    );
\end{prototype}

\subsubsection{Utilities}

A view may have all components reset (select the entire FPA):
\begin{prototype}
bool pmFPAviewReset(pmFPAview *view     ///< View to reset
    );
\end{prototype}

The view level is the highest index that isn't set to -1.
\begin{prototype}
pmFPALevel pmFPAviewLevel(const pmFPAview *view ///< View to examine
    );
\end{prototype}

\subsubsection{Lookups}

The following functions return the appropriate currently selected
hierarchy component.  The functions return \code{NULL} if the selection
is not specific or invalid for the appropriate level.

\begin{prototype}
pmChip *pmFPAviewThisChip(const pmFPAview *view, ///< Current view
                          const pmFPA *fpa ///< FPA containing chip
    );
pmCell *pmFPAviewThisCell(const pmFPAview *view, ///< Current view
                          const pmFPA *fpa ///< FPA containing cell
    );
pmReadout *pmFPAviewThisReadout(const pmFPAview *view, ///< Current view
                                const pmFPA *fpa ///< FPA containing readout
    );
\end{prototype}

\subsubsection{Incrementors}

The following functions return the next hierarchy component, according
to the current selection in the \code{view}.  The functions return
\code{NULL} if there is no next.

\begin{prototype}
pmChip *pmFPAviewNextChip(pmFPAview *view, ///< Current view
                          const pmFPA *fpa, ///< FPA containing chips
                          int nStep     ///< Number of chips to increment
    );
pmCell *pmFPAviewNextCell(pmFPAview *view, ///< Current view
                          const pmFPA *fpa, ///< FPA containing cells
                          int nStep     ///< Number of cells to increment
    );
pmReadout *pmFPAviewNextReadout(pmFPAview *view, ///< Current view
                                const pmFPA *fpa, ///< FPA containing readouts
                                int nStep ///< Number of readouts to increment
    );
\end{prototype}

\subsubsection{HDUs}

The following function returns the HDU corresponding to the current view,
using the \code{pmHDUFrom...} functions, combined with the \code{view}.
\begin{prototype}
pmHDU *pmFPAviewThisHDU(const pmFPAview *view, ///< Current view
                        const pmFPA *fpa ///< FPA for view
    );
\end{prototype}

This function returns the blank Primary HDU corresponding to the
current view, if one exists.  The operation is similar to
pmFPAviewThisHDU, except it returns \code{NULL} if no HDU is found, or
the HDU is not a blank Primary HDU.
\begin{prototype}
pmHDU *pmFPAviewThisPHU(const pmFPAview *view, ///< Current view
                        const pmFPA *fpa ///< FPA for view
    );
\end{prototype}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{FPA Construction}

The following function creates the FPA hierarchy on the basis of the
camera configuration.  The \code{FPA} entry in the camera
configuration specifies the chips (each of type \code{STR}) with their
component cells listed as the corresponding values (whitespace
separated).  The FPA hierarchy is created devoid of any input/output
sources (i.e., HDUs).
\begin{prototype}
pmFPA *pmFPAConstruct(const psMetadata *camera ///< The camera configuration
                     );
\end{prototype}

Input/output sources may be specified within the hierarchy by
providing information that allows the position of the new HDU to be
determined (not only the level, but which component of that level);
this may be done in two ways.  The first is through a \code{pmFPAview}
that corresponds to the HDU position; this is appropriate when
creating an output file of known format.  The second is by providing
the primary header of an input file, from which the HDU position(s)
can be inferred (using the \code{FILE} information within the camera
format configuration); this is useful for adding input sources.  In
both cases, the camera format configuration is required in order to
describe how the FPA is laid out in terms of disk files.

\begin{prototype}
bool pmFPAAddSourceFromView(pmFPA *fpa,   ///< The FPA
                            const pmFPAview *phuView, ///< The view, corresponding to the PHU
                            const psMetadata *format ///< Format of file
                           );
pmFPAview *pmFPAAddSourceFromHeader(pmFPA *fpa, ///< The FPA
                                    psMetadata *phu, ///< Primary header of file
                                    const psMetadata *format ///< Format of file
                                   );
\end{prototype}

As an aid to development, we have a function that prints to a file
stream a representation of the FPA, including its headers and
concepts, if desired.

\begin{prototype}
void pmFPAPrint(FILE *fd,               ///< File descriptor to which to print
                const pmFPA *fpa,       ///< FPA to print
                bool header,            ///< Print headers?
                bool concepts           ///< Print concepts?
               );
\end{prototype}


\subsection{FPA Reading and Writing}

\subsubsection{Reading headers}

The following functions read the headers, if the HDU is at the
appropriate level.  The functions return \code{true} if they
successfully read the header, or if the header had already been read.
The functions do not iterate to lower levels.
\begin{prototype}
bool pmFPAReadHeader(pmFPA *fpa,        ///< FPA for which to read header
                     psFits *fits       ///< FITS file handle
                    );
bool pmChipReadHeader(pmChip *chip,     ///< Chip for which to read header
                      psFits *fits      ///< FITS file handle
                     );
bool pmCellReadHeader(pmCell *cell,     ///< Cell for which to read header
                      psFits *fits      ///< FITS file handle
                     );
\end{prototype}

\subsubsection{Reading pixels}

The following functions iterate over the component cells, reading the
pixels, converting them to \code{F32}, allocating readouts, and
ingesting concepts:
\begin{prototype}
bool pmCellRead(pmCell *cell,           // Cell to read into
                psFits *fits,           // FITS file from which to read
                psDB *db                // Database handle, for "concepts" ingest
               );
bool pmChipRead(pmChip *chip,           // Chip to read into
                psFits *fits,           // FITS file from which to read
                psDB *db                // Database handle, for "concepts" ingest
               );
bool pmFPARead(pmFPA *fpa,              // FPA to read into
               psFits *fits,            // FITS file from which to read
               psDB *db                 // Database handle, for "concepts" ingest
              );
\end{prototype}

The following functions perform the same as the above functions, but
read the pixels into the \code{mask} or \code{weight} elements of the
readout.
\begin{prototype}
bool pmCellReadMask(pmCell *cell,           // Cell to read into
                    psFits *fits,           // FITS file from which to read
                    psDB *db                // Database handle, for "concepts" ingest
                   );
bool pmChipReadMask(pmChip *chip,           // Chip to read into
                    psFits *fits,           // FITS file from which to read
                    psDB *db                // Database handle, for "concepts" ingest
                   );
bool pmFPAReadMask(pmFPA *fpa,              // FPA to read into
                   psFits *fits,            // FITS file from which to read
                   psDB *db                 // Database handle, for "concepts" ingest
                  );
bool pmCellReadWeight(pmCell *cell,           // Cell to read into
                      psFits *fits,           // FITS file from which to read
                      psDB *db                // Database handle, for "concepts" ingest
                     );
bool pmChipReadWeight(pmChip *chip,           // Chip to read into
                      psFits *fits,           // FITS file from which to read
                      psDB *db                // Database handle, for "concepts" ingest
                     );
bool pmFPAReadWeight(pmFPA *fpa,              // FPA to read into
                     psFits *fits,            // FITS file from which to read
                     psDB *db                 // Database handle, for "concepts" ingest
                    );
\end{prototype}


The above functions all read the pixels, at least a cell at a time.
The following function reads the pixels for a readout incrementally.
Multiple calls to this function moves through a readout within a cell
incrementally.  It is required to pass the readout previously acquired
(or a newly-allocated one) in order to preserve state information
(where the read is at).  Only a maximum of \code{numRows} rows are
read at a time.  Returns \code{true} if pixels are read, and
\code{false} otherwise.  To facilitate looping, no error is generated
for reading a plane that doesn't exist.  Note that this function
doesn't put pixels in the HDU.  It is therefore \textbf{not
compatible} with \code{pmCellWrite}, \code{pmChipWrite}, and
\code{pmFPAWrite} (or any function that uses or creates an HDU, for
that matter).  \code{pmReadoutWriteNext} should be used to write the
data that's read by this function.  This function is intended for
reading in many readouts into memory at once (e.g., for stacking)
where the input is not written out.
\begin{prototype}
bool pmReadoutReadNext(pmReadout *readout, // Readout into which to read
                       psFits *fits,    // FITS file from which to read
                       int z,           // Readout number/plane; zero-offset indexing
                       int numRows      // The number of rows to read
                      );
\end{prototype}

\subsubsection{Writing pixels and headers}

The following functions write the appropriate hierarchy level to a
FITS file, if one exists at that level.  The function generates
CELL.TRIMSEC, CELL.BIASSEC and the HDU pixels if required (see
\code{pmHDUGenerate}).  A blank (i.e., image-less header) is written
only if specifically requested.  The function writes the concepts to
the various locations, and then the HDU to the FITS file.  This
function should be called at the beginning of the output cell loop
with \code{blank=true} in order to produce the correct file structure.
\begin{prototype}
bool pmCellWrite(pmCell *cell,          ///<  Cell to write
                 psFits *fits,          ///<  FITS file to which to write
                 psDB *db,              ///<  Database handle for "concepts" update
                 bool blank             ///<  Write a blank PHU?
                );
bool pmChipWrite(pmChip *chip,          ///<  Chip to write
                 psFits *fits,          ///<  FITS file to which to write
                 psDB *db,              ///<  Database handle for "concepts" update
                 bool blank,            ///<  Write a blank PHU?
                 bool recurse           ///<  Recurse to lower levels?
                );
bool pmFPAWrite(pmFPA *fpa,             ///<  FPA to write
                psFits *fits,           ///<  FITS file to which to write
                psDB *db,               ///<  Database handle for "concepts" update
                bool blank,             ///<  Write a blank PHU?
                bool recurse            ///<  Recurse to lower levels?
               );
\end{prototype}


The following function is the companion to \code{pmReadoutReadNext},
as it writes a readout to a FITS file, perhaps incrementally (if it
has been read in using \code{pmReadoutReadNext}).  It relies on the
FITS header to specify how many image planes there are, and the width
and height.
\begin{prototype}
bool pmReadoutWriteNext(pmReadout *readout, ///< Readout to write
                        psFits *fits,   ///<  FITS file to which to write
                        int z           ///<  Image plane to write
                       );
\end{prototype}


\subsubsection{HDU Generation}

The write functions for the FPA hierarchy use \code{pmHDUWrite}, which
assumes that the images in the readouts are subimages of the pixels in
the HDU structure.  If this is not the case, the HDU pixels can be
generated using some simple assumptions.

The following function generate an HDU (with \code{CELL.TRIMSEC},
\code{CELL.BIASSEC} and pixels) for a cell with pixels.  They splice
the images and overscans together without regard for \code{CELL.X0}
and \code{CELL.Y0} (for a proper mosaic, see \code{pmFPAMosaic}),
though they should respect \code{CELL.READDIR} (so that the bias and
trim sections match properly).  A warning may be generated (by the
concept write functions) after running these functions if the bias and
trim sections are specified in the camera format by default values
rather than in the header.  Failure of these functions is often due to
a bad camera format file.
\begin{prototype}
bool pmHDUGenerateForCell(pmCell *cell  ///< The cell for which to generate an HDU
                         );
bool pmHDUGenerateForChip(pmChip *chip  ///< The chip for which to generate an HDU
                         );
bool pmHDUGenerateForFPA(pmFPA *fpa     ///< The fpa for which to generate an HDU
                        );
\end{prototype}

These functions are primarily intended for private use (by the write
functions) within the Modules, but may be used by the user if desired.

\subsection{Masks and Weights}

Pixel mask values are defined with the following enumerated type:
\begin{datatype}
typedef enum {
    PM_MASK_CLEAR   = 0x00,   ///< The pixel is not masked
    PM_MASK_TRAP    = 0x01,   ///< The pixel is a charge trap.
    PM_MASK_BADCOL  = 0x02,   ///< The pixel is a bad column.
    PM_MASK_SAT     = 0x04,   ///< The pixel is saturated.
    PM_MASK_BAD     = 0x08,   ///< The pixel is low
    PM_MASK_FLAT    = 0x10,   ///< The pixel is non-positive in the flat-field.
    PM_MASK_MARK    = 0x20,   ///< The pixel is marked as temporarily ignored
    PM_MASK_EXT1    = 0x40,   ///< This mask value is not used
    PM_MASK_EXT2    = 0x80,   ///< This mask value is not used
} pmMaskValue;
\end{datatype}

\tbd{It would be nice to have a system of registering symbolic names
for mask values at run time.}

The following functions use the readout image and certain concepts to
provide the mask and weight values.  There are two cases.  The first
is that of ``setting'' the mask/weight, where the mask/weight that
produced is temporary --- it is not added to the HDU.  This is
intended for when the user is iterating using pmReadoutReadNext, in
which case the HDU can't be generated.  The second case is that of
``generating'' the mask/weight, where the mask/weight that is produced
is suitable for output (complete with HDU entry); this is intended for
most operations.

In both cases, the mask is formed by identifying pixels are saturated
(at or above \code{CELL.SATURATION}) or bad (at or below
\code{CELL.BAD}); while the weights (actually variances) are
calculated using photon statistics from the cell gain
(\code{CELL.GAIN}) and read noise (\code{CELL.READNOISE})

\begin{prototype}
bool pmReadoutSetMask(pmReadout *readout ///< Readout for which to set mask
                     );
bool pmReadoutSetWeight(pmReadout *readout ///< Readout for which to set weight
                       );
bool pmReadoutGenerateMask(pmReadout *readout ///< Readout for which to generate mask
                          );
bool pmReadoutGenerateWeight(pmReadout *readout ///< Readout for which to generate weight
                            );
\end{prototype}

The following functions are intended for convenience, generating a
mask and weight map for a readout or cell:
\begin{prototype}
bool pmReadoutGenerateMaskWeight(pmReadout *readout ///< Readout for which to generate mask and weights
                                );
bool pmCellGenerateMaskWeight(pmCell *cell ///< Cell for which to generate mask and weights
                             );
\end{prototype}


\subsection{Copying: Converting between formats}

The following functions copy components of an FPA hierarchy to a
different representation of the same camera These functions are useful
for converting between different representations of the same camera.
For example, between Megacam "RAW" (one amp per extension) and Megacam
"SPLICED" formats (two amps = 1 chip per extension, spliced together).
Components are spliced together as necessary.

\begin{prototype}
bool pmFPACopy(pmFPA *target,           ///< The target FPA
               const pmFPA *source      ///< The source FPA, to be copied
              );
bool pmChipCopy(pmChip *target,         ///< The target chip
                const pmChip *source    ///< The source chip, to be copied
               );
bool pmCellCopy(pmCell *target,         ///< The target cell
                const pmCell *source    ///< The source cell, to be copied
               );
\end{prototype}

The following functions are similar, except that the pixels are not
copied (although images of sufficient size are allocated in the
target), and the \code{CELL.XBIN} and \code{CELL.YBIN} are changed
according to the provided binning factors.  These functions are
intended for binning a camera, where the user will do the binning.

\begin{prototype}
bool pmFPACopyStructure(pmFPA *target,   ///< The target FPA
                        const pmFPA *source, ///< The source FPA, to be copied
                        int xBin, int yBin ///< Binning factors in x and y
                       );
bool pmChipCopyStructure(pmChip *target, ///< The target chip
                         const pmChip *source, ///< The source chip, to be copied
                         int xBin, int yBin ///< Binning factors in x and y
                        );
bool pmCellCopyStructure(pmCell *target, ///< The target cell
                         const pmCell *source, ///< The source cell, to be copied
                         int xBin, int yBin ///< Binning factors in x and y
                        );
\end{prototype}


\subsection{Mosaicking: Converting between cameras}

The following functions mosaic cells within the appropriate hierarchy
component into a single cell within the target (which must have only a
single cell).  These functions are therefore useful for converting to
a different camera, which is generally a false representation of the
physical camera; in this manner, one can obtain an image of the chip
or FPA on the sky.  Cells are placed on the chip according to the
\code{CELL.X0} and \code{CELL.Y0} offsets.  The mosaicking is done so
as to avoid performing a deep copy of the pixels, if possible.

\begin{prototype}
bool pmChipMosaic(pmChip *target,       // Target chip --- may contain only a single cell
                  const pmChip *source  // Source chip whose cells will be mosaicked
                 );
bool pmFPAMosaic(pmFPA *target,         // Target FPA --- may contain only a single chip with a single cell
                 const pmFPA *source    // FPA whose chips and cells will be mosaicked
                );
\end{prototype}


\subsection{FPA Files}

\tbd{Below is the old text (it just stops suddenly).  EAM to provide
from the following files: pmFPAfileDefine.h pmFPAfileFitsIO.h
pmFPAfile.h pmFPAfileIO.h pmFPA\_MANAPLOT.h pmFPA\_JPEG.h }

The FPA structure defines the layout of the data read from a camera.
It contains elements to specify the location of the pixels within the
focal plane structure.  It also provides the relationship between a
specific hardware layout of the pixels (readouts, cells, chips, etc)
and a specific organization model for the data (headers and pixel
array sections, etc).  Depending on the needs of the users or the
desires of the instrument builders, the data read out from a single
camera may be stored in a number of different ways.  For example,
multiple cells within the same chip may be stored within the same
pixel array in different locations, within separate arrays in the same
FITS file in different extensions, or as separate files.  Multple
chips may be written to the same file or different files.  Multiple
readouts may be separate files or slices of an image cube.  

The pmFPA structure does not (and should not) define the relationship
between the pixel data and the actual files files on disk.  

The pmFPAfile structure defines a relationship between the data stored
in a pmFPA structure and an external (file) representation of that
data.  The purpose of this structure and its supporting functions is
to allow the application designer to easily add or changes the data
sources and the data destinations used by an application.  The
pmFPAfile defines the input and output data formats.  A single
pmFPAfile may represent FITS image data files, jpeg image files,
photometric measurements, astrometric calibrations, etc.  Each
instance of a pmFPAfile is identified with a particular data format.
It is defined as a data source (file from which to read data) or a
data destination (file to be written).  The pmFPAfile also defines the
naming conventions to be used for the particular type of file or set
of files.  A single pmFPAfile may be used to represent data coming
from or going to a single file on disk or a collection of files on
disk.  The pmFPAfile also defines anciliary data which is needed for
some file formats and not for others.  For example, FITS file
extensions need to be given particular EXTNAME values.  Or, jpeg
images require a colormap and clipping rules. 

The pmFPAfile system also lets the application designer have
flexibility with which types of files are required within a particular
program.  Consider an application which performs some manipulation of
an image.  The program may call several analysis modules as it
operates on the data.  For example, it may perform a bias subtraction
on the image pixels data.  Or, it may detect objects within another
module.  The pmFPAfile system allows the author of a module to refer tperform The program may have a few 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Astrometry}

\tbd{EAM needs to update this section.}

\code{pmAstromWCS} is a structure which represents the FITS WCS
keywords in a single header.  In a traditional astronomy image, this
includes the conversion from pixel coordinates via rotations, scaling,
and offset, to a coordinate system corresponding to linear degree
offsets relative to the reference pixel.  This linear (2D) coordinate
frame is then converted to a spherical (3D) coordinate frame via a
defined projection.


Astrometry is a basic functionality required for the IPP that will be
used repeatedly, both for low-precision (roughly where is my favorite
object?) and high-precision (what is the proper motion of this star?).
As such, it must be flexible, yet robust.

\subsection{Coordinate frames}
\label{sec:coordinateFrames}

There are five coordinate frames that we need to worry about for the
purposes of astrometry:
\begin{itemize}
\item Cell: $(x,y)$ in pixels --- raw coordinates;
\item Chip: $(X,Y)$ in pixels --- the location on the silicon;
\item Focal Plane: $(p,q)$ in microns --- the location on the focal plane;
\item Tangent Plane: $(l,m)$ in arcsec from the telescope boresight; and
\item Sky: (RA,Dec) --- ICRS.
\end{itemize}

The following steps are required to convert from the cell coordinates to
the sky:
\begin{itemize}
\item Cell $\longleftrightarrow$ Chip: two 2D polynomials, $(X,Y) = f(x,y)$;
\item Chip $\longleftrightarrow$ FP: two 2D polynomials, $(p,q) = g(X,Y)$;
\item FP $\longleftrightarrow$ TP: two 4D polynomials, $(l,m) =
h(p,q,m,c)$, where $m$ and $c$ are the magnitude and color of the
object, respectively; and
\item TP $\longleftrightarrow$ Sky:  transformation to the sky using
pre-computed coefficients for each pointing.
\end{itemize}

Note that the transformation between the Focal Plane and the Tangent
Plane is a four-dimensional polynomial, in order to account for any
possible dependencies in the astrometry on the stellar magnitude and
color; the former serves as a check for charge transfer
inefficiencies, while the latter will correct chromatic refraction,
both through the atmosphere and the corrector lenses.

We require structures to contain each of the above transformations as
well as the pixel data.

\subsection{FITS World Coordinate System}

The FITS World Coordinate System (WCS) headers are commonly employed
with astronomical images in order to relate pixels to celestial (or
otherwise) coordinates.  Since it is a FITS standard, we must be able
to read and write from WCS into our internal format.  For the time
being, we will consider only celestial WCS (i.e., no spectral
wavelength calibrations, etc).  Because WCS does not support the
multiple layers that we have built for \PS{}, we will use a simple
internal representation: a transformation, which handles any
distortions (i.e., goes directly from the coordinate frame of the
image to the tangent plane); and the projection.

\begin{prototype}
bool pmAstromReadWCS(psPlaneTransform **transform, // Output transformation
                     psProjection **projection, // Output projection
                     psMetadata *header // Input FITS header
);
bool pmAstromWriteWCS(psMetadata *header, // Output FITS header
                      psPlaneTransform *transform, // Input transformation
                      psProjection *projection // Input projection
);
\end{prototype}

\code{pmAstromReadWCS} shall parse the specified FITS \code{header},
returning new instances of the \code{transform} and \code{projection}
that represent the WCS.  The function shall return \code{true} if it
was able to successfully generate the outputs; otherwise it shall
return \code{false}.

\code{pmAstromWriteWCS} shall add WCS keywords to the supplied FITS
\code{header} that implement the given \code{transform} and
\code{projection}.  The function shall return \code{true} if it was
able to successfully generate the output; otherwise it shall return
\code{false}.

\begin{verbatim}
bool pmAstrometrySimplify(psPlaneTransform **transform, // Output transformation
                          psProjection **projection, // Output projection
                          pmCell *cell // Cell for which to generate transform and projection
);
\end{verbatim}

\code{pmSimplifyAstrometry} shall take a \code{cell} and simplify the
internal astrometric representation (\code{cell->toFPA} or equivalent,
\code{cell->parent->parent->toTangentPlane} and
\code{cell->parent->parent->grommit}) to a single \code{transform} and
\code{projection}.  This allows the subsequent use of
\code{pmWriteAstrometry} in the case that we have only the
multi-layered \PS{} internal astrometric representation.  The function
shall return \code{true} if it was able to successfully generate the
output; otherwise it shall return \code{false}.

\subsection{Astrometry Analysis}

Astrometry is performed on an astronomical image after a collection of
sources in the image have been detected and thier instrumental
positions have been measured.  In this collection of tools, the
coordinates should be measured in the frame of the \code{pmReadout}
portion of the Image Hierarchy.  This potentially allows us to measure
an astrometric transformation resulting from the transformation to any
of the other coordinate system.  For example, it might be necessary to
determine the coordinates of the \code{psReadout} pixels relative to
the \code{psCell} (rather than accept the relationship defined by the
metadata).

For the moment, we define two layers of astrometric analysis which
will be performed on typical mosaic images in the Pan-STARRS IPP:
per-chip astrometry and per-mosaic astrometry.  In the first case, a
collection of detections across a single chip are used to determine a
basic, linear transformation to celestial coordinates.  This
astrometric analysis can be used to determine an initial, approximate
astrometry for each chip in a mosaic camera, with accurcy limited by
the effects of optical distortion (a few pixels error, typically).  In
the second case, a collection of detectors on a collection of chips
from a mosaic camera are used to measure the position of the telescope
boresight, the camera rotation, the impact of distortion from the
telescope optics, and the chip-to-focal plane transformation resulting
from chip placement errors or possible detector tilts or warps.

The process of performing astrometry involves the following steps:
\begin{itemize}
\item Make an initial guess at the celestial coordinates of the raw
  detections (eg, from metadata or image header information).
\item Determine, and load, stars from an astrometric catalog which may
  potentially correspond to the raw detections.
\item Project both raw and reference stars to a common coordinate
  frame (here we use the Focal Plane as an appropriate coordinate
  system). 
\item Identify matches between the raw and reference stars.
\item Determine the transformations necessary to relate the
  coordinates of the two sets of stars.
\item Convert the measured transformations into appropriate terms in
  the astrometric elements of the Image Hierarchy.
\end{itemize}
In this section, we specify several functions which together make
possible the above analysis steps.  

\subsubsection{Astrometry Objects}

We define the following structure to carry the necessary information
about each detection.  
\begin{datatype}
typedef struct {
    psPlane pix;
    psPlane FP;
    psPlane TP;
    psSphere sky;
    double mag;
} pmAstromObj;
\end{datatype}
This structure specifies the coordinate of the detection in each of
the four necessary coordinate frames: \code{pix} defines the position
in the \code{psReadout} frame, \code{FP} defines the position in the
Focal Plane frame, \code{TP} defines the position in the Tangent Plane
frame, \code{sky} defines the position on the Celestial Sphere.  In
addition, a measurement of the brightness is given by the element
\code{Mag}.  Such a data structure should be used for both the raw and
the reference stars.  In astrometric processing, the raw detections
will be projected using the best available information to each of
these coordinate frames from the \code{pix} coordinates, while the
reference detections will be projected to the other frames from the
\code{sky} coordinates.

The raw detections and the reference stars are both projected to a
common coordinate frame for analysis.  In these modules, we use the
Focal Plane for this reference frame.  After projection to the common
frame, it is necessary to determine the match between corresponding
objects in the two lists.  In order to match the raw detections to the
reference stars, different methods are used depending on the
circumstance.

\subsubsection{Matching Stars : Close Match}

If the two sets of coordinates are expected to agree very well (ie,
the current best-guess astrometric solution is quite close to the
`true' astrometric solution), then it is possible to use the simplest
matching process: cross-correlation within a fixed radius.  The
following function accepts two sets of \code{pmAstromObj} sources and
determines the matched objects between the two lists.  The input
sources must have been projected to the Focal Plane coordinates
(\code{pmAstromObj.FP}), and the supplied \code{options} entry must
contain the desired match radius (keyword:
\code{ASTROM.MATCH.RADIUS}).  The output consists an array of
\code{pmAstromMatch} values, defined below.

\begin{prototype}
psArray *pmAstromRadiusMatch (psArray *starlist1, psArray *starlist2, psMetadata *options);
\end{prototype}

\begin{datatype}
typedef struct {
    int idx1;
    int idx2;
} pmAstromMatch;
\end{datatype}
The \code{pmAstromMatch} structure defines the cross-correlation
between two arrays.  An single such data item specifies that item
number \code{pmAstromMatch.idx1} in the first list corresponds to
\code{pmAstromMatch.idx2} in the second list.  

\subsubsection{Matching Stars : Rough Match}

If the two sets of coordinates are not known to agree well, a somewhat
different approach is needed.  Several algorithms have been defined in
the past to correlate two lists with unknown offsets, and potentially
unknown relative rotations and scaling.  One well-known method is the
triangle-match algorithm which searches for similar triangles observed
in the two lists.  This algorithm has the advantage of not requiring
the rotation or the scale to be well-known in advance.  The
disadvantage of the triangle match algorithm is that it is necessarily
an $O(N^3)$ process since it is necessary to construct a substantial
fraction of all possible triangles for both input lists.  \tbd{we do
  not define a triangle match algorithm at this time}.

If the two sets of coordinates are not known to agree well, but the
relative scale and approximate relative rotation is known, then a much
faster match can be found using pair-pair displacements.  In such a
case, the two lists can be considered as having the same coordinate
system, with an unknown relative displacement.  In this algorithm, all
possible pair-wise differences between the source positions in the two
lists are constructed and accumulated in a grid of possible offset
values.  The resulting grid is searched for a cluster representing the
offset between the two input lists.  This algorithm can only tolerate
a small error in the relative scale or the relative rotation of the
two coordinate lists.  However, this process is naturally $O(N^2)$,
and is thus advantageous over triangle matching in some circumstances.
This process can be extended to allow a larger uncertainty in the
relative rotation by allowing the procedure to scan over a range of
rotations.  We define the following function to apply this matching algorithm: 
\begin{prototype}
pmAstromStats pmAstromGridMatch (psArray *raw, psArray *ref, psMetadata *options);
\end{prototype}
The input sources must have been projected to the Focal Plane
coordinates (\code{pmAstromObj.FP}), and the supplied \code{options}
entry must contain the following user-defined parameters:
\begin{itemize}
\item \code{GRID.OFFSET}    : maximum allowed displacement in search
\item \code{GRID.SCALE}     : grid bin size in focal-plane coordinate units
\item \code{GRID.MIN.ANGLE} : minimum tested relative rotation 
\item \code{GRID.MAX.ANGLE} : maximum tested relative rotation 
\item \code{GRID.DEL.ANGLE} : relative rotation step size
\end{itemize}
Note that the angles are defined as clockwise rotations of \code{raw}
relative to \code{ref}.

This function returns values in the \code{pmAstromStats} structure, defined as: 
\begin{datatype}
typedef struct {
    psPlane center;
    psPlane offset;
    double  angle;
    double  minMetric;
    double  minVar;
    int     nMatch;
} pmAstromStats;
\end{datatype}
The elements \code{angle} and \code{offset} define the best rotation
and offset; the element \code{nMatch} indicates the number of matched
sources which fell within the match bin; the element \code{minVar}
specifies the variance of the sources within the match bin; the
element \code{minMetric} specifies the value of the selection metric
for the matched bin.  Note that the metric of choice may not
necessarily be either the simple number of sources or the varience.
We find that a combination based on both which enhances the importance
of having a well-populated bin with a minimal variance gives good
results: $\mbox{metric} = \mbox{var} \times N^{-4}$.  The element
\code{center} defines the center of rotation used for rotating the
\code{raw} stars relative to the \code{ref} stars.

The result of a \code{pmAstromGridMatch} may be used to modify a
\code{psPlaneTransform} structure \code{map}.  The result of
\code{pmAstromGridMatch} can be translated into adjustments of the
\code{psPlaneTransform} (ie the rotation and offset).  This adjustment
is made using the function:
\begin{prototype}
bool pmAstromGridApply (psPlaneTransform *map, pmAstromStats stats);
\end{prototype}
This function modifies the supplied \code{map} entry assuming the
adjustments are relative to the provided transformation.

We define two additional functions which are used in
\code{pmAstromGridMatch}, but which may be useful on their own:

\begin{prototype}
pmAstromStats pmAstromGridAngle (psArray *raw, psArray *ref, psMetadata *options);
\end{prototype}
This function is identical to \code{pmAstromGridMatch}, but is valid
for only a single relative rotation.  The input \code{config}
information need not contain any of the \code{GRID.*.ANGLE} entries
(they will be ignored).

\begin{prototype}
psArray *pmAstromRotateObj (psArray *old, psPlane center, double angle);
\end{prototype}
This function accepts an array of \code{pmAstromObj} objects and
rotates them by the given \code{angle} about the given center
coordinate \code{center} in the Focal Plane Array coordinates.

\subsubsection{Astrometry Fitting Routines}

The result of a \code{pmAstromRadiusMatch} operation is a list of
matched entries between the two input lists.  This list may be used to
determine a linear fit between the two sets of matched sources.  The
following function performs this operation:
\begin{prototype}
bool pmAstromFitFPA (pmFPA *fpa, psArray *st1, psArray *st2, psArray *match, psMetadata *config);
\end{prototype}
This function accepts the raw and reference source lists and the list
of matched entries.  It uses the matched list to determine a
polynomial transformation between the two coordinate systems.  The
fitting uses clipping to exclude outliers, likely representing poor
matches.  The \code{config} element must contain the information
\code{ASTROM.NSIGMA} (specifying the number of sigma used in the
clipping) and \code{ASTROM.NCLIP} (specifying the number of clipping
iterations must be performed).  The \code{config} element must also
specify the order of the polynomial fit (keyword:
\code{ASTROM.ORDER}).  The result of this fit is a set of
modifications of the components of the \code{pmFPA.toTangentPlane}
transformation, and the modifications of the reference coordinate of
the projection (\code{pmFPA.projection.R,D}) and the projection scale
(\code{pmFPA.projection.Xs,Ys}).  The modifications to
\code{pmFPA.toTangentPlane} incorporate the rotation component of the
linear terms and the higher-order terms of the polynomial fits.

An alternative to fitting the rotation of the FPA relative to the
Tangent Plane is to treat the fitted transformation as a measurement
of the chip within the FPA.  The following function performs this
operation in the same way as \code{pmAstromFitFPA}:
\begin{prototype}
bool pmAstromFitChip (pmFPA *fpa, psArray *st1, psArray *st2, psArray *match, psMetadata *config);
\end{prototype}
This function accepts the raw and reference source lists for a single
chip and the list of matched entries.  It uses the matched list to
determine a polynomial transformation between the two coordinate
systems.  The fitting uses clipping to exclude outliers, likely
representing poor matches.  The \code{config} element must contain the
information \code{ASTROM.NSIGMA} (specifying the number of sigma used
in the clipping) and \code{ASTROM.NCLIP} (specifying the number of
clipping iterations must be performed).  The \code{config} element
must also specify the order of the polynomial fit (keyword:
\code{ASTROM.ORDER}).  The result of this fit is a set of
modifications of the components of the \code{pmChip.toFPA}
transformation.

A mosaic represents a particular set of challenges when determining an
astrometric solution.  There is substantial degeneracy between the
astrometric terms which describe the transformationfrom the chip to
the focal plane, and the tranformation from the focal plane to the
tangent plane, in the presence of distortion.  The degeneracy can be
broken by examining the distortion component in its effect on the
gradient of the sources position residuals rather than in the source
positions themselves.  The following function determines the position
residual, in the tangent plane, as a function of position in the focal
plane, for a collection of raw measurements and matched reference
stars.  The configuration data must include the bin size over which
the gradient is measured (keyword: \code{ASTROM.GRAD.BOX}).  The
function returns an array of \code{pmAstromGradient} structures,
defined below.
\begin{prototype}
psArray pmAstromMeasureGradients (psArray *starlist1, psArray *starlist2, psArray *match, psMetadata *config);
\end{prototype}

The following data structure carries the information about the
residual gradient of source positions in the tangent plane
(\code{pmAstromObj.TP}) as a function of position in the focal plane
(\code{pmAstromObj.FP}).
\begin{datatype}
typedef struct {
    psPlane FP;
    psPlane dTPdL;
    psPlane dTPdM;
} pmAstromGradient;
\end{datatype}

The gradient set measured above can be fitted with a pair of 2D
polynomials.  The resulting fits can then be related back to the
implied polynomials which represent the distortion.  The following
function performs the fit and applies the result to the distortion
transformation of the supplied \code{pmFPA} structure.  The
configuration variable supplies the polynomial order (keyword:
\code{ASTROM.DISTORT.ORDER}).
\begin{prototype}
psArray pmAstromFitDistortion (pmFPA *fpa, psArray *gradients, psMetadata *config);
\end{prototype}
