Index: /tags/SDRS-01/doc/modules/ModulesSDRS.tex
===================================================================
--- /tags/SDRS-01/doc/modules/ModulesSDRS.tex	(revision 2073)
+++ /tags/SDRS-01/doc/modules/ModulesSDRS.tex	(revision 2073)
@@ -0,0 +1,753 @@
+%%% $Id: ModulesSDRS.tex,v 1.18 2004-10-13 02:38:13 eugene Exp $
+\documentclass[panstarrs]{panstarrs}
+
+% basic document variables
+\title{Pan-STARRS IPP Modules}
+\subtitle{Supplementary Design Requirements}
+\author{Paul Price}
+\shorttitle{Phase 2 SDRS}
+\group{Pan-STARRS Algorithm Group}
+\project{Pan-STARRS Image Processing Pipeline}
+\organization{Institute for Astronomy}
+\version{01}
+\docnumber{PSDC-430-008}
+% note the use of the docnumber & version number:
+% the complete PSDC document number is given by
+% \thedocnumber-\theversion
+
+\setlength{\topsep}{-2pt}
+  
+\begin{document}
+\maketitle
+\sloppy
+
+% -- Revision History --
+% provide explicit values for the old versions
+% use '\theversion' for the current version (set above)
+% use \hline between each table row
+\RevisionsStart
+% version  Date            Description
+DR & 2004 Jun 7 & Draft \\ \hline
+00 & 2004 Aug 16 & release for cycle 3 \\ \hline
+01 & 2004 Oct 12 & draft for cycle 4 \\ \hline
+\RevisionsEnd
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\DocumentsInternal
+PSCD-130-001  &   PS-1 Design Reference Mission \\ \hline
+PSCD-430-004  &   Pan-STARRS IPP C Code Conventions \\ \hline
+PSCD-430-005  &   Pan-STARRS IPP SRS \\ \hline
+PSCD-430-006  &   Pan-STARRS IPP ADD \\ \hline
+PSCD-430-008  &   Pan-STARRS IPP Architecture SDR \\ 
+\DocumentsExternal
+Posix Standard & Open Group Based Specifications Issue 6, IEEE Std 1003.1, 2003 \\
+\DocumentsEnd
+
+\tableofcontents
+\pagebreak 
+\pagenumbering{arabic}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Introduction}
+
+This document describes the Pan-STARRS Image Processing Pipeline (IPP)
+image processing modules.  The modules use the functionality of the
+\PS{} Library (PSLib) to perform more complex tasks.  They will
+eventually be tied together, employing a script written in a
+high-level language to form a ``processing stage''.  Modules will be
+constructed to support each of the required processing stages, and are
+listed in this document according to the particular processing stage
+for which they will primarily be used.
+
+In order to preserve name space, globally-visible structures and
+functions shall be prefixed with \code{pm}, for ``\PS{} Modules''.
+
+
+\section{Phase 2}
+
+Phase 2 is the processing stage wherein the instrumental signatures
+are removed from the detector images, in preparation for the
+combination of multiple images in Phase 4.
+
+The Phase 2 processing modules are:
+\begin{itemize}
+\item Subtract bias;
+\item Correct for non-linearity;
+\item Flat-field;
+\item Mask bad pixels;
+\item \tbd{Subtract the background;}
+\item \tbd{Mask cosmic rays;}
+\item \tbd{Mask optical defects;}
+\item \tbd{Measure the PSF;}
+\item \tbd{Find and measure objects;}
+\item \tbd{Correct astrometry; and}
+\item \tbd{Get postage stamps.}
+\end{itemize}
+
+Each of these shall be discussed in turn, below.  Those modules which
+are \tbd{TBD} will be deferred until they may be properly defined,
+some of which requires further research to define the best algorithm.
+
+\subsection{Bias subtraction}
+\label{sec:bias}
+
+The bias subtraction module provides a facility to correct detector
+images for the electronic pedestal introduced by the readout
+electronics.
+
+Given an input image and various other parameters,
+\code{pmSubtractBias} shall subtract the bias from the image.
+The API shall be the following:
+\begin{verbatim}
+psReadout *pmSubtractBias(psReadout *in, void *fitSpec, const psList *overscans,
+                          pmOverscanAxis overscanAxis, const psStats *stat,
+                          int nBin, pmFit fit, const psReadout *bias);
+\end{verbatim}
+
+Two types of bias correction may optionally be performed on the input
+image, \code{in}.  The first is the subtraction of an overscan.
+Multiple overscan regions may be specified and fit as a function of
+row (or column).  The second is the subtraction of a full-frame bias
+image (or a ``dark'' image).
+
+The input image, \code{in}, shall have the bias subtracted in-place.
+
+The type of the overscan fit function, \code{fitSpec}, shall be
+dependent upon the value of \code{fit}, which specifies the type of
+fit to be employed and is described below.
+
+The prescan and/or overscan regions to be used are specified in
+\code{overscans}, which is a linked list of subimages.  In cases where
+\code{overscans} is \code{NULL} and \code{overscanAxis} is not
+\code{PM_OVERSCAN_NONE}, the function shall generate an error.  If
+\code{overscans} is non-\code{NULL} and \code{overscanAxis} is
+\code{PM_OVERSCAN_NONE}, then the function shall generate a warning,
+no overscan subtraction shall be performed, and the function shall
+proceed to the full-frame bias subtraction.
+
+The \code{overscanAxis} specifies how the prescan/overscan subtraction
+is to be performed.  It is an enumerated type:
+\begin{verbatim}
+/** Overscan axis */
+typedef enum {
+    PM_OVERSCAN_NONE,                   ///< No overscan subtraction
+    PM_OVERSCAN_ROWS,                   ///< Subtract rows
+    PM_OVERSCAN_COLUMNS,                ///< Subtract columns
+    PM_OVERSCAN_ALL                     ///< Subtract the statistic of all pixels in overscan region
+} pmOverscanAxis;
+\end{verbatim}
+
+If the \code{overscanAxis} is \code{PM_OVERSCAN_NONE}, then the
+function shall not perform any overscan subtraction, but proceed to
+the full-frame bias subtraction.  If the \code{overscanAxis} is
+\code{PM_OVERSCAN_ALL}, then all the overscan regions shall be used to
+generate a single statistic (specified by \code{stat}) which shall be
+subtracted from the entire image.  A warning shall be generated if the
+\code{overscanAxis} is \code{PM_OVERSCAN_NONE} or
+\code{PM_OVERSCAN_ALL} and the \code{fit} is not \code{PM_FIT_NONE}.
+
+If the \code{overscanAxis} is \code{PM_OVERSCAN_ROWS} or
+\code{PM_OVERSCAN_COLUMNS}, then the overscan shall be reduced to a
+single vector (in the specified dimension) using the specified
+statistic (\code{stat}).
+
+The statistic to use in combining multiple pixels in the
+prescan/overscan regions is specified by \code{stat}.  \code{stat} is
+of type \code{psStats} instead of simply \code{psStatsOptions} so that
+clipping levels may be specified, if desired.  In the event that
+multiple options are specified by \code{stats}, a warning shall be
+generated, and the option with the highest priority shall be used,
+according to the following priority order: \code{PS_STAT_SAMPLE_MEAN},
+\code{PS_STAT_SAMPLE_MEDIAN}, \code{PS_STAT_CLIPPED_MEAN},
+\code{PS_STAT_ROBUST_MEAN},\ \code{PS_STAT_ROBUST_MEDIAN},
+\code{PS_STAT_ROBUST_MODE}.
+
+If \code{nBin} is positive and less than the size of the vector, then
+the vector shall subsequently be binned into bins that are a relative
+size of \code{nBin} compared to the original pixels, again using the
+specified statistic (\code{stat}).
+
+\code{fit} is an enumerated type:
+\begin{verbatim}
+/** Fit types */
+typedef enum {
+    PM_FIT_NONE,                        ///< No fit
+    PM_FIT_POLYNOMIAL,                  ///< Fit polynomial
+    PM_FIT_SPLINE                       ///< Fit cubic splines
+} pmFit;
+\end{verbatim}
+
+If \code{fitSpec} is \code{NULL}, or \code{fit} is \code{PM_FIT_NONE},
+then no fit shall be performed to the overscan.  Otherwise,
+\code{fitSpec} shall be interpreted to be a structure of the
+appropriate type (\code{psPolynomial1D} for \code{PM_FIT_POLYNOMIAL},
+and \code{psSpline1D} for \code{PM_FIT_SPLINE}), and the overscan
+shall (after reduction of the vector and binning) be fit using the
+specified functional form.  Upon return, the \code{fitSpec} shall
+contain the coefficients of the overscan fit.
+
+If the overscan is not defined for each row/column, then the function
+shall generate a warning and then interpolate using the provided
+functional form if \code{fit} is not \code{PM_FIT_NONE}; otherwise,
+the function shall generate an error.
+
+Following any binning, the vector shall be fit by the functional form
+specified by \code{fit}.  Then the overscan shall be subtracted from
+the image, using values from the fit if \code{fit} is not
+\code{PM_FIT_NONE}; otherwise using values from the overscan vector if
+\code{overscanAxis} is not \code{PM_OVERSCAN_ALL}; otherwise using the
+appropriate statistic applied to all the prescan/overscan pixels.
+
+A bias (or dark) image shall be subtracted pixel-by-pixel from the
+input image if \code{bias} is non-NULL.  Note that the input image,
+\code{in}, and the \code{bias} image need not be the same size, but
+the function shall use the offsets in the image (\code{in->x0} and
+\code{in->y0}) to determine the appropriate offsets to obtain the
+correct pixel on the \code{bias}.  In the event that the \code{bias}
+image is too small (i.e., pixels on the input image refer to pixels
+outside the range of the \code{bias} image), the function shall
+generate an error.  Any pixels masked in the \code{bias} shall also be
+masked in the output.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Non-linearity}
+
+We here specify two functions to perform the non-linearity correction,
+since either (or both) might be used to specify the correction.
+
+The first, \code{pmNonLinearityPolynomial} shall correct the input
+image for non-linearity by replacing the flux in each pixel of the
+input image, \code{in}, with the result of the specified polynomial,
+\code{coeff}, acting on the flux.  The API shall be the following:
+
+\begin{verbatim}
+psReadout *pmNonLinearityPolynomial(psReadout *in, const psPolynomial1D *coeff);
+\end{verbatim}
+
+The polynomial coefficients, \code{coeff}, will be supplied by the
+caller, likely from the image metadata.
+
+The second function, \code{pmNonLinearityLookup} shall correct
+the input image for non-linearity by using a lookup table.  The API
+shall be the following:
+
+\begin{verbatim}
+psReadout *pmNonLinearityLookup(psReadout *in, const psVector *inFlux, const psVector *outFlux);
+\end{verbatim}
+
+For each pixel in the input image, the function shall find the flux
+value in the \code{inFlux} vector, and replace the flux with the
+corresponding value in the \code{outFlux} vector.  If the sizes of the
+\code{inFlux} and \code{outFlux} vectors differ, then the function
+shall generate a warning, and the longer vector shall be truncated to
+the length of the shorter.  The \code{inFlux} vector may be assumed
+to be pre-sorted and not contain duplicate values.
+
+If the particular value of a pixel is not found in the \code{inFlux}
+vector, the corresponding \code{outFlux} shall be calculated through
+linear interpolation.  If the value of a pixel is beyond the range of
+values specified in the \code{inFlux} vector, then the function shall
+generate a warning (at most one warning of this type per call,
+preferably mentioning the number of pixels out of bounds), and replace
+that pixel value with the \code{outFlux} value corresponding to the
+minimum or the maximum, depending on whether the pixel value is below
+or above the range of \code{inFlux} values.
+
+In the event that the \code{inFlux} vector does not contain two or
+more entries (being the lower limit required for linear
+interpolation), then the function shall generate a warning, and make
+no correction to any of the pixels.
+
+Both \code{pmNonLinearityPolynomial} and \code{pmNonLinearityLookup}
+shall modify the input image in-place.
+
+\subsection{Flat-fielding}
+
+Given an input image and a flat-field image, \code{pmFlatField} shall
+divide the input image by the flat-field image and return it in place,
+updating the mask as appropriate.  The API shall be the following:
+\begin{verbatim}
+bool pmFlatField(psReadout *in, psReadout *mask, const psReadout *flat);
+\end{verbatim}
+
+Note that the input image, \code{in}, and the flat-field image,
+\code{flat}, need not be the same size, since the input image may
+already have been trimmed (following overscan subtraction), but the
+function shall use the offsets of the readout (\code{in->col0,
+in->row0}) and the image subarray (\code{in->image->x0,
+in->image->y0}) to determine the appropriate offsets to obtain the
+correct detector pixels in the flat-field image.  Note that the image
+offset is relative to its parent, so this offset must be followed to
+the top level image which is not a child of another image and the
+offsets summed.  The detector pixel coordinates of pixel \code{x,y} in
+a top-level image are thus \code{x + in->image->x0 + in->col0, y +
+in->image->y0 + in->row0}. In the event that the \code{flat} image is
+too small (i.e., pixels on the input image refer to pixels outside the
+range of the \code{flat} image), the function shall generate an error.
+
+Pixels which are negative or zero in the \code{flat} shall be masked
+in the input image with the value \code{PM_MASK_FLAT} (see
+\S\ref{sec:maskValues}).  Negative pixels in the \code{flat} may be
+set to zero so that they are treated identically to zeroes.  Any
+pixels masked in the \code{flat} shall be masked with corresponding
+values in the \code{output}.
+
+The function shall not normalize the \code{flat}; this responsibility
+is left to the caller.  This function is basically equivalent to a
+divide (with \code{psImageOp}), but with care for the region that is
+divided, checking for negative pixels, and copying of the mask from
+the \code{flat} to the output.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{Masking}
+
+\subsubsection{Mask values}
+\label{sec:maskValues}
+
+We define several mask values for use in the phase 2 processing:
+\begin{verbatim}
+/** Mask values */
+typedef enum {
+    PM_MASK_TRAP       = 0x0001,        ///< The pixel is a charge trap
+    PM_MASK_BADCOL     = 0x0002,        ///< The pixel is a bad column
+    PM_MASK_SAT        = 0x0004,        ///< The pixel is saturated
+    PM_MASK_FLAT       = 0x0008,        ///< The pixel is non-positive in the flat-field
+} pmMaskValue;
+\end{verbatim}
+
+Of these, masks for the charge traps need to be grown by the extent of
+the OT convolution kernel.  For other pixel types, orthogonal transfer
+of the flux in this pixel will not (necessarily) affect the flux in
+neighbouring pixels.
+
+\subsubsection{Bad pixels}
+
+Given an input image, \code{in}, a bad pixel \code{mask}, a
+corresponding value in the bad pixel mask to mask in the input image,
+\code{maskVal}, a saturation level, and a growing radius,
+\code{pmMaskBadPixels} shall mask in the input image those
+pixels in the bad pixel mask that match the value to mask.  The API
+shall be the following:
+\begin{verbatim}
+psReadout *pmMaskBadPixels(psReadout *in, const psImage *mask, unsigned int maskVal,
+                           float sat, unsigned int growVal, int grow);
+\end{verbatim}
+
+Note that the input image, \code{in}, is modified in-place.  All
+pixels in the \code{mask} which satisfy the \code{maskVal} shall have
+their corresponding pixels masked in the input image, \code{in}.  All
+pixels which satisfy the \code{growVal} shall have their corresponding
+pixels, along with all pixels within the \code{grow} radius masked.
+Pixels which have flux greater than \code{sat} shall also be masked,
+but not grown.
+
+Note that the input image, \code{in}, and the \code{mask} need not be
+the same size, since the input image may already have been trimmed
+(following overscan subtraction), but the function shall use the
+offsets in the image (\code{in->x0} and \code{in->y0}) to determine
+the appropriate offsets to obtain the correct pixel on the mask.  In
+the event that the \code{mask} image is too small (i.e., pixels on the
+input image refer to pixels outside the range of the \code{mask}
+image), the function shall generate an error.
+
+
+
+\section{Calibration}
+
+The calibration module essentially consists of combining multiple
+images of a particular type in order to build up signal-to-noise.  For
+this, we require a general purpose image combination module.  We
+forsee this module as only acting upon data from the same detector,
+and so each input image will have the same noise characteristics.
+
+\begin{verbatim}
+typedef struct {
+    psStats *stats;                     // Statistics to use in combining pixels
+    unsigned int maskVal,               // Mask pixels where mask & maskVal == 1
+    float fracHigh;                     // Fraction of high pixels to throw
+    float fracLow;                      // Fraction of low pixels to throw
+    int nKeep;                          // Number of pixels to be sure to keep
+} pmCombineParams;
+
+psImage *
+pmReadoutCombine(psImage *output,       // Output image, or NULL
+                 const psList *inputs,  // List of input readouts
+                 pmCombineParams *params, // Combination parameters
+                 const psVector *zero,  // Offsets to apply for each image
+                 const psVector *scale, // Scales to apply for each image
+                 bool applyZeroScale,   // Are zero and scale for application, or only noise properties?
+                 float gain,            // Gain in e/ADU
+                 float readnoise        // Read noise in e
+                 );
+\end{verbatim}
+
+\code{pmReadoutCombine} combines input images pixel by pixel --- for
+each pixel of the output image, a stack of contributing input pixels
+is formed and combined.  Several of its input parameters are lists or
+vectors, and if these are not all of the same length (or \code{NULL}),
+the module shall generate an error and return \code{NULL}.
+
+If the provided \code{output} is \code{NULL}, then the module shall
+allocate a new image of sufficient size for the input images.  If the
+\code{output} image is non-\code{NULL} and is not of sufficient size
+for the combined image, the module shall generate an error and return
+\code{NULL}.
+
+If the \code{inputs} is \code{NULL}, the module shall generate an
+error and return \code{NULL}.  Otherwise, the \code{inputs} shall be a
+list of \code{psReadout}s.  The images contained within the
+\code{psReadout}s need not all be of the same size, but the module
+shall take into account the offsets (\code{col0,row0}) from the corner
+of the detector when comparing pixels, so that it is the same
+\textit{physical} pixels that are combined.
+
+The parameters used in the combination, including how the pixels are
+to be combined, and how the rejection is performed is contained within
+the \code{params}, which may not be \code{NULL} (otherwise the module
+shall generate an error and return \code{NULL}).  We choose to use
+this structure instead of supplying the values separately in order to
+keep down the number of parameters to \code{pmReadoutCombine}; the
+\code{psCombineParams} may be recycled for subsequent calls to
+\code{pmReadoutCombine} since the values are not dependent upon the
+choice of inputs, but merely specify how the combination is to be
+performed.
+
+The particular statistic specified by \code{stats} shall be used to
+combine each stack of pixels from the input images.  Only one of the
+statistics choices may be specified, otherwise the module shall
+generate an error and return \code{NULL}.
+
+If the \code{maskVal} is non-zero, then pixels in the \code{mask} of
+each \code{psReadout} in the \code{inputs} which satisfy the
+\code{maskVal} shall not have the corresponding pixels placed in the
+stack for combination.
+
+After masking, but before performing the combination, the highest
+\code{fracHigh} fraction and lowest \code{fracLow} fraction of pixels
+in the stack are immediately rejected, unless this would leave less
+than \code{nKeep} pixels in the stack, in which case no immediate
+rejection is performed.
+
+If the \code{zero} vector is non-\code{NULL} and \code{applyZeroScale}
+is \code{true}, then the appropriate values shall be added to the
+\code{inputs} before combining.  In the event that the type of the
+\code{psVector} is more precise than that of any of the \code{inputs},
+the module shall generate a warning and truncate the sum to the
+precision of the image.  If \code{zero} is non-\code{NULL} and
+\code{applyZeroScale} is false, then the values shall only be used in
+calculating the noise.
+
+If the \code{scale} vector is non-\code{NULL} and
+\code{applyZeroScale} is \code{true}, then the appropriate values
+shall multiply the \code{inputs} before combining.  In the event that
+the type of the \code{psVector} is more precise than that of any of
+the \code{inputs}, the module shall generate a warning and truncate
+the multiplication to the precision of the image.  If \code{scale} is
+non-\code{NULL} and \code{applyZeroScale} is false, then the values
+shall only be used in calculating the noise.
+
+The purpose of \code{applyZeroScale} is to allow combination of fringe
+frames, where the frames have been deliberately sky-subtracted and
+rescaled (to get the fringes amplitudes running from -1 to 1), which
+actions should not be undone when combining, but yet it is desirable
+to provide the \code{zero} and \code{scale} values so that the correct
+noise properties are used in the combination.
+
+If the \code{gain} and \code{readnoise} are positive and non-negative
+(respectively), then these shall be used to provide weights for the
+combination.
+
+\section{Camera Configutation Information}
+
+\tbd{these function are not yet ready for implementation.  The APIs
+  are fine but the algorithms need to be specified.}
+
+We require several utility functions to define the general layout of a
+camera and to relate the camera definition to the header in a given
+camera.  This information may be passed to the modules by using the
+configuration files as parse by \code{psMetadataParseConfig}.  These 
+
+\begin{verbatim}
+char *pmCameraFromHeader (psFitsHeader *header);
+\end{verbatim}
+This function examines a primary header unit (\code{header}) and
+determines the camera which provided the data.  \tbr{the rules for
+  performing this analysis probably depend on the keywords such as
+  INSTRUME and TELESCOP.  Should this function be a script so we can
+  easily add a new camera or should the rule set be defined by
+  configuration information?}.
+
+\begin{verbatim}
+bool  pmCameraValidateHeaders (psHash *headers, psMetadata *camera);
+\end{verbatim}
+This funtion examines the collection of \code{headers} and, based on
+the camera definitions in the metadata \code{camera}, determines if
+the header set is consistent with the specified camera.
+
+\begin{verbatim}
+psFPA *pmFPAfromHeader (psList *header, psMetadata *camera);
+\end{verbatim}
+This funtion uses the collection of \code{headers} and the camera
+definitions in the metadata \code{camera} to construct a complete
+\code{psFPA} structure which represents the data described by the
+collection of \code{headers}.  The resulting \code{FPA} has all
+possible structure elements defined but no space for pixel data should
+be allocated.  
+
+\section{Revision Change Log}
+\input{ChangeLogSDRS.tex}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\bibliographystyle{plain}
+\bibliography{panstarrs}
+
+\end{document}
+
+\subsection{Subtract sky}
+
+\tbd{This is a simple sky subtraction routine.  A more complicated
+routine will be specified in the future, following research into the
+best algorithm.}
+
+Given an input image, a polynomial or spline specifying the order of a
+desired fit, a binning factor and statistics to use for the binning,
+along with a clipping level, \code{psPhase2SubtractSky} shall fit and
+subtract a model for the background of the image.  The API shall be
+the following:
+\begin{verbatim}
+psReadout *psPhase2SubtractSky(psReadout *in, void *fitSpec, psFit fit, int binFactor, psStats *stats,
+                               float clipSD);
+\end{verbatim}
+
+Note that the input image, \code{in}, shall be subtracted in-place.
+The function shall return the subtracted image, and also update the
+polynomial, chebyshev or spline specified by \code{fitSpec}, to hold
+the coefficients used in the subtraction.
+
+The fit specification, \code{fitSpec}, specifies the order of the
+polynomial or spline to be used in fitting the background.
+\code{fitSpec} shall be interpreted as a polynomial, Chebyshev or
+spline on the basis of \code{fit} (in the same manner as for bias
+subtraction; \S\ref{sec:bias}).  If \code{fitSpec} is \code{NULL} or
+\code{fit} is \code{PS_FIT_NONE} or \code{PS_FIT_LINEAR}, then no fit
+shall be performed, and the function shall simply return.
+
+When fitting the polynomial, the function shall first bin the input
+image by \code{binFactor} in order to reduce the required processing
+time.  The statistic to use in this binning is specified by
+\code{stat}.  \code{stat} is of type \code{psStats} instead of simply
+\code{psStatsOptions} so that clipping levels may be specified, if
+desired.  In the event that multiple options are specified by
+\code{stats}, a warning shall be generated, and the option with the
+highest priority shall be used, according to the following priority
+order: \code{PS_STAT_SAMPLE_MEAN}, \code{PS_STAT_SAMPLE_MEDIAN},
+\code{PS_STAT_CLIPPED_MEAN}, \code{PS_STAT_ROBUST_MEAN},\
+\code{PS_STAT_ROBUST_MEDIAN}, \code{PS_STAT_ROBUST_MODE}.  If the
+\code{binFactor} is non-positive, or \code{stats} is \code{NULL} or
+fails to specify an option, a warning shall be generated, and the fit
+shall be performed on the entire image.
+
+Binned pixels deviating more than \code{clipSD} standard deviations
+from the mean of the binned pixels shall be clipped in a single
+clipping iteration before polynomial fitting.  If the \code{clipSD} is
+non-positive, then the function shall generate a warning and not
+perform any clipping.
+
+
+\subsection{Cosmic rays}
+
+Given an input image, a choice of a particular algorithm with
+corresponding parameters, \code{psPhase2MaskCRs} shall mask cosmic
+rays on the input image on the basis of their morphology.  The API shall be the following:
+\begin{verbatim}
+/** Masks Cosmic Rays on the input image on the basis of morphology. */
+psReadout *psPhase2MaskCRs(psReadout *in, ///< Input image to be masked, and output
+                           int algorithm, ///< Algorithm number to use
+                           const void *params ///< Parameters for algorithm
+                           );
+\end{verbatim}
+
+This is one case in which the best choice of algorithm is not known,
+and may change in the future.  For this reason, we specify the inputs
+as an integer to specify the choice of algorithm in addition to a
+pointer to some parameters which will be decoded on the basis of the
+choice of algorithm.
+
+Note that the input image is modified in-place.
+
+\subsection{psPhase2MaskOpticalDefects}
+
+Given an input image, a list of nearby stars, and a growing radius,
+\code{psPhase2MaskOpticalDefects} shall mask optical defects on the
+image.  The API shall be the following:
+\begin{verbatim}
+/** Masks optical defects in the input image */
+psChip *psPhase2MaskOpticalDefects(psChip *in, ///< Image to be masked (with astrometry), and output
+                                   const psDlist *catalog, ///< Catalog stars nearby: a list of psObjects
+                                   int grow ///< Number of pixels to grow
+                                   );
+\end{verbatim}
+
+\tbd{It's not clear to me how this is accomplished apart from an
+optical model of the camera.  Put this one on the backburner?}
+
+
+\section{Objects}
+
+To identify and measure objects, we must measure the PSF, and then
+convolve the image by this PSF and apply a threshold.
+
+\subsection{Measure the PSF}
+
+Given an input image, a choice of algorithm with corresponding
+parameters, \code{psPhase2MeasurePSF} shall return the PSF for the
+image.  The API shall be the following:
+\begin{verbatim}
+/** Measures the PSF on the input image.  Returns the PSF */
+psImage *psPhase2MeasurePSF(const psReadout *in, ///< Input image for which to measure the PSF
+                            int algorithm, ///< Algorithm number to use
+                            const void *params ///< Parameters for algorithm
+                            );
+\end{verbatim}
+
+This is another case where the algorithm is not currently clear, and
+may change in the future.  For this reason, we specify the inputs to
+be a choice of algorithm, and a pointer to some parameters, which are
+interpreted on the basis of the algorithm choice.
+
+\subsection{Find and measure objects}
+
+Given an input image, the PSF of that image, and a list of flux levels
+at which to threshold, \code{psPhase2GetObjects} shall return a
+readout with the \code{objects} member set to a list of objects.  The
+API shall be the following:
+\begin{verbatim}
+/** Find and measure objects on the input image.  Fills in the "objects" member of the psReadout. */
+/** THIS NEEDS WORK. */
+psReadout *psPhase2FindObjects(psReadout *in, ///< Input image on which to find objects, and output
+                               const psImage *psf, ///< PSF to use to find objects
+                               const psVector *levels ///< Threshold levels (std dev.s)
+                               );
+\end{verbatim}
+
+Note that the input image shall be modified in-place, only insofar as
+the \code{objects} member shall be set to the list of objects on that
+image.
+
+\tbd{This needs a lot more work.}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Astrometry}
+
+Given a chip, the elements of which have objects found and measured on
+them, a list of catalog stars which lie on (or near) the chip, and
+clipping parameters, \code{psPhase2Astrometry} shall fit an
+astrometric solution.  The API shall be the following:
+\begin{verbatim}
+/** Corrects astrometry on the input chip */
+psChip *psPhase2Astrometry(psChip *in,  ///< Input chip for which to do astrometry, and output
+                           const psDlist *catalog, ///< Catalog stars on the chip: a list of psObjects
+                           int nClips,  ///< Number of clipping iterations
+                           float clipLevel ///< Level at which to clip
+                           );
+\end{verbatim}
+
+Note that the input chip shall be modified in-place, only insofar as
+the appropriate astrometry members shall be updated to correspond to
+the fit solution (specifically, \code{in->cells[i]->cellToSky}, for
+each \code{i}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Postage stamps}
+
+Postage stamps consist of subimages of specific objects of interest,
+which are saved for more careful analysis of the pixels.
+
+\subsection{Specification}
+
+The postage stamps are specified by a center and size, in celestial
+coordinates.  We define a \code{psPostageStampSpec} to specify the
+parameters for a postage stamp:
+\begin{verbatim}
+/** Specification of a postage stamp: location on the sky */
+typedef struct {
+    psSphereCoord *center;              ///< Centre of postage stamp
+    psSphereCoord *size;                ///< Size of postage stamp
+} psPostageStampSpec;
+\end{verbatim}
+
+The \code{center} shall be specified in ICRS coordinates, which is the
+\PS{} standard system.  The \code{size} shall be specified in
+arcseconds on the sky.
+
+\subsection{Extracting postage stamps}
+
+Given an input chip, and a linked-list of regions on or near the input
+chip, \code{psPhase2PostageStamps} shall output an array of subimages,
+containing each of the regions.  The API shall be the following:
+\begin{verbatim}
+/** Return postage stamps of a set of regions */
+psImageArray *psPhase2PostageStamps(const psChip *in, ///< Chip from which to form postage stamps
+                                    const psDlist *regions ///< Regions to postage-stampise: a list of
+                                                           ///< psPostageStampSpec
+                                    );
+\end{verbatim}
+
+\code{regions} shall be a linked list of \code{psPostageStampSpec}s,
+not all of which may correspond to legal positions on the input chip,
+\code{in}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Read in an FPA}
+
+\TBD{This section on reading in an FPA is all TBD and should not be
+implemented yet.}
+
+Of course, before any image manipulation may occur, the image must be
+read in.  This involves populating the FPA with structures to
+represent the true focal plane.  However, different instruments have
+different focal planes, and the images are written to disk in
+different ways.  We have proposed a configuration file format which
+appears to be able to document the structure of a focal plane and
+specify how the IPP can read the required information from the FITS
+files \tbd{REFERENCE}.
+
+Given an open \code{FILE} pointer to a configuration file,
+\code{config}, and the name of an FPA image, \code{fpaName},
+\code{psFPAGenerate} shall return a \code{psFPA} of the correct
+structure, with all the metadata entries read from the nominated FPA
+image.  Astrometric information shall be initialised to values
+specified by the configuration file.  The API shall be:
+
+\begin{verbatim}
+psFPA *psFPAGenerate(FILE *config, const char *fpaName);
+\end{verbatim}
+
+Once an FPA has been generated, the pixels may all be read in at once,
+or the pixels may be read in a chip, cell or readout at a time.  The
+corresponding APIs are:
+
+\begin{verbatim}
+psFPA *psFPAReadAll(psFPA *in);
+psFPA *psFPAReadChip(psFPA *in, const char *chipName);
+psChip *psChipReadCell(psChip *in, const char *cellName);
+psCell *psCellReadReadout(psCell *in, const char *readoutName);
+\end{verbatim}
+
+Note that reads of a cell or readout do not act upon an FPA, but
+rather a chip and a cell, respectively.  This saves the user from
+specifying the name of the FPA, chip, and cell just to get a readout,
+since this information is already stored in the generated \code{psFPA}
+struct.
+
+\tbd{Writing the output}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
