Index: trunk/doc/config/config.tex
===================================================================
--- trunk/doc/config/config.tex	(revision 9622)
+++ trunk/doc/config/config.tex	(revision 9673)
@@ -1,3 +1,3 @@
-%%% $Id: config.tex,v 1.1 2006-10-18 04:19:54 price Exp $
+%%% $Id: config.tex,v 1.2 2006-10-20 03:51:59 price Exp $
 \documentclass[panstarrs,spec]{panstarrs}
 
@@ -100,5 +100,5 @@
 provided;
 \item The environment variable \code{PS_SITE}, if defined; or
-\item \code{\$HOME/.ipprc} otherwise.
+\item \code{$HOME/.ipprc} otherwise. %$
 \end{enumerate}
 
@@ -183,45 +183,45 @@
 ### Example .ipprc file
 
-PATH            STR     .:/my/home/.ipp	# Default search path for configuration files
-WORKDIR		STR	/my/data/disk/	# Top-level working directory
+PATH            STR     .:/my/home/.ipp # Default search path for configuration files
+WORKDIR         STR     /my/data/disk/  # Top-level working directory
 
 ### Database configuration
-DBSERVER	STR	localhost		# Database host name (for psDBInit)
-DBNAME		STR	my_database		# Database name (for psDBInit)
-DBUSER		STR	my_name			# Database user name (for psDBInit)
-DBPASSWORD	STR	my_password		# Database password (for psDBInit)
+DBSERVER        STR     localhost               # Database host name (for psDBInit)
+DBNAME          STR     my_database             # Database name (for psDBInit)
+DBUSER          STR     my_name                 # Database user name (for psDBInit)
+DBPASSWORD      STR     my_password             # Database password (for psDBInit)
 
 ### Setups for each camera system
-CAMERAS		METADATA
-	MCSHORT		STR	mcshort/camera.config
-	MCSHORT_CHIP	STR	mcshort_chip/camera.config
-	MCSHORT_FPA	STR	mcshort_fpa/camera.config
-	MEGACAM		STR	megacam/camera.config
-	MEGACAM_CHIP	STR	megacam_chipmosaic/camera.config
-	MEGACAM_FPA	STR	megacam_fpamosaic/camera.config
-	MEGACAM_DET	STR	megacam_detrended/camera.config
-	UCAM		STR	ucam/camera.config
-	UCAM_MOSAIC	STR	ucam_mosaic/camera.config
-	GPC1		STR	gpc1/camera.config
-	LRIS_BLUE	STR	lris_blue/camera.config
-	LRIS_RED	STR	lris_red/camera.config
-	ISP      	STR	isp/camera.config
-	SIMPLE		STR	simple/camera.config
+CAMERAS         METADATA
+        MCSHORT         STR     mcshort/camera.config
+        MCSHORT_CHIP    STR     mcshort_chip/camera.config
+        MCSHORT_FPA     STR     mcshort_fpa/camera.config
+        MEGACAM         STR     megacam/camera.config
+        MEGACAM_CHIP    STR     megacam_chipmosaic/camera.config
+        MEGACAM_FPA     STR     megacam_fpamosaic/camera.config
+        MEGACAM_DET     STR     megacam_detrended/camera.config
+        UCAM            STR     ucam/camera.config
+        UCAM_MOSAIC     STR     ucam_mosaic/camera.config
+        GPC1            STR     gpc1/camera.config
+        LRIS_BLUE       STR     lris_blue/camera.config
+        LRIS_RED        STR     lris_red/camera.config
+        ISP             STR     isp/camera.config
+        SIMPLE          STR     simple/camera.config
 END
 
 ### psLib setup
-TIME		STR	pslib/psTime.config	# Time configuration file
-LOGLEVEL	S32	9			# Logging level; 3=INFO
-LOGFORMAT	STR	THLNM			# Log format
-LOGDEST		STR	STDERR			# Log destination
-TRACEDEST	STR	STDERR			# Trace destination
+TIME            STR     pslib/psTime.config     # Time configuration file
+LOGLEVEL        S32     9                       # Logging level; 3=INFO
+LOGFORMAT       STR     THLNM                   # Log format
+LOGDEST         STR     STDERR                  # Log destination
+TRACEDEST       STR     STDERR                  # Trace destination
 TRACEFORMAT     STR     THLNM                   # Trace format
-TRACE		METADATA			# Trace levels
-	err		S32	10
-END
-
-RECIPES		METADATA		# Site-level recipes
-	PPMERGE		STR		ppMerge_template.config	# Recipe for combination
-	PPSTATS_PHASE0	STR		ppStats_phase0.config	# Recipe for phase 0 processing
+TRACE           METADATA                        # Trace levels
+        err             S32     10
+END
+
+RECIPES         METADATA                # Site-level recipes
+        PPMERGE         STR             ppMerge_template.config # Recipe for combination
+        PPSTATS_PHASE0  STR             ppStats_phase0.config   # Recipe for phase 0 processing
 END
 \end{verbatim}
@@ -330,5 +330,5 @@
 be useful to define a type:
 \begin{verbatim}
-TYPE	LIMITS	FILTER	EXPECTED	IMFILE.MEAN	IMFILE.STDEV	EXP.MEAN	EXP.STDEV	EXP.MEANSTDEV	ENSEMBLE.MEAN	ENSEMBLE.STDEV	ENSEMBLE.MEANSTDEV
+TYPE    LIMITS  FILTER  EXPECTED        IMFILE.MEAN     IMFILE.STDEV    EXP.MEAN        EXP.STDEV       EXP.MEANSTDEV   ENSEMBLE.MEAN   ENSEMBLE.STDEV  ENSEMBLE.MEANSTDEV
 \end{verbatim}
 
@@ -344,18 +344,18 @@
 
 # File formats that we know about
-FORMATS		METADATA
-	RAW	STR	mcshort/format_raw.config
-	SPLICE	STR	mcshort/format_spliced.config
-	SPLIT	STR	mcshort/format_split.config
+FORMATS         METADATA
+        RAW     STR     mcshort/format_raw.config
+        SPLICE  STR     mcshort/format_spliced.config
+        SPLIT   STR     mcshort/format_split.config
 END
 
 # Description of camera --- all the chips and the cells that comprise them
-FPA	METADATA
-	ccd12	STR	LeftAmp RightAmp
-	ccd13	STR	LeftAmp RightAmp
-	ccd14	STR	LeftAmp RightAmp
-	ccd21	STR	LeftAmp RightAmp
-	ccd22	STR	LeftAmp RightAmp
-	ccd23	STR	LeftAmp RightAmp
+FPA     METADATA
+        ccd12   STR     LeftAmp RightAmp
+        ccd13   STR     LeftAmp RightAmp
+        ccd14   STR     LeftAmp RightAmp
+        ccd21   STR     LeftAmp RightAmp
+        ccd22   STR     LeftAmp RightAmp
+        ccd23   STR     LeftAmp RightAmp
 END
 
@@ -374,68 +374,51 @@
    Haalpha.on   STR Ha
    HaOFF.MP7604 STR HaOff
-
-   CN.MP780     STR CN
-   cn.MP7803    STR CN
-   CN.MP7803    STR CN
-
-   TiO.MP77     STR TiO
-   tio.MP7701   STR TiO
-   TiO.MP7701   STR TiO
-   NB920        STR NB920
-
-   B2F          STR B2F 
-   Bj           STR Bj  
-   Vj           STR Vj  
-   Rj           STR Rj  
-   Ij           STR Ij  
-   Hb           STR Hb  
-   HbOff        STR HbOff
 END
 
 
 # Recipe options
-RECIPES		METADATA
-	# Recipes for ppImage
+RECIPES         METADATA
+        # Recipes for ppImage
         PPIMAGE         STR     megacam/ppImage.config          # Default: all (normal) options on
-	PPIMAGE_O	STR	megacam/ppImage_o.config	# Overscan only
-	PPIMAGE_OB	STR	megacam/ppImage_ob.config	# Overscan, bias only
-	PPIMAGE_OBD	STR	megacam/ppImage_obd.config	# Overscan, bias, dark only
-	PPIMAGE_OBDF	STR	megacam/ppImage_obdf.config	# Overscan, bias, dark, flat only
-	PPIMAGE_B	STR	megacam/ppImage_b.config	# Bias only
-	PPIMAGE_D	STR	megacam/ppImage_d.config	# Dark only
-	PPIMAGE_F	STR	megacam/ppImage_f.config	# Flat only
-	PPIMAGE_J1	STR	megacam/ppImage_j1.config	# JPEG only; binning 1
-	PPIMAGE_J2	STR	megacam/ppImage_j2.config	# JPEG only; binning 2
-	PPIMAGE_N	STR	megacam/ppImage_n.config	# Nothing significant; binning only
-
-	# Recipes for ppMerge
+        PPIMAGE_O       STR     megacam/ppImage_o.config        # Overscan only
+        PPIMAGE_OB      STR     megacam/ppImage_ob.config       # Overscan, bias only
+        PPIMAGE_OBD     STR     megacam/ppImage_obd.config      # Overscan, bias, dark only
+        PPIMAGE_OBDF    STR     megacam/ppImage_obdf.config     # Overscan, bias, dark, flat only
+        PPIMAGE_B       STR     megacam/ppImage_b.config        # Bias only
+        PPIMAGE_D       STR     megacam/ppImage_d.config        # Dark only
+        PPIMAGE_F       STR     megacam/ppImage_f.config        # Flat only
+        PPIMAGE_J1      STR     megacam/ppImage_j1.config       # JPEG only; binning 1
+        PPIMAGE_J2      STR     megacam/ppImage_j2.config       # JPEG only; binning 2
+        PPIMAGE_N       STR     megacam/ppImage_n.config        # Nothing significant; binning only
+
+        # Recipes for ppMerge
         PPMERGE         STR     ppMerge_template.config         # ppMerge recipe
-	PPMERGE_BIAS	STR	megacam/ppMerge_bias.config
-	PPMERGE_DARK	STR	megacam/ppMerge_dark.config
-	PPMERGE_FLAT	STR	megacam/ppMerge_flat.config
-
-	# Other recipes
+        PPMERGE_BIAS    STR     megacam/ppMerge_bias.config
+        PPMERGE_DARK    STR     megacam/ppMerge_dark.config
+        PPMERGE_FLAT    STR     megacam/ppMerge_flat.config
+
+        # Other recipes
         PSPHOT          STR     megacam/psphot.config           # psphot details
         PSASTRO         STR     megacam/psastro.config          # psastro details
-	PPSTATS		STR	megacam/ppStats.config		# ppStats recipe
+        PPSTATS         STR     megacam/ppStats.config          # ppStats recipe
 END
 
 
 # Rejection levels for detrend creation
-REJECTION	METADATA
-	TYPE	LIMITS	FILTER	EXPECTED	IMFILE.MEAN	IMFILE.STDEV	EXP.MEAN	EXP.STDEV	EXP.MEANSTDEV	ENSEMBLE.MEAN	ENSEMBLE.STDEV	ENSEMBLE.MEANSTDEV
-	FLAT	MULTI
-
-	BIAS	LIMITS	*	0		0		15		0		15		0		0		0		0
-	DARK	LIMITS	*	0		0		0		0		0		0		0		0		0
-	FLAT	LIMITS	*	0		0		0		0		0		0		0		0		0
-	FLAT	LIMITS	u	0		0		0		0		0		0		0		0		0
-	FLAT	LIMITS	g	0		0		0		0		0		0		0		0		0
-	FLAT	LIMITS	r	0		0		0		0		0		0		0		0		0
-	FLAT	LIMITS	i	0		0		0		0		0		0		0		0		0
-	FLAT	LIMITS	z	0		0		0		0		0		0		0		0		0
-
-END
-		
+REJECTION       METADATA
+        TYPE    LIMITS  FILTER  EXPECTED        IMFILE.MEAN     IMFILE.STDEV    EXP.MEAN        EXP.STDEV       EXP.MEANSTDEV   ENSEMBLE.MEAN   ENSEMBLE.STDEV  ENSEMBLE.MEANSTDEV
+        FLAT    MULTI
+
+        BIAS    LIMITS  *       0               0               15              0               15              0               0               0               0
+        DARK    LIMITS  *       0               0               0               0               0               0               0               0               0
+        FLAT    LIMITS  *       0               0               0               0               0               0               0               0               0
+        FLAT    LIMITS  u       0               0               0               0               0               0               0               0               0
+        FLAT    LIMITS  g       0               0               0               0               0               0               0               0               0
+        FLAT    LIMITS  r       0               0               0               0               0               0               0               0               0
+        FLAT    LIMITS  i       0               0               0               0               0               0               0               0               0
+        FLAT    LIMITS  z       0               0               0               0               0               0               0               0               0
+
+END
+                
 
 FILERULES METADATA
@@ -511,494 +494,445 @@
 \subsection{Contents}
 
-
-\subsection{Example}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Recipes}
-
-\subsection{Locations}
-
-Recipes may be specified in a number of locations.  Firstly, they may
-be specified on the command line with the \code{-recipe} option,
-giving a symbolic name and a filename or another symbolic name to link
-to.  In addition, they may be specified in the site configuration and
-the camera configuration under the \code{RECIPES} metadata.  Note that
-the \code{PATH(STR)} in the site configuration defines the search paths for
-these files.
-
-\subsection{Contents}
-
-\subsection{Example}
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Revision Change Log}
-%\input{ChangeLog.tex}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%\bibliographystyle{plain}
-%\bibliography{panstarrs}
-
-\end{document}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-\subsubsection{Camera configuration}
-
-The camera configuration file is a fairly simple configuration file
-containing information particular to a particular camera, regardless
-of the file format used to represent that camera.  The camera configuration
-consists of the following elements:
+The camera format specifies how a FITS file from a particular camera
+is to be read.  Different formats may be defined for a single camera
+(e.g., one amplifier per extension, vs all amplifiers spliced together
+in the PHU).  The camera format configuration file contains the rules
+for recognising the format, how to read the file, the contents of a
+FITS file, data appropriate to different types of cells, information
+on how to determine the concepts from the headers, default values, or
+database, and expected formats for certain concepts.
+
+\subsubsection{Rules for recognising}
+
+\code{RULE(METADATA)} contains a list of telescope headers with
+expected values (of the appropriate type) for this particular
+combination of the camera and format.  It is often useful to include
+\code{TELESCOP} and \code{DETECTOR}, if possible, along with any other
+headers that uniquely identify the camera and format.  Note that all
+of the headers must match exactly (modulo leading and trailing spaces
+for strings), including the data type and value, for the rule to
+match, and that the first format's rule to match is accepted.  If a
+rule doesn't match the header, try adjusting the types (especially for
+numerical types; try S32 for integers, F32 and F64 for floats).
+
+\subsubsection{How to read the file}
+
+\code{FILE(METADATA)} contains information on how to read the FITS
+file for this format.  The contents are:
 \begin{itemize}
-\item \code{FORMATS} of type \code{METADATA}: this contains a list of
-  known FITS file formats with the file names (of type \code{STR}) of
-  the configuration files;
-\item \code{FPA} of type \code{METADATA}: this contains a list of
-  chips, each with a string list (type \code{STR} of the component
-  cells; and
-\item \code{RECIPES} of type \code{METADATA}: this contains a list of
-  recipes used for the camera with the file names (of type \code{STR}
-  of the configuration files.
+\item \code{PHU(STR)} identifies the class of the file --- what level
+  in the focal plane hierarchy the primary header unit (PHU) of this
+  file belongs.  Legal values are \code{FPA}, \code{CHIP} or
+  \code{CELL}.
+\item \code{EXTENSIONS(STR)} identifies what level in the focal plane
+  hierarchy the extensions belong.  Legal values are \code{CHIP},
+  \code{CELL} or \code{NONE} (if there are no extensions).
+\item \code{FPA.NAME(STR)} specifies a PHU header keyword for a unique
+  identifier for the FPA.  This is usually an exposure number, or
+  similar.  The purpose is to identify the FPA, so that only files
+  with the same value of \code{FPA.NAME} can be admitted to the same
+  FPA structure.
+\item \code{CHIP.NAME(STR)} (necessary if \code{PHU} is \code{CHIP} or
+  \code{CELL}) specifies a PHU header keyword that identifies the name
+  of the chip.  The purpose is to identify to which chip in the
+  hierarchy the file belongs.
+\item \code{CELL.NAME(STR)} (necessary if \code{PHU} is \code{CELL})
+  specifies a PHU header keyword that identifies the name of the cell
+  within the chip.  The purpose is to identify to which cell in the
+  hierarchy the file belongs.
+\item \code{CONTENT(STR)} (necessary if \code{EXTENSIONS} is
+  \code{NONE} and \code{PHU} is \code{CHIP} or \code{CELL}) specifies
+  a key to the \code{CONTENTS} menu (see below).  The purpose is to
+  identify the contents of the file (in terms of its FPA hierarchy
+  components).  The string has concepts interpolated, where these are
+  enclosed in curly brackets (currently \code{CHIP.NAME} and
+  \code{CELL.NAME} only; \tbd{future concepts may be permitted in the
+  future if there exists sufficient demand}.  This allows such a
+  construct as \code{\{CHIP.NAME\}_\{CELL.NAME\}} to identify a
+  combination of chip and cell.
 \end{itemize}
 
-An example camera configuration file:
+\subsubsection{File contents}
+
+The exact meaning of the \code{CONTENTS} (as well as the type) depends
+on the value of \code{PHU} and \code{EXTENSIONS} in the \code{FILE}
+metadata.  In each case, we rely on the use of \code{chip:cell:type}
+triplets to identify the contents.  These are used to identify the
+contents of an extension: the chip and cell to which a component
+belongs, and the type of the cell (see \S\ref{sec:cell_data} for cell
+types), with the symbolic names separated by colons.  The triplets may
+be listed one after the other, separated by whitespace, where an
+extension contains more than one cell.
+
+\begin{itemize}
+\item If \code{PHU} is \code{FPA} and \code{EXTENSIONS} is
+  \code{NONE}, then \code{CONTENTS} is of type \code{STR}, and
+  contains a string of \code{chip:cell:type} triplets.
+\item If \code{PHU} is \code{CHIP} or \code{CELL} and
+  \code{EXTENSIONS} is \code{NONE}, then \code{CONTENTS} is of type
+  \code{METADATA}, and contains a menu of possible contents.  Each
+  menu item is of type \code{STR}, and consists of a string of
+  \code{chip:cell:type} triplets.  The menu key is provided by the
+  interpolated \code{CONTENT} value within the \code{FILE} metadata.
+\item In all other cases, \code{CONTENTS} is of type \code{METADATA},
+  and contains a list of extension names within the file, with the
+  values of type \code{STR} consisting of a string of
+  \code{chip:cell:type} triplets.
+\end{itemize}
+
+\subsubsection{Cell data}
+\label{sec:cell_data}
+
+\code{CELLS(METADATA)} contains a list of cell types, with concepts
+particular to those types.  Each type, which corresponds to a type
+specified in the \code{CONTENTS}, is of type \code{METADATA}.  The
+contents of these metadata are values for concepts that are particular
+to that cell type (e.g., left amplifier vs right amplifier).  Usually
+\code{CELL.TRIMSEC(STR)} and \code{CELL.BIASSEC(STR)} will be listed
+here, since these differ according to the cell type.  Since there is
+ambiguity in what the values here refer to (if the concept is of type
+\code{STR}), we also require an additional entry with \code{.SOURCE}
+suffixed to the concept name, with the value (of type \code{STR})
+being \code{VALUE} to indicate that the concept is specified by value,
+or \code{HEADER} to indicate that the concept is specified in the
+header of the given name.
+
+[It might be thought that there is no need to provide the ability to
+look up headers here, since it is provided below.  However, the header
+name may vary depending on the cell type.  For example, the Megacam
+spliced format uses \code{TSECA} and \code{TSECB} to specify the trim
+sections for the left and right amplifiers.]
+
+\subsubsection{Concepts from headers}
+
+\code{TRANSLATION(METADATA)} contains a list of concepts that have
+their values ingested from the FITS headers.  Each concept name should
+have type \code{STR}, with the value being the header name from which
+the concept is ingested.  No distinction is made between the PHU and
+extension headers, but inheritance (look at the PHU if it's not in the
+extension header) should be the normal behaviour.  Multiple headers
+may be given for certain concepts:
+\begin{itemize}
+\item \code{FPA.TIME} and \code{CELL.TIME} to specify the date and
+  time in separate headers
+\item \code{CELL.BIASSEC} to specify multiple bias regions (e.g., a
+  prescan and an overscan).
+\end{itemize}
+
+\tbd{TRANSLATION is a poor name (it's supposed to be a header
+translation table); HEADERS would be better.}
+
+\subsubsection{Concepts from default values}
+
+\code{DEFAULTS(METADATA)} contains a list of concepts with their
+default values (of the appropriate types).  A concept may have type
+\code{METADATA}, in which case the metadata acts as a menu.  The menu
+key is determined from an additional entry in the \code{DEFAULTS},
+formed from the concept name suffixed with \code{.DEPEND}, which must
+be of type \code{STR} and contain a concept name.  The value of this
+extra concept determines the menu key.  This allows dependence on the
+chip (e.g., depending on \code{CHIP.NAME}) or cell (\code{CELL.NAME}),
+which is useful for setting things such as \code{CHIP.X0} when it is
+not contained in the header.
+
+\subsubsection{Concepts from database}
+
+\tbd{Database lookup for concepts has never been tested.  In fact, the
+current implementation probably doesn't even match this description.}
+
+\code{DATABASE(METADATA)} contains a list of concepts whose values are
+determined from database lookup.  Each concept is of type
+\code{METADATA}.  Each concept metadata must contain the entries
+\code{TABLE(STR)} and \code{COLUMN(STR)}, which specify the database
+table to use, and the column within that table.  Additional entries
+provide the \code{WHERE} part of the database query.
+
+
+\subsubsection{Formats for concepts}
+
+\code{FORMATS(METADATA)} contains a list of concepts that require
+additional information in order to parse.  Each concept name contains
+a value of type \code{STR} which is a list of options for parsing the
+concept.
+
+Concepts which require formats:
+\begin{itemize}
+\item \code{FPA.RA} and \code{FPA.DEC}: the format specifies the units
+  --- \code{HOURS}, \code{DEGREES} or \code{RADIANS}.  \code{FPA.RA}
+  defaults to \code{HOURS}, and \code{FPA.DEC} defaults to
+  \code{DEGREES}.
+\item \code{FPA.TIME} and \code{CELL.TIME}: \code{USA} indicates that
+  the date format is mm-dd-yyyy; \code{BACKWARDS} indicates that the
+  date format is dd-mm-yyyy; \code{PRE2000} indicates that a two-digit
+  date is used (1900 years is added if the year is less than 100);
+  \code{MJD} indicates the date is a modified julian date; \code{JD}
+  indicates the date is a julian date.
+\item \code{CELL.X0}, \code{CELL.Y0}, \code{CHIP.X0} and
+  \code{CHIP.Y0}: \code{FORTRAN} indicates that the corner corresponds
+  to corner (1,1); if missing, assumes that the corner is at (0,0).
+\end{itemize}
+
+\subsubsection{Default concepts}
+
+Default concepts that should be included in each camera format file,
+either in the \code{CELLS}, \code{TRANSLATION}, \code{DEFAULTS} or
+\code{DATABASE}:
+\begin{itemize}
+\item \code{FPA.CAMERA}: Camera used
+\item \code{FPA.FOCUS}: Telescope focus
+\item \code{FPA.AIRMASS}: Airmass at boresight
+\item \code{FPA.FILTER}: Filter used
+\item \code{FPA.POSANGLE}: Position angle of instrument
+\item \code{FPA.RADECSYS}: Celestial coordinate system
+\item \code{FPA.RA}: Right Ascension of boresight
+\item \code{FPA.DEC}: Declination of boresight
+\item \code{FPA.OBSTYPE}: Type of observation
+\item \code{FPA.OBJECT}: Object of observation
+\item \code{FPA.ALT}: Altitude of telescope
+\item \code{FPA.AZ}: Azimuth of telescope
+\item \code{FPA.TIMESYS}: Time system
+\item \code{FPA.TIME}: Time of exposure
+\item \code{CHIP.XPARITY}: Orientation in x compared to the rest of the FPA
+\item \code{CHIP.YPARITY}: Orientation in y compared to the rest of the FPA
+\item \code{CHIP.X0}: Position of (0,0) on the FPA
+\item \code{CHIP.Y0}: Position of (0,0) on the FPA
+\item \code{CHIP.TEMP}: Temperature of chip
+\item \code{CELL.GAIN}: CCD gain (e/count)
+\item \code{CELL.READNOISE}: CCD read noise (e)
+\item \code{CELL.SATURATION}: Saturation level (counts)
+\item \code{CELL.BAD}: Bad level (counts)
+\item \code{CELL.XPARITY}: Orientation in x compared to the rest of the chip
+\item \code{CELL.YPARITY}: Orientation in y compared to the rest of the chip
+\item \code{CELL.READDIR}: Read direction, rows=1, cols=2
+\item \code{CELL.EXPOSURE}: Exposure time (sec)
+\item \code{CELL.DARKTIME}: Time since flush (sec)
+\item \code{CELL.TRIMSEC}: Trim section
+\item \code{CELL.BIASSEC}: Bias sections
+\item \code{CELL.XBIN}: Binning in x
+\item \code{CELL.YBIN}: Binning in y
+\item \code{CELL.TIMESYS}: Time system
+\item \code{CELL.TIME}: Time of exposure
+\item \code{CELL.X0}: Position of (0,0) on the chip
+\item \code{CELL.Y0}: Position of (0,0) on the chip
+\end{itemize}
+
+In addition, \code{FPA.NAME}, \code{CHIP.NAME} and \code{CELL.NAME}
+are included automatically, based on the \code{FILE} and
+\code{CONTENTS} metadatas.
+
+\subsection{Examples}
+
+\subsubsection{Megacam (short) raw}
 
 \begin{verbatim}
-# Camera configuration file for MegaCam: describes the camera
-
-# File formats that we know about
-FORMATS		METADATA
-	RAW	STR	megacam_raw.config
-	SPLICE	STR	megacam_splice.config
-	SPLIT	STR	megacam_split.config
-END
-
-
-# Description of camera --- all the chips and the cells that comprise them
-FPA	METADATA
-	ccd00	STR	left right
-	ccd01	STR	left right
-	ccd02	STR	left right
-	ccd03	STR	left right
-	ccd04	STR	left right
-	ccd05	STR	left right
-	ccd06	STR	left right
-	ccd07	STR	left right
-	ccd08	STR	left right
-	ccd09	STR	left right
-	ccd10	STR	left right
-	ccd11	STR	left right
-	ccd12	STR	left right
-	ccd13	STR	left right
-	ccd14	STR	left right
-	ccd15	STR	left right
-	ccd16	STR	left right
-	ccd17	STR	left right
-	ccd18	STR	left right
-	ccd19	STR	left right
-	ccd20	STR	left right
-	ccd21	STR	left right
-	ccd22	STR	left right
-	ccd23	STR	left right
-	ccd24	STR	left right
-	ccd25	STR	left right
-	ccd26	STR	left right
-	ccd27	STR	left right
-	ccd28	STR	left right
-	ccd29	STR	left right
-	ccd30	STR	left right
-	ccd31	STR	left right
-	ccd32	STR	left right
-	ccd33	STR	left right
-	ccd34	STR	left right
-	ccd35	STR	left right
-END
-
-
-# Recipe options
-RECIPES		METADATA
-	PHASE2		STR	phase2.config		# Phase 2 recipe details
-	PSPHOT		STR	psphot.config		# psphot details
+# "mcshort" is a MegaCam camera with only the central six chips --- it's faster than the entire FPA.
+# The raw MegaCam data comes off the telescope with each of the chips stored in extensions of a MEF file.
+
+# How to identify this type
+RULE    METADATA
+        TELESCOP        STR     CFHT 3.6m
+        DETECTOR        STR     MegaCam
+        EXTEND          BOOL    T
+        NEXTEND         S32     72
+END
+
+# How to read this data
+FILE    METADATA
+        PHU             STR     FPA     # The FITS file represents an entire FPA
+        EXTENSIONS      STR     CELL    # The extensions represent cells
+        FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier within the hierarchy level
+END
+
+# What's in the FITS file?
+CONTENTS        METADATA
+        # Extension name, chip:cell:type
+        amp24           STR     ccd12:LeftAmp:left
+        amp25           STR     ccd12:RightAmp:right
+        amp26           STR     ccd13:LeftAmp:left
+        amp27           STR     ccd13:RightAmp:right
+        amp28           STR     ccd14:LeftAmp:left
+        amp29           STR     ccd14:RightAmp:right
+        amp42           STR     ccd21:LeftAmp:left
+        amp43           STR     ccd21:RightAmp:right
+        amp44           STR     ccd22:LeftAmp:left
+        amp45           STR     ccd22:RightAmp:right
+        amp46           STR     ccd23:LeftAmp:left
+        amp47           STR     ccd23:RightAmp:right
+END
+
+# Specify the cell data
+CELLS   METADATA
+        left    METADATA        # Left amplifier
+                CELL.BIASSEC.SOURCE     STR     HEADER
+                CELL.TRIMSEC.SOURCE     STR     HEADER
+                CELL.BIASSEC            STR     BIASSEC
+                CELL.TRIMSEC            STR     DATASEC
+                CELL.XPARITY            S32     1 # We could have specified this as a DEFAULT, but this works
+                CELL.X0                 S32     1
+        END
+        right   METADATA        # Right amplifier
+                CELL.BIASSEC.SOURCE     STR     HEADER
+                CELL.TRIMSEC.SOURCE     STR     HEADER
+                CELL.BIASSEC            STR     BIASSEC
+                CELL.TRIMSEC            STR     DATASEC
+                CELL.XPARITY            S32     -1 # This cell is read out in the opposite direction
+                CELL.X0                 S32     2048
+        END
+END
+
+# How to translate PS concepts into FITS headers
+TRANSLATION     METADATA
+        FPA.NAME                STR     EXPNUM
+        FPA.AIRMASS             STR     AIRMASS
+        FPA.FILTER              STR     FILTER
+        FPA.POSANGLE            STR     ROTANGLE
+        FPA.RA                  STR     RA
+        FPA.DEC                 STR     DEC
+        FPA.RADECSYS            STR     RADECSYS
+        FPA.OBSTYPE             STR     OBSTYPE
+        FPA.OBJECT              STR     CMMTOBS
+        FPA.TIME                STR     MJD-OBS
+        FPA.TIMESYS             STR     TIMESYS
+        FPA.ALT                 STR     TELALT
+        FPA.AZ                  STR     TELAZ
+        CHIP.TEMP               STR     DETTEM
+        CELL.EXPOSURE           STR     EXPTIME
+        CELL.DARKTIME           STR     DARKTIME
+        CELL.GAIN               STR     GAIN
+        CELL.READNOISE          STR     RDNOISE
+        CELL.SATURATION         STR     SATURATE
+        CELL.TIME               STR     MJD-OBS
+        CELL.TIMESYS            STR     TIMESYS
+        CELL.XBIN               STR     CCDBIN1
+        CELL.YBIN               STR     CCDBIN2
+END
+
+# Default PS concepts that may be specified by value
+DEFAULTS        METADATA
+        CELL.READDIR            S32     1               # Cell is read in x direction
+        CELL.BAD                S32     0
+        CELL.YPARITY            S32     1
+        CELL.Y0                 S32     1
+
+        CHIP.X0.DEPEND          STR     CHIP.NAME
+        CHIP.X0         METADATA
+                ccd12   S32     6144
+                ccd13   S32     8192
+                ccd14   S32     10240
+                ccd21   S32     6144
+                ccd22   S32     8192
+                ccd23   S32     10240
+        END
+        CHIP.Y0.DEPEND          STR     CHIP.NAME
+        CHIP.Y0         METADATA
+                ccd12   S32     13835
+                ccd13   S32     13835
+                ccd14   S32     13835
+                ccd21   S32     4612
+                ccd22   S32     4612
+                ccd23   S32     4612
+        END
+        CHIP.XPARITY.DEPEND     STR     CHIP.NAME
+        CHIP.XPARITY    METADATA
+                ccd12   S32     1
+                ccd13   S32     1
+                ccd14   S32     1
+                ccd21   S32     1
+                ccd22   S32     1
+                ccd23   S32     1
+        END
+        CHIP.YPARITY.DEPEND     STR     CHIP.NAME
+        CHIP.YPARITY    METADATA
+                ccd12   S32     -1
+                ccd13   S32     -1
+                ccd14   S32     -1
+                ccd21   S32     1
+                ccd22   S32     1
+                ccd23   S32     1
+        END
+END
+
+# How to translate PS concepts into database lookups
+DATABASE        METADATA
+        TYPE            dbLookup        TABLE           COLUMN          chipId          cellId
+#       CHIP.TEMP       METADATA
+#               TABLE   STR     Cryostat
+#               COLUMN  STR     temp
+#               chipId  STR     {CHIP.NAME}
+#               time    STR     {CELL.TIME}
+#       END
+#       CELL.GAIN       dbLookup        Camera          gain            CHIP.NAME       CELL.NAME
+#       CELL.READNOISE  dbLookup        Camera          readNoise       CHIP.NAME       CELL.NAME
+END
+
+
+# Where there might be some ambiguity, specify the format
+FORMATS         METADATA
+        FPA.RA          STR     HOURS
+        FPA.DEC         STR     DEGREES
+        FPA.TIME        STR     MJD
+        CELL.TIME       STR     MJD
+        CELL.X0         STR     FORTRAN
+        CELL.Y0         STR     FORTRAN
 END
 \end{verbatim}
 
-
-\subsubsection{FITS file format}
-
-The FITS file format configuration files are somewhat complicated and
-involved, since they must not only specify how to translate the pixels
-from a FITS file into a focal plane hierarchy
-(\S\ref{sec:focalplane}), but must also specify how to derive the
-various values the IPP needs (\S\ref{sec:concepts}).  Moreover, they
-must be able to do these for the great variety of cameras in use in
-the astronomical community.
-
-Example camera configuration files are included in an appendix, but
-below we explain the components.
-
-\paragraph{FITS File to Focal Plane Hierarchy}
-
-The Focal Plane hierarchy (\code{pmFPA, pmChip, pmCell, pmReadout}) is
-explained in more detail in \S\ref{sec:focalplane}.  The top level, an
-FPA contains one or more chips, which correspond to a contiguous piece
-of silicon.  A chip contains one or more cells, which correspond to a
-single amplifier.  A cell contains one or more readouts, which
-correspond to individual reads of the detector.
-
-The FITS data storage formation is a standard in the astronomical
-community for storing astronomical images.  A FITS file consists of an
-arbitrary number of coupled human readable \code{ASCII} header
-segments and binary data segments.  The headers describe the format
-and layout of the data segments.  The first of these groups is
-traditionally called the ``primary header unit'' (PHU) and the rest are
-referred to as ``extensions''.  The header segments may contain
-extensive documentary information related to the interpretation of the
-data.  Although the FITS format defines a standard representation of
-the data, the header metadata is not so consistently defined within
-the astronomical community.  Also, the flexibility of the data format
-means that different representations are possible for the same
-fundamental collection of data.  The tools presented in this section
-provide a method to define and constrain the wide range of possible
-FITS representations of astronomical images.
-
-Within the FITS data representation, there are various choices which
-can and have been made for the placement of the pixels in the file.
-In the simplest case, the camera consists of a single chip consisting
-of a single cell always read with a single readout.  In this case, the
-image data could be written as part of the primary header unit.  In a
-more complex case with multiple chips and multiple cells, the data may
-be organized in several ways.  The data may be distributed into
-multiple files or in multiple FITS data extensions.  A single camera
-image may be written as a collection of files for individual chips
-with separate extensions for each cell (CFH12K.split, GPC).  Another
-camera may write a single file with multiple extensions for each cell
-(Megacam.raw), or multiple extensions per chip, with each cell
-representing portions of the chip image (Megacam.splice, CFHT-IR).
-
-In all of these representations, there are only two basic distinctions
-in how the pixel data is stored: what level in the hierarchy the
-entire FITS file corresponds to (FPA, chip, or cell), and what level
-the extensions correspond to (chip, cell or no extensions at all).
-Knowing these, and having a list of the extensions, we can construct
-the focal plane hierarchy.
-
-Note that a single data extension, consisting of a uniform grid of
-pixels, can only naturally represent a cell or a chip.  In order to
-represent the entire focal plane array as a single grid, some
-artificial choices would be made to fill-in or ignore the gaps between
-chips and their relative rotations.  Within our framework, a complete
-focal plane mosaic of multiple chips could be represented as a single
-extension by treating the collection of pixels as if they were from a
-single chip.  
-
-To define the hierarchy, we specify the following keywords:
-\begin{itemize}
-\item \code{RULE} of type \code{METADATA}: contains headers with their
-  respective values that are required to be in the PHU of any FITS
-  file of this type.
-
-\item \code{FILE} of type \code{METADATA}: contains information on
-  the global format of the FITS file with the following entries:
-  \begin{itemize}
-  \item \code{PHU} of type \code{STR}: May be one of \code{FPA},
-    \code{CHIP}, or \code{CHIP}.  This specifies the focal plane level
-    of the Primary Header Unit, and hence the entire FITS file (the
-    'class' of the file).
-
-  \item \code{EXTENSIONS} of type \code{STR}: May be one of
-    \code{CHIP}, \code{CELL} or \code{NONE}, though not of a level
-    higher than that specified by the \code{PHU}.  This specifies what
-    each extension represents.
-
-  \item \code{FPA.NAME} of type \code{STR}: Specifies a header keyword
-    in the primary header for a unique identifier for the FPA name
-    (e.g., an observation number).
-
-  \item \code{CHIP.NAME} of type \code{STR}: Need only be included if
-    \code{PHU} is \code{CHIP} or \code{CELL}.  Specifies a header
-    keyword in the primary header for a unique identifier for the chip
-    name (e.g., the CCD identification number or name).
-
-  \item \code{CELL.NAME} of type \code{STR}: Need only be included if
-    \code{PHU} is \code{CELL}.  Specifies a header keyword in the
-    primary header for a unique identifier for the cell name (e.g.,
-    the amplifier identification).
-  \end{itemize}
-
-\item \code{CONTENTS} of type \code{METADATA}: Specifies what the
-  contents of the FITS file are.  Each entry is an extension name with
-  the corresponding value being a string listing the source and the
-  cell type, separated by a colon (e.g., \code{ccd01:left
-  ccd01:right}).  If \code{EXTENSIONS=NONE} then the \code{CONTENTS}
-  is ignored (since there are no extensions to list).
-
-\item \code{CELLS} of type \code{METADATA}: specifies the cell types.
-  Entries are the cell types, each of type \code{METADATA}, with the
-  values being PS concept values appropriate for each cell type (more
-  detail later) \tbd{link to more detail}.  In the event that
-  \code{EXTENSIONS=NONE}, the \code{CELLS} is used as a list of all
-  cells present in the file.
-
-\item \code{TRANSLATION} of type \code{METADATA}
-
-\item \code{DEFAULTS} of type \code{METADATA}
-
-\item \code{DATABASE} of type \code{METADATA}
-
-\item \code{FORMATS} of type \code{METADATA}
-
-\end{itemize}
-
-An example:
+\subsubsection{Megacam (short) split}
 
 \begin{verbatim}
-# The raw MegaCam data comes off the telescope with each of the chips stored in extensions of a MEF file.
-
-# How to identify this type
-RULE	METADATA
-	TELESCOP	STR	CFHT 3.6m
-	DETECTOR	STR	MegaCam
-	EXTEND		BOOL	T
-	NEXTEND		S32	72
-END
-
-# How to read this data
-FORMAT	METADATA
-	PHU		STR	FPA	# The FITS file represents an entire FPA
-	EXTENSIONS	STR	CELL	# The extensions represent cells
-	FPA.NAME	STR	EXPNUM	# A PHU keyword for unique identifier within the hierarchy level
+# "mcshort" is a MegaCam camera with only the central six chips --- it's faster than the entire FPA.
+# The spliced MecaCam data is stored in single extensions for each chip
+
+# How to recognise this type
+RULE    METADATA
+        TELESCOP        STR     CFHT 3.6m
+        DETECTOR        STR     MegaCam
+        # No particular distinguishing features apart from these, so we list this format last
+        # in the camera configuration file.
+END
+
+FILE    METADATA
+        # How to read this data
+        PHU             STR     CHIP    # The FITS file represents an entire FPA
+        EXTENSIONS      STR     NONE    # The extensions represent chips
+        FPA.NAME        STR     EXPNUM  # A PHU keyword for unique identifier
+        CHIP.NAME       STR     EXTNAME # An extension keyword for unique identifie
+        CONTENT         STR     {CHIP.NAME} # Key to the CONTENTS menu
 END
 
 # What's in the FITS file?
-CONTENTS	METADATA
-	# Extension name, chip name:type
-	amp00		STR	ccd00:left
-	amp01		STR	ccd00:right
-	amp02		STR	ccd01:left
-	amp03		STR	ccd01:right
-	amp04		STR	ccd02:left
-	amp05		STR	ccd02:right
-	amp06		STR	ccd03:left
-	amp07		STR	ccd03:right
-	amp08		STR	ccd04:left
-	amp09		STR	ccd04:right
-	amp10		STR	ccd05:left
-	amp11		STR	ccd05:right
-	amp12		STR	ccd06:left
-	amp13		STR	ccd06:right
-	amp14		STR	ccd07:left
-	amp15		STR	ccd07:right
-	amp16		STR	ccd08:left
-	amp17		STR	ccd08:right
-	amp18		STR	ccd09:left
-	amp19		STR	ccd09:right
-	amp20		STR	ccd10:left
-	amp21		STR	ccd10:right
-	amp22		STR	ccd11:left
-	amp23		STR	ccd11:right
-	amp24		STR	ccd12:left
-	amp25		STR	ccd12:right
-	amp26		STR	ccd13:left
-	amp27		STR	ccd13:right
-	amp28		STR	ccd14:left
-	amp29		STR	ccd14:right
-	amp30		STR	ccd15:left
-	amp31		STR	ccd15:right
-	amp32		STR	ccd16:left
-	amp33		STR	ccd16:right
-	amp34		STR	ccd17:left
-	amp35		STR	ccd17:right
-	amp36		STR	ccd18:left
-	amp37		STR	ccd18:right
-	amp38		STR	ccd19:left
-	amp39		STR	ccd19:right
-	amp40		STR	ccd20:left
-	amp41		STR	ccd20:right
-	amp42		STR	ccd21:left
-	amp43		STR	ccd21:right
-	amp44		STR	ccd22:left
-	amp45		STR	ccd22:right
-	amp46		STR	ccd23:left
-	amp47		STR	ccd23:right
-	amp48		STR	ccd24:left
-	amp49		STR	ccd24:right
-	amp50		STR	ccd25:left
-	amp51		STR	ccd25:right
-	amp52		STR	ccd26:left
-	amp53		STR	ccd26:right
-	amp54		STR	ccd27:left
-	amp55		STR	ccd27:right
-	amp56		STR	ccd28:left
-	amp57		STR	ccd28:right
-	amp58		STR	ccd29:left
-	amp59		STR	ccd29:right
-	amp60		STR	ccd30:left
-	amp61		STR	ccd30:right
-	amp62		STR	ccd31:left
-	amp63		STR	ccd31:right
-	amp64		STR	ccd32:left
-	amp65		STR	ccd32:right
-	amp66		STR	ccd33:left
-	amp67		STR	ccd33:right
-	amp68		STR	ccd34:left
-	amp69		STR	ccd34:right
-	amp70		STR	ccd35:left
-	amp71		STR	ccd35:right
-END
-
-# Specify the cell data
-CELLS	METADATA
-	left	METADATA	# Left amplifier
-		CELL.NAME		STR	LeftSide
-		CELL.BIASSEC.SOURCE	STR	HEADER
-		CELL.TRIMSEC.SOURCE	STR	HEADER
-		CELL.BIASSEC		STR	BIASSEC
-		CELL.TRIMSEC		STR	DATASEC
-		CELL.XPARITY		S32	1 # We could have specified this as a DEFAULT, but this works
-		CELL.X0			S32	1
-		CELL.Y0			S32	1
-	END
-	right	METADATA	# Right amplifier
-		CELL.NAME		STR	RightSide
-		CELL.BIASSEC.SOURCE	STR	HEADER
-		CELL.TRIMSEC.SOURCE	STR	HEADER
-		CELL.BIASSEC		STR	BIASSEC
-		CELL.TRIMSEC		STR	DATASEC
-		CELL.XPARITY		S32	-1 # This cell is read out in the opposite direction
-		CELL.X0			S32	2048
-		CELL.Y0			S32	1
-	END
-END
-
-# How to translate PS concepts into FITS headers
-TRANSLATION	METADATA
-	FPA.NAME		STR	EXPNUM
-	FPA.AIRMASS		STR	AIRMASS
-	FPA.FILTER		STR	FILTER
-	FPA.POSANGLE		STR	ROTANGLE
-	FPA.RA			STR	RA
-	FPA.DEC			STR	DEC
-	FPA.RADECSYS		STR	RADECSYS
-	CELL.EXPOSURE		STR	EXPTIME
-	CELL.DARKTIME		STR	DARKTIME
-	CELL.GAIN		STR	GAIN
-	CELL.READNOISE		STR	RDNOISE
-	CELL.SATURATION		STR	SATURATE
-	CELL.TIME		STR	MJD-OBS
-	CELL.XBIN		STR	CCDBIN1
-	CELL.YBIN		STR	CCDBIN2
-END
-
-# Default PS concepts that may be specified by value
-DEFAULTS	METADATA
-	CELL.READDIR		S32	1		# Cell is read in x direction
-	CELL.BAD		S32	0
-	CELL.TIMESYS		STR	UTC
-	CELL.YPARITY		S32	1
-END
-
-# How to translation PS concepts into database lookups
-DATABASE	METADATA
-	TYPE		dbEntry		TABLE		COLUMN		GIVENDBCOL	GIVENPS
-#	FPA.BIAS	METADATA
-#		TABLE	STR	Camera
-#		COLUMN	STR	gain
-#		chipId	STR	{CHIP.NAME}
-#		cellId	STR	{CELL.NAME}
-#		time	STR	{CELL.TIME}
-#	END
-#	CELL.GAIN	dbEntry		Camera		gain		chipId,cellId	CHIP.NAME,CELL.NAME
-#	CELL.READNOISE	dbEntry		Camera		readNoise	chipId,cellId	CHIP.NAME,CELL.NAME
-
-# A database entry refers to a particular column (COLUMN) in a
-# particular table (TABLE), given certain PS concepts (GIVENPS) that
-# match certain database columns (GIVENDBCOL).
-END
-
-
-# Where there might be some ambiguity, specify the format
-FORMATS		METADATA
-	FPA.RA		STR	HOURS
-	FPA.DEC		STR	DEGREES
-	CELL.TIME	STR	MJD
-#	CELL.BINNING	STR	SEPARATE
-	CELL.X0		STR	FORTRAN
-	CELL.Y0		STR	FORTRAN
-END
-\end{verbatim}
-
-Observe how the \code{CONTENTS} specifies the extension name, which we
-know from the \code{EXTENSIONS} is a cell, and that each extension is
-associated with a chip, and has a cell type.
-
-\paragraph{Deriving concept values}
-\label{sec:derivingconcepts}
-
-The PS concepts are described in more detail in \S\ref{sec:concepts}.
-Basically, astronomical cameras generally store the important details
-(``concepts'') in different ways.  This is generally manifested in the
-choice of different FITS header keywords to describe the same concept,
-but one can also imagine deriving values from a database or a known
-default.
-
-We therefore specify the following keywords:
-\begin{itemize}
-\item \code{TRANSLATION} of type \code{METADATA} is a translation
-  table for understanding PS concepts in terms of FITS headers.  The
-  PS concept (keyword) is derived from the FITS header given in the
-  value.
-\item \code{DATABASE} of type \code{METADATA} is a formula for
-  obtaining a PS concept from the database.  Each component is of a
-  user-specified type containing \code{TABLE}, \code{COLUMN},
-  \code{GIVENDBCOL} and \code{GIVENPS}.  The idea is that to obtain
-  the value of a PS concept, one refers to a particular \code{COLUMN}
-  in a particular \code{TABLE}, where the value of certain PS concepts
-  (\code{GIVENPS}; multiple values separated by a comma or semicolon)
-  match certain database columns (\code{GIVENDBCOL}; multiple values
-  separated by a comma or semicolon).
-\item \code{DEFAULTS} of type \code{METADATA} is a set of default
-  values of PS concepts for the camera.  The PS concept (keyword) is
-  assigned the value.  There is also limited dependency allowed; see
-  \S\ref{sec:concepts}.
-\end{itemize}
-
-An example:
-\begin{verbatim}
+CONTENTS        METADATA
+        # Extension name, chip:cell:type
+        ccd12           STR     ccd12:LeftAmp:left ccd12:RightAmp:right
+        ccd13           STR     ccd13:LeftAmp:left ccd13:RightAmp:right
+        ccd14           STR     ccd14:LeftAmp:left ccd14:RightAmp:right
+        ccd21           STR     ccd21:LeftAmp:left ccd21:RightAmp:right
+        ccd22           STR     ccd22:LeftAmp:left ccd22:RightAmp:right
+        ccd23           STR     ccd23:LeftAmp:left ccd23:RightAmp:right
+END
+
+# Specify the cells
+CELLS           METADATA
+        left            METADATA
+                CELL.BIASSEC.SOURCE     STR     HEADER
+                CELL.TRIMSEC.SOURCE     STR     HEADER
+                CELL.BIASSEC            STR     BSECA
+                CELL.TRIMSEC            STR     TSECA
+                CELL.X0                 S32     0
+                CELL.GAIN.SOURCE        STR     HEADER
+                CELL.GAIN               STR     GAINA
+        END
+
+        right           METADATA
+                CELL.BIASSEC.SOURCE     STR     HEADER
+                CELL.TRIMSEC.SOURCE     STR     HEADER
+                CELL.BIASSEC            STR     BSECB
+                CELL.TRIMSEC            STR     TSECB
+                CELL.X0                 S32     1024
+                CELL.GAIN.SOURCE        STR     HEADER
+                CELL.GAIN               STR     GAINB
+        END
+END
+
 # How to translate PS concepts into FITS headers
 TRANSLATION     METADATA
@@ -1010,3211 +944,116 @@
         FPA.DEC         STR     DEC
         FPA.RADECSYS    STR     RADECSYS
-        FPA.MJD         STR     MJD-OBS
+        FPA.OBSTYPE     STR     OBSTYPE
+        FPA.OBJECT      STR     CMMTOBS
+        FPA.TIME        STR     MJD-OBS
+        FPA.TIMESYS     STR     TIMESYS
+        FPA.ALT         STR     TELALT
+        FPA.AZ          STR     TELAZ
+        CHIP.TEMP       STR     DETTEM
         CELL.EXPOSURE   STR     EXPTIME
         CELL.DARKTIME   STR     DARKTIME
+        CELL.READNOISE  STR     RDNOISE
+        CELL.SATURATION STR     SATURATE
+        CELL.TIME       STR     MJD-OBS
+        CELL.TIMESYS    STR     TIMESYS
         CELL.XBIN       STR     CCDBIN1
         CELL.YBIN       STR     CCDBIN2
-        CELL.SATURATION STR     SATURATE
 END
 
 # Default PS concepts that may be specified by value
 DEFAULTS        METADATA
+        CELL.READDIR            S32     1               # Cell is read in x direction
         CELL.BAD                S32     0
-        CELL.PARITY.DEPEND      STR     CHIP.NAME
-        CELL.PARITY    METADATA
-                amp00   S32     1
-                amp01   S32     -1
-                amp02   S32     1
-                amp03   S32     -1
+        CELL.XPARITY            S32     1
+        CELL.YPARITY            S32     1
+        CELL.Y0                 S32     0
+#       PPMERGE.SCALE           F32     1.0
+#       PPMERGE.ZERO            F32     0.0
+        CHIP.X0.DEPEND          STR     CHIP.NAME
+        CHIP.X0         METADATA
+                ccd12   S32     0
+                ccd13   S32     2048
+                ccd14   S32     4096
+                ccd21   S32     0
+                ccd22   S32     2048
+                ccd23   S32     4096
         END
-END
-
-# How to translate PS concepts into database lookups
+        CHIP.Y0.DEPEND          STR     CHIP.NAME
+        CHIP.Y0         METADATA
+                ccd12   S32     9223
+                ccd13   S32     9223
+                ccd14   S32     9223
+                ccd21   S32     0
+                ccd22   S32     0
+                ccd23   S32     0
+        END
+        CHIP.XPARITY.DEPEND     STR     CHIP.NAME
+        CHIP.XPARITY    METADATA
+                ccd12   S32     1
+                ccd13   S32     1
+                ccd14   S32     1
+                ccd21   S32     1
+                ccd22   S32     1
+                ccd23   S32     1
+        END
+        CHIP.YPARITY.DEPEND     STR     CHIP.NAME
+        CHIP.YPARITY    METADATA
+                ccd12   S32     -1
+                ccd13   S32     -1
+                ccd14   S32     -1
+                ccd21   S32     1
+                ccd22   S32     1
+                ccd23   S32     1
+        END
+END
+
+
+# How to translation PS concepts into database lookups
 DATABASE        METADATA
-        TYPE            dbEntry         TABLE           COLUMN          GIVENDBCOL      GIVENPS
-        CELL.GAIN       dbEntry         Camera          gain            chipId,cellId   CHIP.NAME,CELL.NAME
-        CELL.READNOISE  dbEntry         Camera          readNoise       chipId,cellId   CHIP.NAME,CELL.NAME
+# None
+END             
+
+
+# Where there might be some ambiguity, specify the format
+FORMATS         METADATA
+        FPA.RA          STR     HOURS
+        FPA.DEC         STR     DEGREES
+        FPA.TIME        STR     MJD
+        CELL.TIME       STR     MJD
 END
 \end{verbatim}
 
-The \code{.DEPEND} entry in the \code{DEFAULTS} will be explained in
-\S\ref{sec:concepts}.
-
-\paragraph{Indentification by rule}
-\label{sec:camerarule}
-
-The function \code{pmConfigCameraFromHeader} requires that the camera
-configuration also contains a rule on how to recognise that a FITS
-header comes from that camera.
-
-We therefore specify another keyword: \code{RULE} of type
-\code{METADATA}: Contains a list of FITS headers keywords and values
-(of the appropriate type) against which actual headers are compared to
-determine if it matches the camera type.
-
-An example is:
+\subsubsection{Imaging Sky Probe}
+
 \begin{verbatim}
+# Pan-STARRS Imaging Sky Probe
+
 # How to identify this type
 RULE    METADATA
-        TELESCOP        STR     CFHT 3.6m
-        DETECTOR        STR     MegaCam
-        EXTEND          BOOL    T
-        NEXTEND         S32     72
-END
-\end{verbatim}
-
-\paragraph{Recipes}
-
-The camera configuration file must also contain filenames for the
-recipe configuration files.  We include \code{RECIPES} of type
-\code{METADATA} with component keywords being the various recipe names
-and the values (of type \code{STR}) the corresponding recipe
-configuration filename.
-
-An example:
-\begin{verbatim}
-# Recipes for LRIS
-RECIPES METADATA
-        PHASE1          STR     lris_phase1.config
-        PHASE2          STR     lris_phase2.config
-        PHASE4          STR     lris_phase4.config
-END
-\end{verbatim}
-
-\subsubsection{Recipe Configuration}
-
-\tbd{The contents of the recipe configuration file are dependent upon
-the particular module, and hence are not specified here at this time.}
-
-
-\subsection{PS Concepts}
-
-\subsubsection{Ingest}
-
-For different camera systems, these concepts are not always known by
-the same name, nor are they generally obtained in the same manner, and
-so their source or value must be specified in the camera configuration
-file.  At ingest, the value of a concept shall be found by searching in
-the following order:
-\begin{itemize}
-\item The cell data from the \code{CELLS} metadata in the camera configuration.
-\item The FITS header via the \code{TRANSLATION} table.
-\item The \code{DATABASE} lookup.
-\item The \code{DEFAULTS} value.
-\end{itemize}
-
-\subsubsection{Dependencies for defaults}
-
-In the \code{DEFAULTS} table in the camera configuration, we allow the
-specification of the concept with an additional suffix, \code{DEPEND}.
-The value (of type \code{STR}) of the \code{CONCEPT.DEPEND} is the
-name of a concept on which the first concept depends.  For example, it
-might depend on the chip name.  Then the first concept becomes of type
-\code{METADATA}, with the component keywords being the value of the
-second concept (on which the first depends).  To avoid infinite
-recursion, no further dependency is permitted.  We also allow an entry
-\code{CONCEPT.DEFAULT} specifiying the default value of the concept if
-a match is not made with the dependcency list.  An example of the
-dependency:
-
-\begin{verbatim}
-# Default PS concepts that may be specified by value
-DEFAULTS        METADATA
-        CELL.GAIN.DEPEND     STR     CHIP.NAME
-        CELL.GAIN.DEFAULT    STR     1.0
-        CELL.GAIN    METADATA
-                ccd00   F32     1.2
-                ccd01   F32     3.4
-                ccd02   F32     5.6
-        END
-END
-\end{verbatim}
-
-\subsubsection{FORMATS}
-
-Because of the variety of methods for specifying these concepts
-(especially in FITS headers), we must also specify additional
-information in the camera configuration that specifies how to
-interpret the data provided.  These are provided in an entry
-\code{FORMATS} (of type \code{METADATA}) in the camera configuration.
-Within the \code{FORMATS} metadata, there is a string for each of the
-concepts that requires a format to be specified.
-
-\paragraph{CELL.TIME}
-
-The time at which the shutter opens is represented in a variety of
-ways in FITS files, so care must be taken to specify what the format
-is in the file under consideration.  Permitted values of
-\code{CELL.TIME.FORMAT} are:
-
-\begin{itemize}
-\item \code{JD}: The value pointed to by \code{CELL.TIME} is to be
-  interpreted as a Julian Date.
-\item \code{MJD}: The value pointed to by \code{CELL.TIME} is to be
-  interpreted as a Modified Julian Date.
-\item \code{ISO}: The value pointed to by \code{CELL.TIME} is to be
-  interpreted as an ISO date-time (yyyy-mm-ddThh:mm:ss.ss).
-\item \code{SEPARATE}: The date and time are specified separately, and
-  the \code{CELL.TIME} contains the headers for the date and the time
-  separated by whitespace or a comma.  Then it is necessary to add
-  additional qualifiers to specify the formats of these:
-  \begin{itemize}
-  \item \code{PRE2000}: The year is in the old style two-digit format
-    popular before the year 2000, and it should be assumed that the
-    date is in the twentieth century.
-  \item \code{BACKWARDS}: The date is in the format dd-mm-yyyy or
-    dd/mm/yyyy.
-  \item \code{SOD}: The time is specified as seconds-of-day.
-  \end{itemize}
-\end{itemize}
-
-Note that the FITS standard is that the time in the header refers to
-the {\it start} of the observation.  
-
-\tbd{the PRE2000 and BACKWARDS qualifiers should be replace with
-explicit format definitions in the form YYYY/MM/DD}
-
-\tbd{In the future, we might add additional qualifiers that calculate
-the start time of the observation based on someone foolishly putting
-the end- or mid-time in the header.}
-
-\tbd{Should we move CELL.TIMESYS into the format as well?}
-
-\paragraph{FPA.RA and FPA.DEC}
-
-The RA and Declination of the boresight might be specified in a few
-ways.  We need to specify both how the value is interpreted and the
-units.  \code{FPA.RA.FORMAT} and \code{FPA.DEC.FORMAT} should be one
-of the following:
-
-\begin{itemize}
-\item \code{HOURS}: The value pointed to by the concept should be
-  interpreted as being in hours.
-\item \code{DEGREES}: The value pointed to by the concept should be
-  interpreted as being in degrees.
-\item \code{RADIANS}: The value pointed to by the concept should be
-  interpreted as being in radians.
-\end{itemize}
-
-How the value is interpreted can be determined from the type of the
-header: if it is of type \code{STR}, then we can reasonably assume
-that it is in sexagesimal format with colons or spaces as separators;
-and if it is of type \code{F32} (or \code{F64}), then we can assume
-that it is in decimal format.
-
-\subsubsection{Implicit format information}
-
-While details like the units of the right ascension in the header must
-be specified explicitly, some other details can be determined from
-implicit information.
-
-\begin{itemize}
-\item \code{FPA.RA} and \code{FPA.DEC}: if the value on ingest is of
-type \code{STRING}, then it may be interpreted as sexagesimal
-notation, ``\code{dd:mm:ss.ss}'', or ``\code{dd:mm.mmm}''.  A space
-may be used instead of a colon to separate the values.  Otherwise, if
-the value is of a numerical type (\code{F32} or \code{F64}), then that
-is the appropriate value.
-\item \code{CELL.XBIN} and \code{CELL.YBIN}: if the value on ingest is
-of type \code{STRING}, then it may be interpreted as ``\code{x,y}'',
-where \code{x} is the binning in x, and \code{y} is the binning in y.
-A space may be used instead of a comma, and there may even be a space
-before or after the comma (or both).  Otherwise, if the value is of a
-numerical type (\code{S32}, etc), then that is the appropriate value.
-\item \code{CELL.BIASSEC} and \code{CELL.TRIMSEC}: These values on
-ingest should always be of type \code{STRING}.  If they contain a
-square bracket, then they may be interpreted as a list of standard
-region specifications, ``\code{[x0:x1,y0:y1];[x2:x3,y2:y3];...}'',
-where the semi-colon may be replaced by spaces.  Otherwise, the string
-may be interpreted as a FITS header (or headers, separated by spaces,
-commas or semi-colons) that contains the appropriate values.
-\end{itemize}
-
-\tbd{the use of implicit interpretation of formats should be
-  discouraged: format interpretation guides should be provided}
-
-\subsection{Configuration APIs}
-
-\begin{prototype}
-bool pmConfigRead(psMetadata **site, psMetadata **camera, psMetadata **recipe,
-                  int *argc, char **argv, const char *recipeName);
-psMetadata *pmConfigCameraFromHeader(const psMetadata *site, const psMetadata *header);
-psMetadata *pmConfigRecipeFromCamera(const psMetadata *camera, const char *recipeName);
-\end{prototype}
-
-\code{pmConfigRead} shall load the \code{site} configuration
-(according to the above rule for determining the source).  The
-\code{camera} configuration shall also be loaded if it is specified on
-the command line (\code{argc, argv}); otherwise it shall be set to
-\code{NULL}.  The \code{recipe} shall also be loaded from the command
-line (if specified) or, if the camera configuration has been loaded,
-from the camera configuration and recipe specification therein (see
-below).  In dealing with the command line parameters, the functions
-shall use the appropriate functions in psLib to retrieve and remove
-the relevant options from the argument list; this simplifies
-assignment of the mandatory arguments, since all the optional command
-line arguments are removed leaving only the mandatory arguments.  The
-following psLib setups shall also be performed if they are specified
-in the site configuration:
-\begin{itemize}
-\item the function shall call \code{psTimeInitialize} with the
-  configuration file specified by \code{TIME}.
-\item the function shall call \code{psLogSetLevel} with the logging
-  level specified by \code{LOGLEVEL}.
-\item the function shall call \code{psLogSetFormat} with the log
-  format specified by \code{LOGFORMAT}.
-\item the function shall call \code{psTraceSetLevel} with the component names and
-  trace levels specified by the \code{TRACE}.
-\end{itemize}
-Note that additional log/trace command-line options may be specified
-and interpretted using the \code{psArgumentVerbosity} function from
-psLib.  These options should (in the case of logging) override the
-configuration-supplied information or (in the case of tracing)
-supplement it.
-
-\code{pmConfigCameraFromHeader} shall load the \code{camera}
-configuration based on the contents of the FITS \code{header}, using
-the list of known cameras contained in the \code{site} configuration.
-If more than one camera matches the FITS header, a warning shall be
-generated and the first matching camera returned.
-
-\code{pmConfigRecipeFromCamera} shall load the \code{recipe}
-configuration based on the \code{recipeName} and the list of known
-recipes contained in the \code{camera} configuration (details below).
-
-\begin{prototype}
-bool pmConfigValidateCamera(const psMetadata *camera, const psMetadata *header);
-\end{prototype}
-
-This function, used by \code{pmConfigCameraFromHeader}, shall return
-\code{true} if the FITS \code{header} matches the rule contained in
-the \code{camera} configuration (see \S\ref{sec:camerarule});
-otherwise it shall return \code{false}.
-
-\begin{prototype}
-psDB *pmConfigDB(psMetadata *site);
-\end{prototype}
-
-\code{pmConfigDB} shall use the \code{site} configuration data to open
-a database handle.  \tbd{This is fairly straightforward at the moment,
-but will change when we beef up security.}
-
-\subsubsection{Example usage}
-
-The following is provided as an example of how the above functions
-are envisioned in use.
-
-\begin{verbatim}
-int main(int argc, char *argv[])
-{
-    // Parse other command-line arguments here
-    psMetadata *site = NULL;            // Site configuration
-    psMetadata *camera = NULL;          // Camera configuration
-    psMetadata *recipe = NULL;          // Recipe configuration
-    if (! pmConfigRead(&site, &camera, &recipe, &argc, argv, "moduleName")) {
-        psLogMsg("moduleName", PS_LOG_ERROR, "Can't find site configuration!\n");
-        exit(EXIT_FAILURE);
-    }
-    // Parse other command-line arguments here
-
-    // The command-line argument list now contains only mandatory arguments
-    // Assume the first of these is an input image
-    char *imageName = argv[1];          // Name of FITS file
-    psFits *imageFH = psFitsOpen(imageName, "r"); // File handle for FITS file
-    if (! imageFH) {
-        psLogMsg("moduleName", PS_LOG_ERROR, "Can't open input image %s\n", imageName);
-        exit(EXIT_FAILURE);
-    }
-    psMetadata *header = psFitsReadHeader(NULL, imageFH); // FITS header
-
-    if (!camera && !(camera = pmConfigCameraFromHeader(site, header))) {
-        psLogMsg("moduleName", PS_LOG_ERROR, "Can't find camera configuration!\n");
-        exit(EXIT_FAILURE);
-    }
-
-    if (! recipe && !(recipe = pmConfigRecipeFromCamera(camera, "moduleName"))) {
-        psLogMsg("moduleName", PS_LOG_ERROR, "Can't find recipe configuration!\n");
-        exit(EXIT_FAILURE);
-    }
-
-    // Now go on and do stuff
-    ....
-}
-\end{verbatim}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{``Concepts''}
-\label{sec:concepts}
-
-Each image from an astronomical instrument has associated with it what
-we will call {\it concepts} (for want of a better word; \tbd{we would
-like to call this ``metadata'', but unfortunately that name is already
-taken}).  These are values corresponding to general quantities and
-qualities necessary to understand and interpret the data, such as
-airmass, date, read noise and filter.  The values of each of the below
-concepts shall be determined when the FPA is read into memory (via
-\code{pmFPARead}), and stored at the appropriate level in the focal
-plane hierarchy.
-
-After ingest (performed in \code{pmFPARead}, the user may safely
-assume that all of the above concepts exist at the appropriate level
-(meaning the user needn't be hampered by excessive error checking), is
-of the specified type (meaning the user doesn't need to worry about
-whether the value of interest is stored in, e.g., floating point or
-double precision or even a colon-delimited string) and in the
-specified format (meaning the user doesn't need to know, e.g., whether
-the right ascension is in radians or degrees) --- all the conversions
-are handled by the ``concepts'' functions at ingest.
-
-Most of the structures and functions in this section are intended to
-be ``private'', since there is no need envisioned for the user to call
-them directly.
-
-\subsection{Specifying a concept}
-
-Specifying a ``concept'' requires a (meaningful) name (preferably with
-the level in the name, e.g., \code{CELL.EXPOSURE}), a
-comment/description, a type, a default or blank value, functions to
-read and write, and a level that the concept applies to
-(FPA/Chip/Cell).
-
-\begin{datatype}
-typedef psMetadataItem* (*p_pmConceptReadFunc)(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db);
-typedef bool (*p_pmConceptWriteFunc)(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db);
-typedef struct {
-    psMetadataItem *blank;          // Blank value of concept; also contains the name
-    p_pmConceptReadFunc read;       // Function to call to read the concept
-    p_pmConceptWriteFunc write;     // Function to call to write the concept
-} p_pmConceptSpec;
-\end{datatype}
-
-\code{blank} is a \code{psMetadataItem} that provides the name, type
-and default/blank value for the concept.  \code{read} and \code{write}
-provide the functions to read and write.
-
-A concept specification may be allocated:
-\begin{prototype}
-p_pmConceptSpec *p_pmConceptSpecAlloc(psMetadataItem *blank, pmConceptReadFunc read,
-                                      pmConceptWriteFunc write);
-\end{prototype}
-
-\subsection{Registering a concept}
-
-The concept specifications that have been registered shall be stored in
-three \code{psMetadata}s, one for each level (FPA, chip, cell).
-
-Registering a concept is achieved by:
-\begin{prototype}
-bool pmConceptRegister(psMetadataItem *blank, pmConceptReadFunc read,
-                       pmConceptWriteFunc write, pmConceptLevel level);
-\end{prototype}
-
-\code{pmConceptRegister} shall generate a concept specification from
-the provided \code{blank}, and \code{read} and \code{write} functions,
-and register it in the metadata specified by the \code{level}.
-
-\code{pmConceptLevel} simply specifies which level in the focal plane
-hiearchy the concept applies to:
-\begin{datatype}
-typedef enum {
-    PM_CONCEPT_LEVEL_FPA,               // Store in the FPA
-    PM_CONCEPT_LEVEL_CHIP,              // Store in the chip
-    PM_CONCEPT_LEVEL_CELL               // Store in the cell
-} pmConceptLevel;
-\end{datatype}
-
-A \code{read} function of \code{NULL} indicates that there is no
-special interpretation of the concept required, and that it can be
-used as read.  A \code{write} function of \code{NULL} indicates that
-no special formatting of the concept is required, and that it can be
-written as is.
-
-
-\subsection{Default concepts}
-
-Below is a list of concepts that the IPP will use, with the expected
-type and a short description.
-
-\begin{itemize}
-\item \code{FPA.NAME} (\code{psString}): An identifier (e.g., observation number) for the FPA instance
-\item \code{FPA.AIRMASS} (F32): Airmass at which the observation is made (boresight)
-\item \code{FPA.FILTER} (\code{psString}): Filter used in observation
-\item \code{FPA.POSANGLE} (F32): Position angle for camera
-\item \code{FPA.RADECSYS} (\code{psString}): System of RA,Dec (e.g., J2000 or ICRS)
-\item \code{FPA.RA} (F64): Right Ascension of boresight in radians
-\item \code{FPA.DEC} (F64): Declination of boresight in radians
-\item \code{CHIP.NAME} (\code{psString}): The name of the chip (unique within the FPA) --- set at FITS read
-\item \code{CELL.NAME} (\code{psString}): The name of the cell (unique within the parent chip) --- set at FITS read
-\item \code{CELL.GAIN} (F32): CCD gain (e/ADU)
-\item \code{CELL.READNOISE} (F32): CCD read noise (e)
-\item \code{CELL.SATURATION} (F32): CCD saturation point (ADU)
-\item \code{CELL.BAD} (F32): CCD bad pixel point (ADU)
-\item \code{CELL.XPARITY} (S32): Direction of CCD readout in x relative to the rest of the chip
-\item \code{CELL.YPARITY} (S32): Direction of CCD readout in y relative to the rest of the chip
-\item \code{CELL.READDIR} (S32): Read direction: line (1) or column (2)
-\item \code{CELL.EXPOSURE} (F32): Exposure time of image (sec)
-\item \code{CELL.DARKTIME} (F32): Dark time for image (sec)
-\item \code{CELL.TRIMSEC} (\code{psRegion*}): Trim region
-\item \code{CELL.BIASSEC} (\code{psList*} of \code{psRegion*}): Overscan region(s)
-\item \code{CELL.XBIN} (S32): CCD binning in x
-\item \code{CELL.YBIN} (S32): CCD binning in y
-\item \code{CELL.TIMESYS} (\code{psTimeType}): Time system in use
-\item \code{CELL.TIME} (\code{psTime*}): Time of observation start
-\item \code{CELL.X0} (S32): x position of cell (0,0) on the chip
-\item \code{CELL.Y0} (S32): y position of cell (0,0) on the chip
-\end{itemize}
-
-\tbd{CELL.EXPOSURE, CELL.DARKTIME and CELL.TIME should actually be
-specified at the readout level.  However, at this present time, we're
-not sure how these should be specified, and so we move them up to the
-cell level and assume that all readouts are of the same exposure and
-dark time.}
-
-The concept specifications for the above shall be registered by
-\code{pmConceptsInit}:
-\begin{prototype}
-bool pmConceptsInit(void);
-\end{prototype}
-
-Since defined concept specifications are required before any concept
-ingest can take place, all functions that work with the concepts must
-call \code{pmConceptsInit} first.
-
-The concept specification metadata containers and the concept
-specifications that have been registered shall all be freed by
-\code{pmConceptsDone}:
-\begin{prototype}
-void pmConceptsDone(void);
-\end{prototype}
-Calling \code{pmConceptsDone} is required in order to avoid a memory
-leak, since the metadata containers are defined \code{static}.
-
-\subsection{Reading, Writing and Blanking}
-
-Reading concepts is the act of determining their values and setting
-them in the \code{concepts} metadata in the focal plane hierarchy.
-Writing concepts is the act of taking the \code{concepts} metadata
-which is in the focal plane hierarchy and preparing them for output.
-By ``blanking'', we mean setting the concepts to a default or blank
-value (e.g., \code{NaN} for floating point); this takes place before
-reading, and can be used to set up a focal plane hierarchy without
-reading from any particular source.
-
-The following functions shall read, write or blank (as appropriate)
-the concepts at the appropriate level in the focal plane hierarchy:
-\begin{prototype}
-bool p_pmConceptsReadFPA(pmFPA *fpa);
-bool p_pmConceptsReadChip(pmChip *chip);
-bool p_pmConceptsReadCell(pmCell *cell);
-bool p_pmConceptsWriteFPA(pmFPA *fpa);
-bool p_pmConceptsWriteChip(pmChip *chip);
-bool p_pmConceptsWriteCell(pmCell *cell);
-bool p_pmConceptsBlankFPA(pmFPA *fpa);
-bool p_pmConceptsBlankChip(pmChip *chip);
-bool p_pmConceptsBlankCell(pmCell *cell);
-\end{prototype}
-
-Under ordinary circumstances, these functions will be called by
-\code{pmFPARead}, \code{pmFPAWrite} and \code{pmFPAConstruct}.
-
-
-\subsection{Copying concepts}
-
-The values of concepts may be copied from one source to another:
-\begin{prototype}
-bool pmFPACopyConcepts(pmFPA *target, pmFPA *source);
-\end{prototype}
-
-\code{pmFPACopyConcepts} shall iterate through the focal plane
-hierarchy, copying the values of the concepts from the \code{source}
-to the \code{target}.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%\input{CameraImages.tex}
-
-%\input{CameraGeometry.tex}
-
-\section{Photometry}
-
-\tbd{This section is to be deferred, and for now consists only of
-place holders, with no functional items.}
-
-Photometric observations are performed in an instrumental photometric
-system, and must be related to other photometric systems.  We
-require a data structure which defines a photometric system, as well
-as a structure to define the transformation between photometric
-systems.
-
-The photometric system is defined by the psPhotSystem structure.  
-A photometric system is identified by a human-readable \code{name}
-(ie, SDSS.g, Landolt92.B, GPC1.OTA32.r).  Each photometric system is
-given a unique identifier \code{ID}.  Observations taken with a
-specific camera, detector, and filter represent their own photometric
-system, and it may be necessary to perform transformations between
-these systems.  Photometric systems associated with observations from
-a specific camera/detector/filter combination can be associated with
-those components.
-\begin{datatype}
-typedef struct {
-    const int ID;                       ///< ID number for this photometric system
-    const char *name;                   ///< Name of photometric system
-    const char *camera;                 ///< Camera for photometric system
-    const char *filter;                 ///< Filter used for photometric system
-    const char *detector;               ///< Detector used for photometric system
-} psPhotSystem;
-\end{datatype}
-
-The following structure defines the transformation between two
-photometric systems.
-\begin{datatype}
-typedef struct {
-    psPhotSystem src;                   ///< Source photometric system
-    psPhotSystem dst;                   ///< Destination photometric system
-    psPhotSystem pP, pM;                ///< Primary color reference
-    psPhotSystem sP, sM;                ///< Secondary color reference
-    float pA, sA;                       ///< Color offset for references
-    psPolynomial3D transform;           ///< Transformation from source to destination
-} psPhotTransform;
-\end{datatype}
-
-The transformation between two photometric systems may depend on the
-airmass of the observation and on the colors of the object of
-interest.  For a specific observation, such a transformations can be
-defined as a polynomial function of the color of the star and the
-airmass of the observations.  If sufficient data exists, the
-transformation between the photometric systems may include more than
-one color, constraining the curvature of the stellar spectral energy
-distributions.  This latter term may be significant for stars which
-are highly reddened, for example.  Derived photometric quantities may
-have been corrected for airmass variations, in which case only color
-terms may be measurable.  The structure defines the transformation
-between a source photometric system (\code{src}) and a target
-photometric system (\code{dst}).  The photometric system of a primary
-color is defined by \code{pP, pM} such that the color is constructed
-as $pP - pM$.  A secondary color is defined by \code{sP, sM}.  For
-both, a reference color is specified (\code{pA, sA}): the polynomial
-transformation terms refer to colors in the form $pP - pM - pA$.  The
-transformation is specified as a 3D polynomial.  For a star of
-magnitude $M_{\rm src}$ in the source photometric system, with
-additional magnitude information in the other systems $M_{\rm pP}$,
-$M_{\rm pM}$, $M_{\rm sP}$, $M_{\rm sM}$, observed at an airmass of
-$z$, the magnitude of the star in the target system $M_{\rm dst}$ is
-given by: $M_{\rm dst} = M_{\rm src} + transform(z, M_{\rm pP} -
-M_{\rm pM} - pA, M_{\rm sP} - M_{\rm sM} - sA)$.
-
-\section{Image Detrending}
-
-Image Detrending is the image analysis process wherein the
-instrumental signatures are removed from the individual images.  This
-section discusses the modules used for image detrending.  The basic
-image detrending steps are:
-\begin{itemize}
-\item Subtract bias;
-\item Correct for non-linearity;
-\item Flat-field;
-\item Mask bad pixels;
-\item Subtract the background;
-\item Mask cosmic rays;
-\item Mask optical defects;
-\end{itemize}
-
-\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:
-
-\begin{prototype}
-pmReadout *pmSubtractBias(pmReadout *in, pmOverscanOptions *overscanOpts,
-                          psRegion imageRegion, psList *overscanRegions,
-                          const pmReadout *bias, const pmReadout *dark);
-\end{prototype}
-
-Three 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.  The third is the subtraction of a suitably scaled full-frame
-dark image.
-
-The input image, \code{in}, shall have the bias subtracted in-place.
-The input image may be of type U16, S32, or F32.  The region of the
-input image that shall have the overscan or full-frame subtractions
-applied is specified by \code{imageRegion}.
-
-Overscan subtraction is performed if \code{overscanOpts} is
-non-\code{NULL} (see \S\ref{sec:overscan}).  \code{overscanRegions}
-shall be a list of \code{psRegion}s that specify the regions that
-comprise the overscans.
-
-A \code{bias} frame shall be subtracted pixel-by-pixel from the input
-image if \code{bias} is non-NULL.  If \code{dark} is non-\code{NULL},
-then the dark image, scaled by the ratio of dark times (from
-\code{CELL.DARKTIME}) shall be subtracted pixel-by-pixel from the
-input image.  The full-frame subtractions (both bias and dark) should
-only be performed on the image region specified by
-\code{CELL.TRIMSEC}.  Note that the input image, \code{in}, and the
-\code{bias} and \code{dark} frames 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} or
-\code{dark} shall also be masked in the output.  The bias and dark
-images may be copied to the same type as the input image if required.
-
-
-\subsubsection{Overscan subtraction}
-\label{sec:overscan}
-
-The options for performing the overscan subtraction are bundled in a
-\code{pmOverscanOptions}:
-
-\begin{datatype}
-typedef struct {
-    // Inputs
-    bool single;                // Reduce all overscan regions to a single value?
-    bool scanRows;              // Scan direction was rows? (otherwise columns)
-    pmFit fitType;              // Type of fit to overscan
-    unsigned int order;         // Order of polynomial, or number of spline pieces
-    psStats *stat;              // Statistic to use when reducing the minor direction
-    // Outputs
-    psPolynomial1D *poly;       // Result of polynomial fit
-    psSpline1D *spline;         // Result of spline fit
-} pmOverscanOptions;
-\end{datatype}
-
-The mode in which the overscan is subtracted is specified by the
-\code{single} boolean.  If \code{single} is \code{true}, then the
-entire overscan region is reduced to a single value using the
-\code{stat}.  If \code{single} is \code{false}, the overscan shall be
-reduced along the dimension specified by \code{scanRows} (rows if
-\code{scanRows} is true; otherwise columns).
-
-If the overscan is not defined for each row/column,
-\code{pmSubtractBias} shall generate an error if \code{fitType} is
-\code{PM_FIT_NONE}; otherwise, the function shall shall generate a
-warning and the undefined values shall be interpolated using the
-provided functional form.
-
-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}.
-
-\code{fitType} is an enumerated type which specifies the type of fit
-to employed on the overscan vector:
-\begin{datatype}
-typedef enum {
-    PM_FIT_NONE,                        ///< No fit
-    PM_FIT_POLY_ORD,                    ///< Fit ordinary polynomial
-    PM_FIT_POLY_CHEBY,                  ///< Fit Chebyshev polynomial
-    PM_FIT_SPLINE                       ///< Fit cubic splines
-} pmFit;
-\end{datatype}
-
-If \code{fitType} is \code{PM_FIT_NONE}, then the overscan vector is
-subtracted from the image without fitting.  Otherwise, the overscan
-vector is fit using the specified functional form, the fit is
-subtracted from the image, and the \code{poly} or \code{spline} is
-allocated and updated with the results of the fit.
-
-The allocator for a \code{pmOverscanOptions} shall be:
-\begin{prototype}
-pmOverscanOptions *pmOverscanOptionsAlloc(bool single, bool scanRows,
-                                          pmFit fitType, unsigned int order,
-                                          psStats *stat);
-\end{prototype}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\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.
-
-These operations act only on the region of the readout specified by
-\code{CELL.TRIMSEC}.
-
-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{prototype}
-pmReadout *pmNonLinearityPolynomial(pmReadout *in, const psPolynomial1D *coeff);
-\end{prototype}
-
-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{prototype}
-pmReadout *pmNonLinearityLookup(pmReadout *in, const char *filename);
-\end{prototype}
-
-For each pixel in the input image, the function shall replace the flux
-with the corresponding value from the supplied lookup table, specified
-by the \code{filename}.  The lookup table file shall consist of two
-columns of data, the first being the original flux value and the
-second being the replaced flux value.  The file shall be in a format
-suitable for reading by \code{psLookupTableRead}.
-
-Both \code{pmNonLinearityPolynomial} and \code{pmNonLinearityLookup}
-shall modify the input image in-place.  The input image may be of
-type U16, S32, or F32.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\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 contained within the input image as appropriate.
-The API shall be the following:
-\begin{prototype}
-bool pmFlatField(pmReadout *in, const pmReadout *flat);
-\end{prototype}
-
-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 zero and negative pixels, and copying of the
-mask from the \code{flat} to the output.
-
-The images in the input and flat-field readouts must both be of type
-F32.
-
-This operation acts only on the region of the readout specified by
-\code{CELL.TRIMSEC}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\subsection{Masking}
-
-\subsubsection{Mask values}
-\label{sec:maskValues}
-
-We define several mask values for use in the detrend processing:
-\begin{datatype}
-/** 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{datatype}
-
-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{prototype}
-pmReadout *pmMaskBadPixels(pmReadout *in, const pmReadout *mask, unsigned int maskVal,
-                           float sat, unsigned int growVal, int grow);
-\end{prototype}
-
-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,
-and grown by a single pixel (in addition to the \code{grow} done on
-the \code{growVal}).
-
-\tbd{In the future, may change {\tt grow} to a convolution kernel}.
-
-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 correspond to pixels outside the range of the \code{mask}
-image), the function shall generate an error.
-
-The input image may be of type U16, S32 or F32.  The mask image
-must be of type U8.
-
-This operation acts only on the region of the readout specified by
-\code{CELL.TRIMSEC}.
-
-\subsection{Subtract sky}
-
-\tbd{This may be deferred.}
-
-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{pmSubtractSky} shall fit and
-subtract a model for the background of the image.  The API shall be
-the following:
-\begin{prototype}
-pmReadout *pmSubtractSky(pmReadout *in, psPolynomial2D *poly, psImage *mask, psU8 maskVal, 
-                         int binFactor, psStats *stats, float clipSD);
-\end{prototype}
-
-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 polynomial, \code{poly}, specifies the order of the polynomial,
-and on return shall contain the coefficients of the fit.  If
-\code{poly} is \code{NULL}, then no fit shall be performed, and the
-function shall generate a warning and return.
-
-When fitting the polynomial, the function shall first bin the input
-image by \code{binFactor} in order to reduce the required processing
-time.  In the binning, pixels in the \code{mask} (if non-\code{NULL})
-which satisfy the \code{maskVal} shall be excluded.  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.  These pixels may be
-interpolated over, or may be simply ignored in the fitting, according
-to the choice of algorithm.  If the \code{clipSD} is non-positive,
-then the function shall generate a warning and not perform any
-clipping.
-
-The \code{mask} shall be of type U8, and the input image,
-\code{in}, must be of type F32.
-
-This operation acts only on the region of the readout specified by
-\code{CELL.TRIMSEC}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\subsection{Paper Trail}
-
-The elements of the focal plane hierarchy each contain an
-\code{analysis} member, intended to log the results of the detrend
-tasks.  The detrend tasks shall add to the \code{analysis} members as
-follows:
-
-\begin{itemize}
-\item \code{pmMaskBadPixels}:
-  \begin{itemize}
-  \item \code{MASK.DONE} (STR): The time at which masking was
-    completed.
-  \item \code{MASK.SAT} (S32): The number of saturated pixels masked
-    in the image
-  \item \code{MASK.SAT.GROW} (S32): The number of additional pixels
-    masked by growing the saturated pixels.
-  \item \code{MASK.BAD} (S32): The number of pixels masked in the
-    image
-  \item \code{MASK.BAD.GROW} (S32): The number of additional pixels
-    masked by growing the specified bad pixels.
-  \end{itemize}
-\item \code{pmNonLinearityPolynomial} and \code{pmNonLinearityLookup}:
-  \begin{itemize}
-  \item \code{NONLIN.DONE} (STR): The time at which the non-linearity
-    correction was completed.
-  \item \code{NONLIN.POLY} (STR): The polynomial coefficients used (if
-    applicable).
-  \item \code{NONLIN.LOOKUP} (STR): The filename for the lookup table
-    (if applicable).
-  \end{itemize}
-\item \code{pmSubtractBias}:
-  \begin{itemize}
-  \item \code{BIAS.DONE} (STR): The time at which the bias-subtraction
-    was completed.
-  \item \code{BIAS.OVERSCAN.AXIS} (STR): Overscan axis used.
-  \item \code{BIAS.OVERSCAN.FIT.TYPE} (STR): Fit type applied to
-    overscan.
-  \item \code{BIAS.OVERSCAN.FIT.COEFF} (STR): Coefficients of overscan
-    fit.
-  \item \code{BIAS.OVERSCAN.REGION} (STR): Overscan regions (from
-    \code{x0,y0,numCols,numRows}).
-  \item \code{BIAS.OVERSCAN.BIN} (S32): Number of pixels per bin used
-    in overscan.
-  \item \code{BIAS.OVERSCAN.MEAN} (F32): The mean of the binned
-    overscan pixels after subtracting the fit.
-  \item \code{BIAS.OVERSCAN.SD} (F32): The standard deviation of the
-    binned overscan pixels after subtracting the fit.
-  \end{itemize}
-\item \code{pmFlatField}:
-  \begin{itemize}
-  \item \code{FLAT.DONE} (STR): The time at which the flat-fielding
-    was completed.
-  \item \code{FLAT.BAD} (S32): Number of non-positive flat-field
-    pixels.
-  \end{itemize}
-\end{itemize}
-
-To be added by higher-levels:
-\begin{itemize}
-\item \code{BIAS.NAME} (STR): Name of bias image
-\item \code{DARK.NAME} (STR): Name of dark image
-\item \code{FLAT.NAME} (STR): Name of flat image
-\item \code{MASK.NAME} (STR): Name of mask image
-\end{itemize}
-
-\subsection{Detrend Lookups}
-
-When it comes time to perform a detrend operation on an image, it is
-necessary to determine {\em which} detrend image should be used.  The
-Pan-STARRS Image Processing Pipeline uses the concept of a detrend
-image database table, or set of tables (part of the Metadata
-Database), to store the known master detrend images.  These tables can
-be accessed though the basic query functions specified for the master
-detrend database.  To simplify the interaction for the case of the
-detrend images, the following function allows the user to explicitly
-search the detrend database table or tables for detrend images which
-satisfy a set of characteristics.
-
-\begin{prototype}
-psArray *pmDetrendLookup (psMetadata *constraints, psMetadata *tableDefs);
-\end{prototype}
-This function accepts a metadata structure which restricts the
-selected detrend images.  This metadata structure may contain any of
-the following entries:
-\begin{verbatim}
-TYPE        type of detrend data (eg, flat, bias) 
-CAMERA      name of desired camera (eg, GPC, MEGACAM)
-CHIP        chip identifier (eg., ccd00)
-FILTERNAME  name of specific filter hardware (eg, r.GPC01)
-FILTERTYPE  conceptual name of filter (eg., r)
-TIME_MIN    lower bound on valid time range 
-TIME_MAX    upper bound on valid time range 
-LABEL       match the entry label
-RECIPE      recipe used to build detrend image
-EXPTIME     exposure time 
-AIRMASS     airmass 
-\end{verbatim}
-Any detrend images which match the provided constraints are returned
-as an array of \code{psMetadata} elements corresponding to the columns
-of the detrend database table.  The additional input parameter
-specifies additional information to define the detrend database
-tables.  This may include the access information (IP, Username,
-Password), as well as names for the table and the columns which
-correspond to the constraint names.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Detrend Creation}
-
-In the detrend creation process, a collection of raw images are
-combined to produce a clean, high-quality master image for correcting
-the effect of interest.  The input images may potentially be processed
-and scaled in some way.  The resulting output images may be to be
-re-scaled to have a consistent signal for all chips in the mosaic.
-The simplest example is the construction of a bias image, in the case
-where there is signficant 2-D bias structure.  In this case, the input
-raw bias images are probably combined without any additional
-processing.  In another example, flat-field image must be
-bias-corrected and scaled to a consistent normalization before being
-combined, and the flat-field images from the different chips must be
-normalized so that each chip will be flattened consistently across the
-mosaic.  A complex example is the fringe pattern, in which the input
-images must be bias-corrected and flattened, and the resulting images
-must be scaled by the amplitude of the fringe pattern on each image,
-rather than by the average flux level.  In this section, we define the
-tools necessary to perform the detrend creation process.
-
-\subsection{Image Stacking}
-
-A basic operation in generating the master detrend images is using a
-stack of many input images of a particular type and combining them,
-with perhaps some additional scaling, in order to build up
-signal-to-noise and to reject deviant pixel.  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{datatype}
-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;
-\end{datatype}
-
-\begin{prototype}
-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{prototype}
-
-\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{pmReadout}s.  The images contained within the
-\code{pmReadout}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{pmCombineParams} 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{pmReadout} 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 rejection is performed.  If \code{zero} is
-non-\code{NULL} and \code{applyZeroScale} is false, then the values
-shall only be used in calculating the Poisson variances.
-
-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 rejection is performed.  If
-\code{scale} is non-\code{NULL} and \code{applyZeroScale} is false,
-then the values shall only be used in calculating the Poisson
-variances.
-
-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 using Poisson statistics ($\sigma_i$ below).
-
-In summary, pixels corresponding to the same physical pixel are
-combined, having values $x_i \pm \sigma_i$.  In the case that
-\code{applyZeroScale} is \code{true}, then:
-\begin{eqnarray}
-x_i & = & s_i f_i + z_i \\
-\sigma_i & = & [g x_i + r^2]^{1/2} / g
-\end{eqnarray}
-Where $f_i$ is the value of the pixel in image $i$, $s_i$ is the scale
-applied to image $i$, $z_i$ is the zero offset applied to image $i$,
-$g$ is the gain, and $r$ is the read noise.  If scales are not
-provided, they are set to unity; if zero offsets are not provided,
-they are set to zero.
-
-If \code{applyZeroScale} is \code{false}, then the values are:
-\begin{eqnarray}
-x_i & = & f_i \\
-\sigma_i & = & [g (s_i f_i + z_i) + r^2]^{1/2} / g
-\end{eqnarray}
-where the same symbols are used as above.
-
-The \code{inputs, zero} and \code{scale} may be of U16, S32 and F32
-types, and must all be of the same type.  The \code{output} shall be
-of the same type.
-
-\subsection{Fringe Amplitude}
-
-Some images contain a signal caused by thin-film interference in the
-device due to strong emission lines.  The resulting instrumental
-effect consists of a pattern (the ``fringe pattern'') of bright and
-dark bands corresponding to the constructive and destructive
-interference of the emission lines.  In the case that a single
-emission line causes the line structure, the resulting pattern can be
-described by two independent parameters: First, the amplitude of the
-emission line determines the overall amplitude of the pattern.
-Second, the three-dimensional surface structure of the device
-determines the shape of the pattern.  In a typical situation, the
-device is illuminated by multiple emission lines, as well as a
-continuum spectral source, which contributes to the overall light
-detected by the device without following the fringe pattern.  The
-relative intensities of the continuum background and the fringe
-pattern depend on the device structure (thickness) and on the ratio of
-the continuum and line emission fluxes. 
-
-A simple approach to the fringe pattern is to subtract a master fringe
-frame scaled by the amplitude of the fringe pattern.  The amplitude of
-the fringe pattern is used both in the process of constructing the
-master image and in scaling the master image when it is applied to
-science image.  This is the method currently in use at CFHT and it
-usually performs well.  However, the fringe signal can vary as the
-emission lines in the atmosphere change, and the above method breaks
-down unless different fringe images corresponding to different
-atmospheric conditions are constructed.  
-
-An alternative technique is to use multiple master fringe images at
-the same time, each representing different atmospheric conditions.
-The observed fringe frame can be considered as a linear combination of
-different fringe patterns, depending on the relative strengths of the
-lines active in creating each of the fringe masters.  It is not
-critical that the fringe master images represent completely orthogonal
-fringe patterns, they need only sample sufficiently different
-conditions to provide a handle on the underlying fringe signals.  
-
-We define a method of measuring the fringe pattern which is robust in
-the presence of stars and which is fast.  We implement a varient on
-the method used at CFHT in which the fringe pattern is mapped by a
-series of points distributed across the image.  At CFHT, manual effort
-is used to carefully define point pairs which correspond to peaks and
-valleys of the fringe pattern.  We implement a different approach in
-which the fringe points are randomly chosen across the image.  At each
-point in the image, the median flux is measured in a box of specified
-size.  A low-frequency spatial filter is then applied to these
-measurements.  The resulting array of points and fluxes then
-represents the strength of the fringe pattern on that image.  The
-comparison between any two fringe images is then just a linear fit
-between these fringe statistics vectors, as follows:
-\[
-S_i = C_0 + C_1 F_i
-\]
-where $S_i$ is the fringe statistic on the science image and $F_i$ is
-the fringe statistic on the reference fringe image.  Extending this
-logic to any number of reference fringe images results in the
-following relationship:
-\[
-S_i = C_0 + \sum_j C_j F_j
-\]
-
-In order to correct a single science image, the collection of fringe
-statistics ($S_i$) are used to measure the coefficients $C_0$, $C_j$.
-The linear combination of the reference fringe images is then used to
-build a master image which is subtracted from the science image.  The
-following structures and functions implement the above concepts.
-
-The \code{pmFringeStats} structure represents the fringe statistics
-for a given image.  
-\begin{datatype}
-typedef struct {
-    psU32 nRequested;   // number of fringe points selected
-    psU32 nAccepted;    // number of fringe points not masked
-    psU32 dX;           // median box half-width
-    psU32 dY;           // median box half-height
-    psU32 nX;           // large-scale smoothing in x (col)
-    psU32 nY;      	// large-scale smoothing in y (row)
-    psVector x;    	// fringe point coordinates (col)
-    psVector y;    	// fringe point coordinates (row)
-    psVector f;    	// fringe point median
-    psVector df;   	// fringe point stdev
-    psVector mask;      // fringe point on/off mask
-} pmFringeStats;
-\end{datatype}
-
-The \code{pmFringeStats} structure is allocated with the following
-function:
-\begin{prototype}
-pmFringeStats *pmFringeStatsAlloc (
-    int nPts,     // number of points to create
-    int dX,     // half-width of fringe boxes
-    int dY,     // half-height of fringe boxes
-    int nX,     // smoothing scale in x
-    int nY    // smoothing scale in y
-);
-\end{prototype}
-
-A set of fringe points appropriate to the dimensions of a specific
-image are created with the following function:
-\begin{prototype}
-bool pmFringeStatsCreatePoints (pmFringeStats *fringe, psImage *image);
-\end{prototype}
-
-In general, \code{pmFringeStatsCreatePoints} should only be needed
-when a new chip and filter are first use for analysis.  Multiple
-fringe images with the same chip and filter need to be examined with
-the same fringe points in order for the statistical comparison to be
-meaningful.  The constructed fringe points should be saved and loaded
-as a FITS table using the following function:
-\begin{prototype}
-bool pmFringeStatsWriteFits (psFits *fits, pmFringeStats *fringe);
-bool pmFringeStatsReadFits (psFits *fits, pmFringeStats *fringe);
-\end{prototype}
-
-In order to measure the fringe statistics for a given image, the
-following function is defined:
-\begin{prototype}
-bool pmFringeStatsMeasure(pmFringeStats *fringe, pmReadout *readout)
-\end{prototype}
-This function measures the robust median at each of the fringe points
-and saves the median values in \code{fringe->f} and the scatter in
-\code{fringe->df}.
- 
-Given the fringe statistics for a science image, and the fringe
-statistics for a set of reference fringe images, the following
-function can be used to measure the scaling coefficients of the
-reference fringe frames which best fit the science image fringe
-pattern:
-\begin{prototype}
-pmFringeScale *pmFringeScaleMeasure (pmFringeStats *science, psArray *fringes) 
-\end{prototype}
-
-Given a science image, a set of master fringe images, and a the set of
-fringe statistics for the reference fringe images, the following
-function can be used to correct the science image for the fringe pattern:
-\begin{prototype}
-psImage *pmFringeCorrect(psImage *out, psMetadata *info, psImage *science, psArray *fringeImage, psArray *fringeStats);
-\end{prototype}
-
-\subsection{Flat-field Re-Normalization}
-
-Consider a collection of $N_i$ flat-field images obtained with a
-mosaic camera consisting of $N_j$ chips.  Each image is exposed to an
-illumination source which should be a uniform surface
-brightness\footnote{This is likely a false assumption: the
-illumination source likely has spatial variations.  However, for the
-purposes of this discussion, it only matters that such spatial
-variations scale consistently as a function of illumination intensity.
-The spatial errors are corrected by the photometric flat-field
-correction technique (eg., Magnier \& Cuillandre 2004).}  Two factors
-determine the actual measured flux level (in Digital Numbers) on each
-of the chips in each image: the gain of each chip ($\mbox{gain}_j$)
-and the flux level from the illumination source ($\mbox{source}_i$).
-When the images are combined, the input images must be scaled so that
-the flux levels can be consistently compared.  After combining the
-collection of images, it is necessary to determine an appropriate
-re-normalization for the resulting flat-field images.  In effect, the
-individual chips must be adjusted so that the master flat-field image
-has a flux level which varies from chip to chip in proportion to the
-actual chip gain.  In this case, if a uniform illumination source
-illuminates the mosaic, the resulting flux levels will be corrected by
-the flat-field to a single, consistent flux level. 
-
-In order to determine the correct relative scaling between the
-devices, it is thus necessary to know the individual chip gains, or at
-least the gain ratios.  A typical technique scaled all chips relative
-to a reference chip, or by a statistic measured for the complete
-collection.  These techniques fail if the input collection of images
-does not always consist of the same set of chips; for the GPC on
-Pan-STARRS, we must expect that individual cells or even chips may be
-disabled on a frequent basis, so our algorithms must not be limited by
-the assumption that all chips are available in all images.  We
-therefore define the following algorithm to measure the relative chip
-gains for a collection of input flat-field images, each with a
-measured flux $\mbox{flux}_{i,j}$.  We want to solve for the chip
-gains and the source illumination fluxes which would make the best
-prediction of the measured input image fluxes:
-\[
-\mbox{flux}^{\rm pred}_{i,j} = \mbox{gain}_j \times \mbox{source}_i
-\]
-This relationship is easiest to determine if we take the logarithm of
-both sides of the equation:
-\[
-M^{\rm pred}_{i,j} = G_j + S_i
-\]
-where $M^{\rm pred}_{i,j} = \log (\mbox{flux}^{\rm pred}_{i,j})$, $G_j
-= \log (\mbox{gain}_j)$, and $S_i = \log (\mbox{source}_i)$.  We can
-then write the chi-square which we want to minimize as:
-\[
-\chi^2 = \sum_{i,j} (M^{\rm obs}_{i,j} - G_j - S_i)^2
-\]
-where we ignore the weights of the different measured flux levels.
-Taking the derivatives with respect to the parameters of interest
-($G_j, S_i$), and setting them to 0, we determine the following set of
-equations which must be solved:
-\[
-G_j \times N_i = \sum_i M^{\rm obs}_{i,j} - \sum_i S_i
-\]
-\[
-S_j \times N_j = \sum_j M^{\rm obs}_{i,j} - \sum_j G_j \\
-\]
-This set of equations can be solved iteratively, starting from the
-assumption that all chip gains are 1.0, ($G_j = 0$), or by supplying
-a guess for the chip gains.  The result of this analysis is the
-measured chip gains and the measured source illumination levels for
-each of the input flat-field images.  The chip gains can then be used
-to modify the flux levels on the master flat-field images.
-
-We define the following function to perform the analysis discussed
-above:
-\begin{prototype}
-bool pmFlatNormalization (psVector *sourceFlux, psVector *chipGains, psArray *fluxLevels);
-\end{prototype}
-The input array \code{fluxLevels} consists of $N_i$ vectors, one per
-mosaic image.  Each vector consists of $N_j$ elements, each a
-measurement of the input flat-field image flux levels.  All of these
-vectors must be constructed with the same number of elements, or the
-function will return an error.  If a chip is missing from a particular
-image, that element should be set to \code{NaN}.  The vector
-\code{chipGains} supplies initial guesses for the chip gains.  If the
-vector contains the values 0.0 or \code{NaN} for any of the elements,
-the gain is set to the mean of the valid values.  If the vector length
-does not match the number of chips, an warning is raised, all chip
-gain guesses will be set to 1.0, and the vector length modified to
-match the number of chips defined by the supplied \code{fluxLevels}.
-The \code{sourceFlux} input vector must be allocated (not
-\code{NULL}), but the routine will set the vector length to the number
-of source images regardless of the initial state of the vector.  All
-vectors used by this function must be of type \code{PS_DATA_F64}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Objects on Images}
-
-\subsection{Overview}
-
-The process of finding, measuring, and classifying astronomical
-sources on images is one of the critical tasks of the IPP or any
-astronomical software system.  In this section, we define structures
-and functions related to the task of source detection and measurement.
-The elements defined in this section are generally low-level
-components which can be connected together to construct a complete
-object measurement suite.  
-
-We first define the collection of structures needed to carry
-information about the detected sources.  A major challenge is to
-define what we mean by an astronomical object in the context of image
-source detection.  An astronomical object may be as simple as a
-stellar point source, or it may consist of a galaxy which has smooth
-extended structure; it may consist of an irregular galaxy or galaxy
-group with substantial and complex sub-structure, or it may consist of
-complex non-stellar structures such as planetary nebulae, reflection
-nebulae, outflows and jets.
-
-The simplest objects (ie, stars) can be sufficiently modeled by the
-point-source function (PSF).  More complex objects (such as simple,
-smooth galaxies), may have approximate analytical models which
-represent their morphology with more-or-less accuracy.  In the extreme
-cases, the objects are not well modeled at all and must be represented
-in other ways.  Thus, one aspect of our data structures must be
-elements to specify if an object has been represented by a model, what
-the model parameters are, and how well it is represented by the model.
-Another aspect of the data structures must be a representation of the
-pixels associated with the object so complex structures may be
-referenced without attempting to supply an analytical model.  Finally,
-it is often useful to allow a single complex model to be represented
-as a collection of simpler contained structures which may be modeled.
-Thus, the representation of an object must be capable of identifying
-children, or substructures, of that object.
-
-Two additional aspects must be considered.  First, source detection
-need not be performed on a single image in isolation: it is necessary
-for multiple realizations of the same source in multiple images to be
-measured together (whether or not through simultaneous fitting in
-multiple bands or via application of the results from one image to
-another image).  Second, it will be necessary to performed object
-measurements on pixels in which no source is actually detected.  For
-example, this is a convenient way to provide flux upper limits at the
-locations of known objects.
-
-In the discussion that follows, images are of type F32 and masks are
-of type U8.
-
-\subsection{Structures to Describe Sources}
-
-In the object analysis process, we will use specific mask values to
-mark the image pixels.  The following structure defines the relevant
-mask values.
-\begin{datatype}
-typedef enum {
-    PSPHOT_MASK_CLEAR     = 0x00,
-    PSPHOT_MASK_INVALID   = 0x01,
-    PSPHOT_MASK_SATURATED = 0x02,
-    PSPHOT_MASK_MARKED    = 0x08,
-} psphotMaskValues;
-\end{datatype}
-
-\subsubsection{pmSource and pmPeak}
-
-We define the following structure to represent a single source
-detected in a single image.  
-\begin{datatype}
-typedef struct {
-  pmPeak *peak;            // description of peak pixel
-  psImage *pixels;         // rectangular region including object pixels
-  psImage *weight;         // Image variance.
-  psImage *mask;           // Mask which marks pixels associated with objects.
-  pmMoments *moments;      // basic moments measure for the object
-  pmModel *modelPSF;       // PSF model parameters and type
-  pmModel *modelEXT;       // FLT model parameters and type
-  pmSourceType type;       // Best identification of object
-  pmSourceMode mode;       // flags describing the model quality 
-  psArray *blends;         // array of other sources blended with this source
-  float apMag;             // measured aperture magnitude for source
-  float fitMag;            // measured model magnitude for source
-  psRegion region;         // area on image covered by selected pixels
-} pmSource;
-\end{datatype}
-
-A source has the capacity for several types of measurements.  The
-simplest measurement of a source is the location and flux of the peak
-pixel associated with the source:
-\begin{datatype}
-typedef struct {
-  int x;                   // x-coordinate of peak pixel
-  int y;                   // y-coordinate of peak pixel
-  float counts;            // value of peak pixel (above sky?)
-  pmPeakType class;        // description of peak
-} pmPeak;
-\end{datatype}
-
-A peak pixel may have several features which may be determined when
-the peak is found or measured.  These are specified by the
-\code{pmPeakType} enum.  \code{PM_PEAK_LONE} represents a single pixel
-which is higher than its 8 immediate neighbors.  The
-\code{PM_PEAK_EDGE} represents a peak pixel which touching the image
-edge.  The \code{PM_PEAK_FLAT} represents a peak pixel which has more
-than a specific number of neighbors at the same value, within some
-tolerance:
-\begin{datatype}
-typedef enum {
-  PM_PEAK_LONE,             // isolated peak
-  PM_PEAK_EDGE,             // peak on edge
-  PM_PEAK_FLAT              // peak has equal-value neighbors
-  PM_PEAK_UNDEF             // Undefined.
-} pmPeakType; 
-\end{datatype}
-
-\subsubsection{pmMoments and source description}
-
-The pixels which contain the source are specified with the
-\code{psImage *pixels} element, a subimage of the image being
-analysed.  Similarly, the \code{mask} element is a subimage of the
-corresponding mask image and the \code{weight} element is a subimage
-of the corresponding weight image (image varience).  Since these are
-subimages, a collection of many objects may include overlapping
-pixels; care must be taken that pixel manipulations for one source do
-not unintentionally interfere with the other source pixels.  The
-\code{mask} may be used to exclude any pixels which are not considered
-part of the source.  Along with these pixel structures, we include the
-\code{psRegion region} element which defines the boundaries of the
-current associated subimages. 
-
-One of the simplest measurements which can be made quickly for an
-object are the object moments.  We specify a structure to carry the
-moment information for a specific source: 
-
-\begin{datatype}
-typedef struct {
-  float x;                  // x-coord of centroid
-  float y;                  // y-coord of centroid
-  float Sx;                 // x-second moment
-  float Sy;                 // y-second moment 
-  float Sxy;                // xy cross moment
-  float Sum;                // pixel sum above sky (background)
-  float Peak;               // peak counts above sky
-  float Sky;                // sky level (background)
-  float SN;                 // approx signal-to-noise
-  int   nPixels;            // number of pixels used
-} pmMoments;
-\end{datatype}
-
-A collection of object moment measurements can be used to determine
-approximate object classes.  The key to this analysis is the location
-and statistics (in the second-moment plane, $\sigma_x$ vs $\sigma_y$)
-of the group of objects which are likely PSF objects.  We define the
-following structure to identify the location and size of the psf clump
-in the second-moment plane.
-\begin{datatype}
-typedef struct {
-    float X;
-    float dX;
-    float Y;
-    float dY;
-} pmPSFClump;
-\end{datatype}
-
-A given source may be identified as most-likely to be one of several
-source types.  The \code{pmSource} entry \code{pmSourceType} defines
-the current best-guess for this source.  
-
-\begin{datatype}
-typedef enum {
-    PM_SOURCE_UNKNOWN,                  ///< no guess yet made
-    PM_SOURCE_DEFECT,                   ///< a cosmic-ray
-    PM_SOURCE_SATURATED,                ///< random saturated pixels
-    PM_SOURCE_STAR,                     ///< a good-quality star
-    PM_SOURCE_EXTENDED,                 ///< an extended object (eg, galaxy)
-} pmSourceType;
-\end{datatype}
-
-The related element, \code{pmSourceMode mode}, holds a collection of flags which
-are used to indicate the status of the analysis for a source.  These
-are defined below:
-\begin{datatype} 
-typedef enum {
-    PM_SOURCE_DEFAULT    = 0x0000, ///< no flags are set
-    PM_SOURCE_PSFMODEL   = 0x0001, ///< flags refer to the PSF model
-    PM_SOURCE_EXTMODEL   = 0x0002, ///< flags refer to the EXT model
-    PM_SOURCE_SUBTRACTED = 0x0004, ///< the model has been subtracted from the image
-    PM_SOURCE_FITTED     = 0x0008, ///< the source has been fitted with a model
-    PM_SOURCE_FAIL       = 0x0010, ///< the model fit failed
-    PM_SOURCE_POOR       = 0x0020, ///< the model fit was poor (low S/N, etc)
-    PM_SOURCE_PAIR       = 0x0040, ///< the model fit is one of a paired source
-    PM_SOURCE_PSFSTAR    = 0x0080, ///< the source was used to construct the image PSF model
-    PM_SOURCE_SATSTAR    = 0x0100, ///< the source is saturated
-    PM_SOURCE_BLEND      = 0x0200, ///< the source is a blend with another source
-    PM_SOURCE_LINEAR     = 0x0400, ///< the source was fitted with the linear PSF model
-    PM_SOURCE_TEMPSUB    = 0x0800, ///< the source has been subtracted, but should be replaced
-} pmSourceMode;
-\end{datatype}
-
-\subsubsection{pmModel Source Model and Abstraction} 
-
-An object's flux distribution may be modeled with some analytical
-function.  The description of the model includes the model parameters
-and their errors, along with the fit $\chi^2$.  The model type is
-identified by code \code{type}, dynamically assigned based on the
-available models (see below).  We discuss the details of these models
-in section~\ref{ObjectModels}.  The model parameters have 4 special
-elements.  The first four elements represent aspects of the source
-which are not specified by the image PSF, even for point sources.  
-These consist of, in order:
-\begin{itemize}
-\item the local sky
-\item the object normalization
-\item the x-coordinate
-\item the y-coordinate
-\end{itemize}
-
-\tbd{should be include utility pointers to these parameters so that
-  functions do not need to know the parameter sequence?}
-
-The structure which carries the information about a given source model
-is defined below:
-\begin{datatype}
-typedef struct {
-  pmModelType type;         // model to be used
-  psVector *params;         // parameter values
-  psVector *dparams;        // parameter errors
-  psF32 chisq;              // fit chisq
-  psS32 nDOF;               // number of degrees of freedom
-  psS32 nIter;              // number of iterations
-  pmModelStatus status;     // fit status
-  float radius;             // fit radius actually used
-} pmModel;
-\end{datatype}
-
-The \code{status} element carries the resulting success/failure status
-of an attempt to fit the model to the source:
-\begin{datatype}
-typedef enum {
-    PM_MODEL_UNTRIED,               ///< model fit not yet attempted
-    PM_MODEL_SUCCESS,               ///< model fit succeeded
-    PM_MODEL_NONCONVERGE,           ///< model fit did not converge
-    PM_MODEL_OFFIMAGE,              ///< model fit drove out of range
-    PM_MODEL_BADARGS                ///< model fit called with invalid args
-} pmModelStatus;
-\end{datatype}
-
-We distinguish several ways in which an analytical model may be
-applied to a source.  The PSF model represents the best fit of the
-image PSF to the specific object.  In this case, the PSF-dependent
-parameters are specified for the object by the PSF, not by the fit.
-The EXT model represents the best fit of the given model to the
-object, with all parameters floating in the fit.  Such a model would
-typically be used to represent and extended object, hence the
-abbreviation EXT.  In some circumstances, a source may be fitted with
-a PSF model in which the position is held fixed, and not allowed to
-vary in the model fitting process.  We identify such a model as FIX.
-Finally, we allow for the case in which two nearly-merged PSFs are
-fitted with a single 2-PSF model.  We identify such a model as DBL.
-The \code{pmSource} structure contains a pointer to both a PSF and an
-EXT model, allowing any source to carry information about both
-possible fitting modes \tbd{not clear that we actually use this
-information; we might be better off simply distinguishing with one of
-the pmSourceMode flags}.  The value of the model at a specific
-coordinate can be determined by calling the function:
-\begin{prototype}
-psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row);
-\end{prototype}
-For this function, the values of \code{col,row} are in the
-\code{image} coordinates, which may be a subimage, while the reference
-coordinate for the model is in the parent image coordinates.
-
-In the \code{pmSource} structure, the elements \code{apMag} and
-\code{fitMag} are used to carry the measured magnitude of the source
-determined either from aperture photometry or from the integral of the
-fitted model function.  The element \code{blends} is used to carry
-pointers to the collection of sources which were found to be blended
-with this source.  Only the primary source of a blend group carries
-this information.%%% (see Section~\ref{blends}).
-
-Every model instance belongs to a class of models, defined by the
-value of the \code{pmModelType type} entry.  Various functions need
-access to information about each of the models.  Some of this
-information varies from model to model, and may depend on the current
-parameter values or other data quantities.  In order to keep the code
-from requiring the information about each model to be coded into the
-low-level fitting routines, we define a collection of functions which
-allow us to abstract this type of model-dependent information.  These
-generic functions take the model type and return the corresponding
-function pointer for the specified model.  Each
-model is defined by creating this collection of specific functions,
-and placing them in a single file for each model.  We define the
-following structure to carry the collection of information about the
-models. 
-
-\begin{datatype}
-typedef struct {
-    char *name;
-    int nParams;
-    pmModelFunc          modelFunc;
-    pmModelFlux          modelFlux;
-    pmModelRadius        modelRadius;
-    pmModelLimits        modelLimits;
-    pmModelGuessFunc     modelGuessFunc;
-    pmModelFromPSFFunc   modelFromPSFFunc;
-    pmModelFitStatusFunc modelFitStatusFunc;
-} pmModelGroup;
-\end{datatype}
-
-Each entry in the \code{pmModelGroup} defines the information needed
-by the system to specify a model.  The function types define above are
-\begin{prototype}
-typedef psMinimizeLMChi2Func pmModelFunc;
-typedef psF64 (*pmModelFlux)(const psVector *params);
-typedef psF64 (*pmModelRadius)(const psVector *params, double flux);
-typedef bool (*pmModelLimits)(psVector **beta_lim, psVector **params_min, psVector **params_max);
-typedef bool (*pmModelGuessFunc)(pmModel *model, pmSource *source);
-typedef bool (*pmModelFromPSFFunc)(pmModel *modelPSF, pmModel *modelFLT, pmPSF *psf);
-typedef bool (*pmModelFitStatusFunc)(pmModel *model);
-\end{prototype}
-
-Each of these functions is found for a given model by calling the
-corresponding lookup function:
-\begin{prototype}
-pmModelFunc          pmModelFunc_GetFunction (pmModelType type);
-pmModelFlux          pmModelFlux_GetFunction (pmModelType type);
-pmModelRadius        pmModelRadius_GetFunction (pmModelType type);
-pmModelLimits        pmModelLimits_GetFunction (pmModelType type);
-pmModelGuessFunc     pmModelGuessFunc_GetFunction (pmModelType type);
-pmModelFromPSFFunc   pmModelFromPSFFunc_GetFunction (pmModelType type);
-pmModelFitStatusFunc pmModelFitStatusFunc_GetFunction (pmModelType type);
-\end{prototype}
-
-\code{pmModelFunc} is the function used to determine the value of the
-model at a specific coordinate, and is the one used by
-\code{psMinimizeLMChi2}.  
-
-\code{pmModelFlux} returns the total integrated flux for the given
-input parameters.
-
-\code{pmModelRadius} returns the scaling radius at which the flux of
-the model matches the specified flux.  This presumes that the model is
-a function of an elliptical contour.  
-
-\code{pmModelLimits} sets the parameter limit vectors for the
-function.
-
-\code{pmModelGuessFunc} generates an initial guess for the model based
-on the provided source statistics (moments and pixel values as
-needed).
-
-\code{pmModelFromPSFFunc} takes as input a representation of the psf
-and a value for the model and fills in the PSF parameters of the
-model.  The input primarily relies upon the centroid coordinates of
-the input model, thought the normalization may potentially be used.
-
-\code{pmModelFitStatusFunc} returns a true or false values based on
-the success or failure of a model fit.  the success is determined by
-quantities such as the chisq or the signal-to-noise.
-
-In addition, the following functions are useful for interacting with
-the collection of models:
-\begin{prototype}
-int                  pmModelParameterCount (pmModelType type);
-\end{prototype}
-This function returns the number of parameters used by the listed
-function.
-
-\begin{prototype}
-char                *pmModelGetType (pmModelType type);
-pmModelType          pmModelSetType (char *name);
-\end{prototype}
-These two functions provide translations between the user-space model
-names and the internal model type codes.  The model type codes are not
-necessarily maintained between compilations of the program; the name
-should be used to transfer models between programs or systems.
-
-\subsubsection{pmGrowthCurve}
-
-When the photometry of source is measured in a fixed aperture, there
-is always a fraction of the source light which falls outside of the
-aperture.  The resulting aperture magnitude is thus larger (ie,
-fainter) than the actual source.  As the aperture is increased, the
-amount of loss decreases and the measured magnitude increases.  This
-trend is the curve of growth for the source.  We use the following
-structure to carry information about the curve of growth.  We use the
-PSF model to measure the curve of growth for an image.  
-
-\begin{datatype}
-typedef struct {
-    psVector *radius;
-    psVector *apMag;
-    psF32 refRadius;
-    psF32 maxRadius;
-    psF32 fitMag;
-    psF32 apRef;   // apMag[refRadius]
-    psF32 apLoss;  // fitMag - apRef
-} pmGrowthCurve;
-\end{datatype}
-In this structure, \code{radius} is a monotonically increasing
-sequence of radius values (in pixels).  The \code{apMag} vector
-contains the measured magnitude at any of these radius: this is the
-curve-of-growth trend.  The remaining entries summaries the
-relationship: \code{refRadius} is the global reference radius used for
-this image; \code{maxRadius} is the outermost radius at which the
-curve of growth was measured; \code{fitMag} is the fitted PSF model
-magnitude integrated to infinity; \code{apRef} is the aperture
-magnitude at the reference radius; \code{apLoss} is the difference
-between the aperture magnitude at the reference radius and the fitted
-model magnitude.  A few related functions are specified to interact
-with the curve of growth:
-
-\begin{prototype}
-pmGrowthCurve *pmGrowthCurveAlloc (psF32 minRadius, psF32 maxRadius, psF32 dRadius);
-\end{prototype}
-This function allocates a \code{pmGrowthCurve} structure and fills in
-the \code{radius} vector (see psLib SDRS \code{psVectorCreate}).  It
-does {\em not} allocate the \code{apMag} vector.
-
-\begin{prototype}
-psF32 pmGrowthCurveCorrect (pmGrowthCurve *growth, psF32 radius);
-\end{prototype}
-This function accepts a \code{growth} curve structure and returns the
-correction between the specified radius and the reference radius
-($apMag(refRadius) - apMag(radius)$).
-
-The following two functions are used to search the growth curve to the
-corresponding radius entry:
-\begin{prototype}
-int psVectorBracket (psVector *index, psF32 key, bool above);
-psF32 psVectorInterpolate (psVector *index, psVector *value, psF32 key);
-\end{prototype}
-
-\subsubsection{Aperture Trends}
-
-With PSF model fitting, there is always some discrepancy between the
-model of the PSF and the actual PSF.  As a result, the measured flux
-from the model will not represent exactly the flux of the source.  It
-is necessary to measure the correction between the model and the
-actual source flux.  One way to perform this measurement is to compare
-the model flux with the flux measured for bright stars within a fixed
-aperture.  The quantity to be measured is $dA = m_{\rm aperture} -
-m_{\rm fit}$.  In practice, $dA$ exhibits variations as a function of
-the source position ($x,y$) and the source flux.  The variations as a
-function of source position can be understood as a change in the PSF
-model error as a function of position due to the changing shape of the
-PSF (despite the varying PSF model, it is possible that the fitted
-model yields positional variations in the residual flux).  The
-variations in $dA$ as a function of magnitude can be understood as the
-result of a bias in the local background measurement (for the fainter
-sources) and as a result of non-linearity in the detector setting on
-the bright end.  We use a 4D polynomial to represent these trends.
-The first two dimensions of the polynomial represent the variation of
-$dA$ as a function of $x,y$; we provide helper functions to define 1st
-and 2nd order polynomials in $x,y$.  The next two dimensions are
-fitted independently (no cross terms).  The first represents the
-variation as a function of $r^2 / flux$, where $r$ is the aperture
-radius used to measure $dA$; this is the scaling of a magnitude error
-in the presence of a constant error in the sky level.  The last
-dimension represents the variation of $dA$ as a function of the
-stellar flux.
-
-The following forms of the aperture correction model may be selected
-by the user:
-\begin{datatype}
-typedef enum {
-    PM_PSF_NONE,
-    PM_PSF_CONSTANT,
-    PM_PSF_SKYBIAS,
-    PM_PSF_SKYSAT,
-    PM_PSF_XY_LIN,
-    PM_PSF_XY_QUAD,
-    PM_PSF_SKY_XY_LIN,
-    PM_PSF_SKYSAT_XY_LIN,
-    PM_PSF_ALL
-} pmPSF_ApTrendOptions;
-\end{datatype}
-
-The following utility function sets the aperture correction model
-coefficient masks to select the specific desired coefficients:
-\begin{prototype}
-bool pmPSF_MaskApTrend (pmPSF *psf, pmPSF_ApTrendOptions option);
-\end{prototype}
-
-\subsubsection{pmPSF, pmPSFtry, and PSF model} 
-
-It is useful to generate a model to define the point-spread-function
-which describes the flux distribution for unresolved sources in an
-image.  In general, the PSF varies with position in the image.  We
-allow any of the source models defined for the \code{pmModel} to
-represent the PSF.  For a given source model, the 2D spatial variation
-of all of the source parameters, except the first four PSF-independent
-parameters, are represented as polynomial, stored in a \code{psArray}.
-The structure also contains the aperture correction model
-(\code{ApTrend}) and the curve-of-growth model (\code{growth}).  The
-additional elements are: \code{ApResid}, the constant term in the
-aperture correction model; \code{dApResid}, the residual scatter for
-bright sources ($S/N > 100$) after applying the aperture correction;
-\code{skyBias}, the measured average bias in the sky measurement;
-\code{skySat}, the scaling of the flux-dependent portion of the
-correction.
-
-The other elements of the structure define the quality of the PSF
-determination.  
-
-\begin{datatype}
-typedef struct {
-    pmModelType type;                   ///< PSF Model in use
-    psArray *params;                    ///< Model parameters (psPolynomial2D)
-    psPolynomial4D *ApTrend;            ///< ApResid vs (x,y,rflux) (rflux = ten(0.4*mInst)
-    pmGrowthCurve *growth;              ///< apMag vs Radius
-    float ApResid;                      ///< ???
-    float dApResid;                     ///< ???
-    float skyBias;                      ///< ???
-    float skySat;                       ///< ???
-    float chisq;                        ///< PSF goodness statistic
-    int nPSFstars;                      ///< number of stars used to measure PSF
-    int nApResid;                       ///< number of stars used to measure ApResid
-} pmPSF;
-\end{datatype}
-
-\begin{prototype}
-pmModel *pmModelFromPSF (pmModel *model, pmPSF *psf);
-\end{prototype}
-This function constructs a \code{pmModel} instance based on the
-\code{pmPSF} description of the PSF.  The input is a \code{pmModel}
-with at least the values of the centroid coordinates (possibly
-normalization if this is needed) defined.  The values of the
-PSF-dependent parameters are specified for the specific realization
-based on the coordinates of the object.  
-
-\begin{prototype}
-bool pmPSFFromModels (pmPSF *psf, psArray *models, psVector *mask);
-\end{prototype}
-This function takes a collection of \code{pmModel} fitted models from
-across a single image and builds a \code{pmPSF} representation of the
-PSF.  The input array of model fits may consist of entries to be
-ignored (noted by a non-zero \code{mask} entry).  The analysis of the
-models fits a 2D polynomial for each parameter to the collection of
-model parameters as a function of position (and normalization?).  In
-this process, some of the input models may be marked as outliers and
-excluded from the fit.  These elements will be marked with a specific
-mask value (1 == \code{PSFTRY_MASK_OUTLIER}).  
-
-We definet he following two functions to convert the PSF model
-parameters into a collection of elements on a metadata structure, and
-vice versa.  These can be used to read and write PSFs to a file and or
-a database.
-\begin{prototype}
-psMetadata *pmPSFtoMD (psMetadata *metadata, pmPSF *psf);
-pmPSF *pmPSFfromMD (psMetadata *metadata);
-\end{prototype}
-
-We have the capability to test several different model functions in an
-attempt to build an accurate PSF for an image.  The complete set of
-data needed to build and test as specific PSF model is carried by the
-\code{pmPSFtry} structure:
-\begin{datatype}
-typedef struct {
-    pmModelType modelType;
-    pmPSF      *psf;
-    psArray    *sources;      // pointers to the original sources
-    psArray    *modelEXT;     // model fits, floating parameters 
-    psArray    *modelPSF;     // model fits, PSF parameters
-    psVector   *mask;
-    psVector   *metric;
-    psVector   *fitMag;
-} pmPSFtry;
-\end{datatype}
-This structure contains a pointer to the collection of \code{sources}
-which will be used to test the PSF model form.  It lists the
-\code{pmModelType type} of model being tests, and contains an element
-to store the resulting \code{psf} representation.  In addition, this
-structure carries the complete collection of FLT (floating parameter)
-and PSF (fixed parameter) model fits to each of the sources
-\code{modelFLT} and \code{modelPSF}.  It also contains a mask which is
-set by the model fitting and psf fitting steps.  For each model, the
-value of the quality metric is stored in the vector \code{metric} and
-the fitted instrumental magnitude is stored in \code{fitMag}.  The
-quality metric for the PSF model is the aperture magnitude minus the
-fitted magnitude for each source.  
-
-This collection of aperture residuals is examined in the analysis
-process, and a linear trend of the residual with the inverse object
-flux (ie, $10^{0.4*mag}$) is fitted.  The result of this fit is a
-measured sky bias (systematic error in the sky measured by the fits),
-an effective infinite-magnitude aperture correction (\code{ApResid}),
-and the scatter of the aperture correction for the ensemble of PSF
-stars (\code{dApResid}).  The ultimate metric to intercompare multiple
-types of PSF models is the value of the aperture correction scatter.
-
-The following functions are used to try out a single PSF model.
-\begin{prototype}
-pmPSFtry *pmPSFtryModel (psArray *sources, char *modelName, float RADIUS);
-\end{prototype}
-This function takes the input collection of sources and performs a
-complete analysis to determine a PSF model of the given type
-(specified by model name).  The result is a \code{pmPSFtry} with the
-results of the analysis.
-
-\begin{prototype}
-bool pmPSFtryMetric (pmPSFtry *try, float RADIUS);
-\end{prototype}
-This function is used to measure the PSF model metric for the set of
-results contained in the \code{pmPSFtry} structure.
-
-The following datatype defines the masks used by the \code{pmPSFtry}
-analysis to identify sources which should or should not be included in
-the analysis.
-\begin{datatype}
-enum {
-    PSFTRY_MASK_CLEAR    = 0x00,
-    PSFTRY_MASK_OUTLIER  = 0x01, // 1: outlier in psf polynomial fit (provided by psPolynomials)
-    PSFTRY_MASK_EXT_FAIL = 0x02, // 2: ext model failed to converge 
-    PSFTRY_MASK_PSF_FAIL = 0x04, // 3: psf model failed to converge 
-    PSFTRY_MASK_BAD_PHOT = 0x08, // 4: invalid source photometry           
-    PSFTRY_MASK_ALL      = 0x0f,
-} pmPSFtryMaskValues;
-\end{datatype}
-
-
-\begin{datatype}
-typedef enum {
-  PM_CONTOUR_CRUDE
-} pmContourType; 
-\end{datatype}
-
-Allocators for the above structures are defined as follows:
-\begin{prototype}
-pmSource   *pmSourceAlloc ();
-pmPeak     *pmPeakAlloc (int x, int y, float counts, psPeakType class);
-pmMoments  *pmMomentsAlloc ();
-pmModel    *pmModelAlloc (pmModelType type);
-\end{prototype}
-
-\subsection{Basic Object Detection APIs}
-
-In this section, we specify a collection of basic functions which
-operate on images and sources.  We define them roughly in order in
-which we expect to use them in a basic object detection process.
-
-\begin{prototype}
-psVector *pmFindVectorPeaks(const psVector *vector, float threshold);
-\end{prototype}
-
-Find all local peaks in the given vector above the given threshold.  A
-peak is defined as any element with a value greater than its two
-neighbors and with a value above the threshold.  Two types of special
-cases must be addressed.  Equal value elements: If an element has the
-same value as the following element, it is not considered a peak.  If
-an element has the same value as the preceding element (but not the
-following), then it is considered a peak.  Note that this rule
-(arbitrarily) identifies flat regions by their trailing edge.  Edge
-cases: At start of the vector, the element must be higher than its
-neighbor.  At the end of the vector, the element must be higher or
-equal to its neighbor.  These two rules again places the peak
-associated with a flat region which touches the image edge at the
-image edge.  The result of this function is a vector containing the
-coordinates (element number) of the detected peaks (type
-\code{psU32}).
-
-\begin{prototype}
-psArray *pmFindImagePeaks(const psImage *image, float threshold);
-\end{prototype}
-
-Find all local peaks in the given image above the given threshold.
-This function should find all row peaks using
-\code{pmFindVectorPeaks}, then test each row peak and exclude peaks
-which are not local peaks.  A peak is a local peak if it has a higher
-value than all 8 neighbors.  If the peak has the same value as its +y
-neighbor or +x neighbor, it is NOT a local peak.  If any other
-neighbors have an equal value, the peak is considered a valid peak.
-Note two points: first, the +x neighbor condition is already enforced
-by \code{pmFindVectorPeaks}.  Second, these rules have the effect of
-making flat-topped regions have single peaks at the (+x,+y) corner.
-When selecting the peaks, their type must also be set.  The result of
-this function is an array of \code{pmPeak} entries.  The resulting set
-of peaks should be considered a starting point, not an unambiguous
-sample of the only real peaks.  If the input image is a subimage, the
-output peak coordinates should be in the {\em parent} coordinate
-frame.
-
-\begin{prototype}
-psArray *pmPeaksSubset(psArray *peaks, float maxvalue, const psRegion valid);
-\end{prototype}
-
-Create a new peaks array, removing certain types of peaks from the
-input array of peaks based on the given criteria.  Peaks should be
-eliminated if they have a peak value above the given maximum value
-limit or if the fall outside the valid region.  The result of the
-function is a new array with a reduced number of peaks.
-
-\begin{prototype}
-bool pmSourceDefinePixels(pmSource *mySource, 
-                          pmReadout *readout,
-                          psF32 x, 
-                          psF32 y,
-                          psF32 Radius)
-
-bool pmSourceRedefinePixels(pmSource *mySource, 
-                            pmReadout *readout,
-                            psF32 x, 
-                            psF32 y,
-                            psF32 Radius)
-\end{prototype}
-
-The first form defines \code{psImage} subarrays (pixel, weight, and
-mask) for the source located at coordinates \code{x,y} on the image
-set defined by \code{readout} (in parent coords).  The pixels defined
-by this operation consist of a square window (of full width $2 Radius
-+ 1$) centered on the pixel which contains the given coordinate, in
-the frame of the readout.  The window is defined to have limits which
-are valid within the boundary of the \code{readout} image, thus if the
-radius would fall outside the image pixels, the subimage is truncated
-to only consist of valid pixels.  If \code{readout->mask} or
-\code{readout->weight} are not \code{NULL}, matching subimages are
-defined for those images as well.  This function fails if no valid
-pixels can be defined (x or y less than Radius, for example).  This
-function should be used to define a region of interest around a
-source, including both source and sky pixels.  The second form accepts
-an existing source and redefines the pixels if the requested radius
-encompasses more pixels than the existing images.
-
-\begin{prototype}
-pmSource *pmSourceLocalSky(pmSource *source,
-                           psStatsOptions statsOptions,
-                           float Radius)
-\end{prototype}
-
-Measure the local sky in the vicinity of the given \code{source}.  The
-\code{Radius} defines the square aperture in which the moments will be
-measured.  This function assumes the source pixels have been defined,
-and that the value of \code{Radius} here is smaller than the value of
-\code{Radius} used to define the pixels.  The annular region not
-contained within the radius defined here is used to measure the local
-background in the vicinity of the source.  The local background
-measurement uses the specified statistic passed in via the
-\code{statsOptions} entry.  This function allocates the
-\code{pmMoments} structure.  The resulting sky is used to set the
-value of the \code{pmMoments.sky} element of the provided
-\code{pmSource} structure.  
-
-\begin{prototype}
-bool pmSourceMoments(pmSource *source, float radius);
-\end{prototype}
-
-Measure source moments for the given \code{source}, using the value of
-\code{source.moments.sky} provided as the local background value and
-the peak coordinates as the initial source location.  The resulting
-moment values are applied to the \code{source.moments} entry, and the
-source is returned.  The moments are measured within the given
-circular radius of the \code{source.peak} coordinates.  The return
-value indicates the success (TRUE) of the operation.  This function
-also measures the approximate signal-to-noise ratio of the source
-(\code{source.SN}) based on the total number of source counts divided
-by the square-root of the total source variance, as determined from
-the weight image.
-
-\begin{prototype}
-pmPSFClump pmSourcePSFClump(psArray *sources, psMetadata *metadata);
-\end{prototype}
-
-We use the source moments to make an initial, approximate source
-classification, and as part of the information needed to build a PSF
-model for the image.  As long as the PSF shape does not vary
-excessively across the image, the sources which are represented by a
-PSF (the start) will have very similar second moments.  The function
-\code{pmSourcePSFClump} searches a collection of \code{sources} with
-measured moments for a group with moments which are all very similar.
-The function returns a \code{pmPSFClump} structure, representing the
-centroid and size of the clump in the $\sigma_x$, $\sigma_y$
-second-moment plane.  
-
-The goal is to identify and characterize the stellar clump within the
-$\sigma_x, \sigma_y$ plane.  To do this, an image is constructed to
-represent this plane.  The units of $\sigma_x$ and $\sigma_y$ are in
-image pixels.  A pixel in this analysis image represents 0.1 pixels in
-the input image.  The dimensions of the image need only be 10 pixels.
-The peak pixel in this image (above a threshold of half of the image
-maximum) is found.  The coordinates of this peak pixel represent the
-2D mode of the $\sigma_x, \sigma_y$ distribution.  The sources with
-$\sigma_x, \sigma_y$ within 0.2 pixels of this value are then used to
-calculate the median and standard deviation of the $\sigma_x,
-\sigma_y$ values.  These resulting values are returned via the
-\code{pmPSFClump} structure.
-
-The return value indicates the success (TRUE) of the operation.
-
-\tbd{limit the S/N of the candidate sources (part of Metadata)?} 
-
-\tbd{save the clump parameters on the Metadata} 
-
-\begin{prototype}
-bool pmSourceRoughClass(psArray *sources, psMetadata *metadata, pmPSFClump clump)
-\end{prototype}
-
-Based on the specified data values, make a guess at the source
-classification.  The sources are provides as a \code{psArray} of
-\code{pmSource} entries.  Definable parameters needed to make the
-classification are provided to the routine with the \code{psMetadata}
-structure.  The rules below refer to values which can be extracted
-from the metadata using the given keywords.  Except as noted, the data
-type for these parameters are \code{psF32}.
-
-The following rules are used to make the classification.  The number
-of saturated pixels are counted, based on the mask having the
-\code{PSPHOT_MASK_SATURATED} bit set.  Sources which are greater than
-1$\sigma$ larger than the \code{pmPSFClump} center in both dimensions
-and which have more than a single saturated pixel are identified as
-being a likely saturated star (\code{type = PM_SOURCE_STAR, mode =
-PM_SOURCE_SATSTAR}).  Sources which are not so large but which have
-multiple saturated pixels are identified as saturated regions, ie
-bleed trails or hot columns (\code{type = PM_SOURCE_SATURATED}).
-
-Sources with 
-\[ \sigma_x < 0.05 \]
-or
-\[ \sigma_y < 0.05\]
-should be identified as type \code{PM_SOURCE_DEFECT} (likely cosmic
-ray pixel).
-
-Sources with
-\[ \sigma_x > \mbox{CLUMP}_{x} + 3\mbox{CLUMP}_{dx}\]
-and 
-\[ \sigma_y > \mbox{CLUMP}_{y} + 3\mbox{CLUMP}_{dy}\]
-should be identified as type \code{PM_SOURCE_EXTENDED}.  
-
-All other sources should be identified as type \code{PM_SOURCE_STAR}.
-Of these sources, the mode should be set to \code{PM_SOURCE_PSFSTAR}
-for any sources with $SN$ greater than \code{PSF_SN_LIM} which are
-within 1.5$\sigma$ of the PSF clump center.  These sources are used to
-determine a guess at the shape of the PSF, based on the collection of
-$\sigma_x$ and $\sigma_y$ values.
-
-\subsection{Object Fitting}
-
-We need a way to fit a particular functional model to an object.
-PSLib includes the \code{psMinimizeLMChi2} and \code{psMinimizePowell}
-functions, which form the core of this processes.  However, additional
-support functions and wrapping functions are necessary for the
-specific case of source fitting.  The operations can be broken down
-into discrete steps:
-
-\begin{enumerate}
-\item Identify the pixels of interest
-
-\item Make a guess at the model parameters.  For some models, the
-parameters may be guessed based on only the moments.  For others,
-additional measurements must be made.
-
-\item Construct the input vectors from the pixels of interest.
-
-\item Apply fitting function \code{psMinimizeLMChi2()}
-
-\item Construct model image.
-
-\item Subtract model from image.
-\end{enumerate}
-
-\begin{prototype}
-bool pmSourceModelGuess(pmSource *source, const psImage *image, pmModelType model);
-\end{prototype}
-
-Convert available data to an initial guess for the given model.  This
-function allocates a \code{pmModel} entry for the \code{pmSource}
-structure based on the provided model selection.  The method of
-defining the model parameter guesses are determined by using
-\code{pmModelGuessFunc_GetFunction} to determine the guess function
-for the model of interest.  The returned function is called and the
-guess values are used to set the model parameters.  The function
-returns \code{TRUE} on success or \code{FALSE} on failure.
-
-\begin{prototype}
-psArray *pmSourceContour(const pmSource *source, const psImage *image, float level, pmContourType type);
-\end{prototype}
-
-Find points in a contour for the given source at the given level.  If
-\code{type} is \code{PM_CONTOUR_CRUDE}, the contour is found by starting at
-the source peak, running along each pixel row until the level is
-crossed, then interpolating to the level coordinate for that row.
-This is done for each row, with the starting point determined by the
-midpoint of the previous row, until the starting point has a value
-below the contour level.  The returned contour consists of two vectors
-giving the x and y coordinates of the contour levels.  This function
-may be used as part of the model guess inputs.
-
-\tbd{Other contour types may be specified in the future for more refined contours}
-
-\begin{prototype}
-bool pmSourceFitModel(pmSource *source, psImage *image);
-\end{prototype}
-
-Fit the requested model to the specified source.  The starting guess
-for the model is given by the input \code{source.model} parameter
-values.  The pixels of interest are specified by the
-\code{source.pixels} and \code{source.mask} entries.  This function
-calls \code{psMinimizeLMChi2()} on the image data.  The function
-returns \code{TRUE} on success or \code{FALSE} on failure.
-
-\begin{prototype}
-bool pmModelFitStatus (pmModel *model);
-\end{prototype}
-
-This function wraps the call to the model-specific function returned
-by \code{pmModelFitStatusFunc_GetFunction}.  The model-specific
-function examines the model parameters, parameter errors, Chisq, S/N,
-and other parameters available from \code{model} to decide if the
-particular fit was successful or not.
-
-\begin{prototype}
-bool pmSourceAddModel(psImage *image, pmSource *source, bool center, bool sky);
-bool pmSourceSubModel(psImage *image, pmSource *source, bool center, bool sky);
-\end{prototype}
-
-Add or subtract the given source model flux to/from the provided
-image.  The boolean option \code{center} selects if the source is
-re-centered to the image center or if it is placed at its centroid
-location.  The boolean option \code{sky} selects if the background sky
-is applied (\code{TRUE}) or not.  The pixel range in the target image
-is at most the pixel range specified by the \code{source.pixels}
-image.  The success status is returned.
-
-\begin{prototype}
-bool pmSourcePhotometry (float *fitMag,  // integrated fit magnitude
-                         float *obsMag,  // aperture flux magnitude
-                         pmModel *model, // model used for photometry
-                         psImage *image, // image pixels to be used
-                         psImage *mask   // mask of pixels to ignore
-);
-\end{prototype}
-
-The function returns both the magnitude of the fit, defined as $-2.5
-\log{\rm flux}$, where the flux is integrated under the model,
-theoretically from a radius of 0 to infinity.  In practice, we
-integrate the model beyond $50 \sigma$.  The aperture magnitude is
-defined as $-2.5 \log{\rm flux}$, where the flux is summed for all
-pixels which are not excluded by the aperture mask.  The model flux is
-calculated by calling the model-specific function provided by
-\code{pmModelFlux_GetFunction}.
-
-\begin{prototype}
-int pmSourceDophotType (pmSource *source);
-\end{prototype}
-This function converts the source classification into the closest
-available approximation to the Dophot classification scheme.  The
-following list gives the correspondence:
-\begin{verbatim}
-PM_SOURCE_DEFECT:       8
-PM_SOURCE_SATURATED:    8
-PM_SOURCE_SATSTAR:      10
-PM_SOURCE_PSFSTAR:      1
-PM_SOURCE_GOODSTAR:     1
-PM_SOURCE_POOR_FIT_PSF: 7
-PM_SOURCE_FAIL_FIT_PSF: 4
-PM_SOURCE_FAINTSTAR:    4
-PM_SOURCE_GALAXY:       2
-PM_SOURCE_FAINT_GALAXY: 2
-PM_SOURCE_DROP_GALAXY:  2
-PM_SOURCE_FAIL_FIT_GAL: 2
-PM_SOURCE_POOR_FIT_GAL: 2
-PM_SOURCE_OTHER:        ?
-\end{verbatim}
-
-\begin{prototype}
-int pmSourceSextractType (pmSource *source);
-\end{prototype}
-This function converts the source classification into the closest
-available approximation to the Sextractor classification scheme.
-\tbd{the correspondence is not yet defined}.
-
-\subsection{Object List Input/Output}
-
-We support several object catalog formats.  Some of these mimic the
-formats used by the Elixir system to support testing with existing
-data and software.  Some of these are for use by the Pan-STARRS
-project for testing.
-
-\subsubsection{OBJ Format}
-
-This format is produced by versions of DoPhot and is used by the
-Elixir system as an intermediate output data product.  The objects are
-written to a text file with fixed line-length and with fixed column
-positions.  The file has no header associated with it.  This is only
-an output format, and should be used just for testing and comparison
-with the Elixir tools.
-
-\subsubsection{SX Format}
-
-This format is produced by versions of Sextractor and is used by the
-Elixir system as an intermediate output data product.  The objects are
-written to a text file with fixed line-length and with fixed column
-positions.  The file has no header associated with it.  This is only
-an output format, and should be used just for testing and comparison
-with the Elixir tools.  The SX and OBJ formats are similar, but use a
-somewhat different definition of the columns.
-
-\subsubsection{CMP Format}
-
-This format is used extensively by the Elixir system, and many data
-files are available in this format.  The format is a pseudo-FITS
-format, consisting of a FITS header (with NAXIS=2) and a text data
-segment with fixed line length.  The CMP files are always in SPLIT
-format in the sense that each object table is a single file. 
-
-\subsubsection{CMF Format}
-
-This format is a true FITS table format.  The object data is stored
-for each readout in a separate extension.  In addition, the Cell
-headers are stored in their own extensions (with NAXIS=0).  In SPLIT
-format, the Cell header is the PHU header.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Image Combination}
-
-The image combination for \PS{} will employ an iterative approach, in
-order to identify cosmic rays.  The first pass involves transforming
-and combining the input images, and noting pixels which are apparently
-deviant.  These pixels are examined in further detail, before a subset
-of them are declared to be bad, whereupon these pixels are
-re-transformed, and the images are combined properly.  Here we
-introduce two functions which will perform the combination and
-examination steps.  Prototype code exists for each of these functions.
-\tbd{For further details, see the document about image combination for
-\PS{}.}
-
-\subsection{Combining images}
-
-\begin{prototype}
-psImage *pmCombineImages(psImage *combined, // Combined image
-                         psArray **questionablePixels, // Array of rejection masks
-                         const psArray *images, // Array of input images
-                         const psArray *errors, // Array of input error images
-                         const psArray *masks,// Array of input masks
-                         unsigned int maskVal, // Mask value
-                         const psPixels *pixels, // Pixels to combine
-                         int numIter,   // Number of rejection iterations
-                         float sigmaClip, // Number of standard deviations at which to reject
-                         const psStats *stats // Statistics to use in the combination
-                         );
-\end{prototype}
-
-\code{pmCombineImages} shall combine the input \code{images},
-returning the \code{combined} image and a list of
-\code{questionablePixels} in each input image.  The array of error
-images, \code{errors}, shall be used to calculate the value in the
-combined image and the list of questionable pixels, if
-non-\code{NULL}.  Pixels whose corresponding value in the array of
-mask images, \code{masks}, matches \code{maskVal} shall be masked from
-the combination.  The \code{images}, \code{errors} and \code{masks}
-arrays, if non-\code{NULL}, shall all carry the same number of images;
-otherwise the function shall generate an error and return \code{NULL}.
-The sizes of all images in the \code{images}, \code{errors} and
-\code{masks} arrays shall be identical; otherwise the function shall
-generate an error and return \code{NULL}.
-
-If \code{pixels} is non-\code{NULL}, only those pixels specified shall
-be combined.  The combination consists of \code{numIter} iterations in
-which a stack of pixels is combined using the specified \code{stats}.
-In each iteration, questionable pixels are identified as lying more
-than \code{sigmaClip} standard deviations from the combined value;
-these pixels are excluded from the stack for the next iteration.  The
-value for the combined image is that produced by the \textit{first}
-iteration (i.e., with no pixels excluded except those which have their
-corresponding mask match the \code{maskVal}); this allows subsequent
-calls to the function to only act on a small fraction of the pixels,
-since questionable pixels identified in the first call of the function
-will be properly rejected at a later point (see the example, below).
-
-In the event that \code{images} or \code{stats} are \code{NULL}, the
-function shall generate an error and return \code{NULL}.
-
-\subsection{Rejecting pixels}
-
-\begin{prototype}
-psArray *pmRejectPixels(const psArray *images, // Array of input images
-                        const psArray *masks, // Array of masks for input images
-                        const psArray *pixels, // These are the pixels which were rejected in the combination
-                        const psArray *inToOut, // Transformations from input to output system
-                        const psArray *outToIn, // Transformations from output to input system
-                        float rejThreshold, // Rejection threshold
-                        float gradLimit // Gradient limit
-                        );
-\end{prototype}
-
-\tbd{This algorithm will change: an addition will be made to avoid
-masking pixels in the wings of a star when combining images taken in
-different seeing, and the gradient limit criteria will be changed.}
-
-\code{pmRejectPixels} inspects those questionable \code{pixels}
-identified by \code{pmCombineImages} to determine if they are truly
-discrepant.  This inspection is performed in the coordinate frame of
-the detector, where the pixels haven't been smeared by transformation.
-Two tests are applied to each of the \code{images}:
-\begin{enumerate}
-\item The list of questionable pixels for an image is converted to an
-  image which is transformed back to the coordinate frame of the
-  detector.  Those pixels in the detector frame which have a value
-  exceeding \code{rejThreshold} are suspected cosmic rays and
-  subjected to the next test.  Depending on the value of the
-  \code{rejThreshold}, this test basically amounts to demanding that
-  questionable pixels neighbor each other in the transformed image.
-\item The cores of point sources may mimic a cosmic ray, especially in
-  under-sampled images.  To minimize flagging stars as cosmic rays, we
-  determine the gradient around the pixel of interest; if the gradient
-  is large, then the pixel is likely the core of a point source.  In
-  order to reliably measure the gradient in the presence of a
-  suspected cosmic ray, we use the companion images --- the gradient
-  is the mean gradient at the corresponding position on the other
-  images.  In order to calculate the corresponding positions, the
-  \code{inToOut} and \code{outToIn} transformations are required.  If
-  the gradient is less than \code{gradLimit}, then the pixel is
-  identified as a cosmic ray.
-\end{enumerate}
-
-The function shall return an array of \code{psPixels}, one for each of
-the input \code{images}, containing pixels that have been identified
-as cosmic rays according to the above criteria.
-
-If any of the input pointers are \code{NULL}, then the function shall
-generate an error and return \code{NULL}.
-
-\subsection{Example}
-
-Here is an example of what the image combination routine looks like,
-demonstrating how the various pieces fit together.  The inputs are:
-\begin{itemize}
-\item \code{psArray *inputs}: Input detector images, each a
-  \code{psImage} of type \code{psF32}
-\item \code{psArray *inputMask}: Input mask images, each a
-  \code{psImage} of type \code{psU8}
-\item \code{psArray *inputsErr}: Input error images, each a
-  \code{psImage} of type \code{psF32}
-\item \code{psPlaneTransform *skyToDetector}: Maps from sky
-  coordinates to detector coordinates, each a \code{psPlaneTransform}
-\item \code{psRegion *combineRegion}: Sky coordinate pixels to combine
-\item \code{int numIter}: Number of iterations in combination
-\item \code{float rejThreshold}: Threshold for rejection
-\item \code{float gradLimit}: Limit for gradient
-\end{itemize}
-
-The output is the combined image.
-
-\begin{verbatim}
-    psArray *transformed = psArrayAlloc(nImages); // Array of transformed images
-    psArray *transformedErr = psArrayAlloc(nImages); // Array of transformed error images
-    psArray *transformedMask = psArrayAlloc(nImages); // Array of masks for transformed images
-
-    for (int i = 0; i < nImages; i++) {
-        psPixels *blanks = NULL;        // List of blank pixels
-        transformed->data[i] = psImageTransform(NULL, &blanks, inputs->data[i],
-                                                inputMask->data[i], inputMaskVal, NAN, skyToDetector,
-                                                combineRegion, NULL, PS_INTERPOLATE_BILINEAR);
-        transformedErr->data[i] = psImageTransform(NULL, NULL, inputsErr->data[i], inputMask->data[i],
-                                                   inputMaskVal, NAN, skyToDetector, combineRegion, NULL,
-                                                   PS_INTERPOLATE_BILINEAR_VARIANCE);
-        psImage *skyImage = transformed->data[i]; // Dereference the transformed image
-        psRegion *blankRegion = psRegionAlloc(0, 0, skyImage->numCols, skyImage->numRows); // Size of
-                                                                                           // transformed
-                                                                                           // image
-        transformedMask->data[i] = psPixelsToMask(NULL, blanks, *blankRegion, PS_MASK_BLANK);
-        psFree(blankRegion);
-        psFree(blanks);
-    }
-
-    psArray *rejected = NULL;           // Array of rejected pixel lists
-    psStats *combineStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN); // Statistic to use in doing the combination
-    psImage *combined = pmCombineImages(NULL, &rejected, transformed, transformedErr, transformedMask, 0,
-                                        NULL, numIter, sigmaClip, combineStats); // Combined image
-    psArray *bad = pmRejectPixels(inputs, rejected, NULL, skyToDetector, rejThreshold, gradLimit); // Bad pix
-    psPixels *combinePixels = NULL;     // Pixels to combine
-    for (int i = 0; i < nImages; i++) {
-        psPixels *badSource = psPixelsTransform(NULL, bad->data[i], skyToDetector); // Bad pixels on the input
-        psImage *badMask = psPixelsToMask(NULL, badSource, PS_MASK_COSMICRAY); // Mask image for the input
-        (void)psBinaryOp(inputMask->data[i], inputMask->data[i], "|", badMask); // Put CRs into original mask
-        psFree(badSource);
-        psFree(badMask);
-
-        combinePixels = psPixelsConcatenate(redo, bad->data[i]);
-
-        // Update transformed image
-        psPixels *blanks = NULL;        // List of blank pixels
-        transformed->data[i] = psImageTransform(transformed->data[i], &blanks, inputs->data[i],
-                                                inputMask->data[i], inputMaskVal | PS_MASK_COSMICRAY, NAN,
-                                                skyToDetector, combineRegion, bad->data[i],
-                                                PS_INTERPOLATE_BILINEAR);
-        transformedErr->data[i] = psImageTransform(transformedErr->data[i], NULL, inputsErr->data[i],
-                                                   inputMask->data[i], inputMaskVal | PS_MASK_COSMICRAY,
-                                                   NAN, skyToDetector, combineRegion, bad->data[i],
-                                                   PS_INTERPOLATE_BILINEAR_VARIANCE);
-        psImage *skyImage = transformed->data[i]; // Dereference the transformed image
-        psRegion *blankRegion = psRegionAlloc(0, 0, skyImage->numCols, skyImage->numRows); // Size of
-                                                                                           // transformed
-                                                                                           // image
-        transformedMask->data[i] = psPixelsToMask(transformedMask->data[i], blanks, *blankRegion,
-                                                  PS_MASK_BLANK);
-        psFree(blankRegion);
-        psFree(blanks);
-    }
-    psFree(bad);
-
-    // Combine with no rejection
-    combined = pmCombineImages(combined, NULL, transformed, transformedErr, transformedMask,
-                               PS_MASK_BLANK, combinePixels, 0, 0.0, combineStats);
-    psFree(combineStats);
-    psFree(combinePixels);
-    psFree(transformed);
-    psFree(transformedErr);
-    psFree(transformedMask);
-\end{verbatim}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Image Subtraction}
-
-Image subtraction is arguably the best method of identifying faint
-variable sources in images with different point-spread functions.  It
-relies on fitting for a convolution kernel that minimizes the
-residuals in subtracting small regions of the image.  The use of a
-convolution kernel consisting of a linear combination of basis
-functions allows the problem to be solved with only modest computing
-power.
-
-\subsection{The kernels}
-
-We will allow for the use of two convolution kernels.  The first is
-that employed by the popular image subtraction program,
-\href{http://www2.iap.fr/users/alard/package.html}{ISIS}, consisting
-of Gaussians modified by polynomials:
-\begin{equation}
-B_{ijk}(u,v) = e^{-(u^2 + v^2)/2\sigma_i^2} u^j v^k
-\end{equation}
-The second simply consists of delta functions, which we refer to as
-POIS (Pan-STARRS Optimal Image Subtraction):
-\begin{equation}
-B_{ij}(u,v) = \delta(u - i)\ \delta(v - j)
-\end{equation}
-\tbd{For further details, see the document about image subtraction for
-\PS{}.}  The former is widely used, while the second appears to be
-equally useful and faster, though not as tried and proven.
-
-\begin{datatype}
-typedef enum {
-    PM_SUBTRACTION_KERNEL_POIS,         // POIS kernel --- delta functions
-    PM_SUBTRACTION_KERNEL_ISIS          // ISIS kernel --- gaussians modified by polynomials
-} pmSubtractionKernelsType;
-\end{datatype}
-
-In order to simplify the book-keeping for the kernels, we will define
-a \code{pmSubtractionKernels}, which keeps track of the details of the
-each of the kernel basis functions:
-
-\begin{datatype}
-typedef struct {
-    pmSubtractionKernelType type;       // Type of kernels --- allowing the use of multiple kernels
-    int size;                           // Size of kernel in x and y
-    int spatialOrder;                   // Maximum order of spatial variations
-    psVector *u, *v;                    // Offset (for POIS) or polynomial order (for ISIS)
-    psVector *sigma;                    // Width of Gaussian (for ISIS)
-    psVector *xOrder, *yOrder;          // Spatial polynomial order (for all)
-    int subIndex;                       // Index of kernel to be subtracted to maintain flux conservation
-    psArray *preCalc;                   // Array of images containing pre-calculated kernel (to
-                                        // accelerate ISIS; don't use for POIS)
-} pmSubtractionKernels;
-\end{datatype}
-
-This structure caters for both choices of kernel type.  For a POIS
-kernel, the \code{u} and \code{v} vectors shall be set to the
-coordinates for the delta functions for the corresponding kernel.  For
-an ISIS kernel, the \code{sigma} vector shall be set to the Gaussian
-widths and the \code{u} and \code{v} vectors shall be set to the
-orders of the modifying polynomials for the corresponding kernel.  For
-both choices of kernel, the \code{xOrder} and \code{yOrder} vectors
-specify the order of the spatial variation.
-
-In order to maintain flux conservation when the kernel is spatially
-variable, we need to treat one kernel in the set differently.  The
-convolutions for this kernel, identified by the \code{subIndex}, are
-calculated in the usual way, while all others have the \code{subIndex}
-kernel subtracted from them.  For details, see the
-\href{http://www.edpsciences.org/journal/index.cfm?v_url=aas/full/2000/11/ds8706/ds8706.html}{paper
-by Alard (2000, A\&AS, 144, 363)}.
-
-Since the ISIS kernels are continuous functions, it is worth
-pre-calculating them instead of calculating them each time they are
-required.  The \code{preCalc} array, consisting of \code{psImage}s is
-provided for this purpose.
-
-The \code{pmSubtractionKernels} are generated by the following functions:
-
-\begin{prototype}
-pmSubtractionKernels *pmSubtractionKernelsAllocPOIS(int size, int spatialOrder);
-pmSubtractionKernels *pmSubtractionKernelsAllocISIS(const psVector *sigmas, const psVector *orders,
-                                                    int size, int spatialOrder);
-\end{prototype}
-
-\code{pmSubtractionKernelsAllocPOIS} shall generate the
-\code{pmSubtractionKernels} suitable for the POIS kernel basis set.
-This involves setting the \code{u}, \code{v}, \code{xOrder} and
-\code{yOrder} to the appropriate values.  \code{size} is the half-size
-of the kernel, and \code{spatialOrder} is the maximum spatial order
-(the spatial variation is $x^i y^j$ with $i+j <$ \code{spatialOrder}).
-The \code{subIndex} is set to the kernel which has \code{u = 0},
-\code{v = 0}, \code{xOrder = 0} and \code{yOrder = 0}.  There should
-be \code{(2 * size + 1) * (2 * size + 1) * (spatialOrder + 1) *
-(spatialOrder + 2) / 2} kernels.
-
-\code{pmSubtractionKernelsAllocISIS} shall generate the
-\code{pmSubtractionKernels} suitable for the ISIS kernel basis set.
-This involves setting the \code{sigma}, \code{u}, \code{v},
-\code{xOrder} and \code{yOrder} to the appropriate values, as well as
-generating the \code{preCalc} images.  Note that the \code{sigma}
-vector contained within the \code{pmSubtractionKernels} is not the
-same as the input \code{sigmas} vector, but contains repeated entries.
-\code{size} is the half-size of the kernel, which specifies the size
-of the \code{preCalc} images.  The \code{spatialOrder} is the maximum
-spatial order (the spatial variation is $x^i y^j$ with $i+j <$
-\code{spatialOrder}).  The \code{subIndex} is set to the kernel which
-has \code{u = 0}, \code{v = 0}, \code{xOrder = 0} and \code{yOrder =
-0}, for the first of the Gaussian widths in the \code{sigmas} vector.
-
-\subsection{Stamps}
-
-Sub-regions on an image which are used to derive the best-fit
-convolution kernel are referred to as ``stamps''.
-
-\begin{datatype}
-typedef struct {
-    int x, y;                           // Position
-    psImage *matrix;                    // Associated matrix
-    psVector *vector;                   // Associated vector
-    pmStampStatus status;               // Status of stamp
-} pmStamp;
-\end{datatype}
-
-A stamp is the region around a central pixel, \code{x,y}.  The
-\code{matrix} and \code{vector} are generated in the process of
-solving for the best-fit convolution kernel; each of these will likely
-be of type \code{psF64} in order to maintain the best possible
-precision (we will be summing squares).  In order to allow us to throw
-out stamps without having to laboriously recompute the total
-least-squares matrix and vector, we use a separate matrix and vector
-for each stamp.
-
-To allow iteration on the choice of stamps, a stamp contains a
-\code{status}, an enumerated type:
-
-\begin{datatype}
-typedef enum {
-    PM_STAMP_USED,                      // Use this stamp
-    PM_STAMP_REJECTED,                  // This stamp has been rejected
-    PM_STAMP_RECALC,                    // Having been reset, this stamp needs to be recalculated
-    PM_STAMP_NONE                       // No stamp in this region
-} pmStampStatus;
-\end{datatype}
-
-\begin{prototype}
-psArray *pmSubtractionFindStamps(psArray *stamps, // Output stamps, or NULL
-                                 const psImage *image, // Image for which to find stamps
-                                 const psImage *mask, // Mask
-                                 unsigned int maskVal, // Value for mask
-                                 float threshold, // Threshold for stamps in the image
-                                 int xNum, int yNum, // Number of stamps in x and y
-                                 int border // Border around image to ignore (should be size of kernel)
-                                 );
-\end{prototype}
-
-\code{pmSubtractionFindStamps} returns an array of stamps on the
-\code{image} suitable for use in calculating the best-fit convolution
-kernel.  Except for a \code{border} all the way around, the
-\code{image} is broken into \code{xNum} $\times$ \code{yNum}
-rectangles; there will be a stamp within each rectangle.  If
-\code{stamps} is non-\code{NULL}, then the function shall only attempt
-to identify a new stamp in a particular rectangle if the corresponding
-stamp \code{status} is \code{PM_STAMP_REJECTED}.
-
-A stamp shall be recognized as the pixel with the greatest value that
-does not have the corresponding pixel in the \code{mask} matching
-\code{maskVal}.  If the value of the this pixel does not exceed
-\code{threshold}, then the stamp \code{status} shall be marked as
-\code{PM_STAMP_NONE}, which means that the stamp will be ignored in
-future iterations.  If a legitimate stamp is found within the region,
-then its status shall be changed to \code{PM_STAMP_RECALC}.
-
-
-\subsection{Solving for the kernel}
-
-Calculating the best-fit convolution kernel requires solving a matrix
-equation, the elements of which are obtained by applying the kernel
-basis functions to the stamps.  The final matrix and vector are the
-sum of the matrices and vectors obtained for each of the individual
-stamps.
-
-\begin{prototype}
-bool pmSubtractionCalculateEquation(psArray *stamps, // The stamps for which to calculate the equation
-                                    const psImage *reference, // Reference image
-                                    const psImage *input, // Input image
-                                    const psSubtractionKernels *kernels, // The kernel basis functions
-                                    int footprint // Half-size of region over which to calculate equation
-                                    );
-\end{prototype}
-
-\code{pmSubtractionCalculateEquation} shall calculate the
-\code{matrix} and \code{vector} for each of the \code{stamps} which
-have \code{status} set to \code{PM_STAMP_RECALC}.  The calculation is
-made over a region with a half size of \code{footprint} on the
-\code{reference} and \code{input} images, using each of the
-\code{kernels}.  In the event that any of the input pointers are
-\code{NULL}, the function shall generate an error and return
-\code{false}; otherwise, the function shall return \code{true}.
-
-The vector is:
-\begin{equation}
-v_i = \sum_{x,y} I(x,y) [ R(x,y) \otimes B_i(u,v) ] / \sigma(x,y)^2
-\end{equation}
-and the matrix is:
-\begin{equation}
-M_{ij} = \sum_{x,y} \left[ R(x,y) \otimes B_i(u,v) \right] \  \left[ R(x,y) \otimes B_j(u,v) \right] / \sigma(x,y)^2
-\end{equation}
-where $I(x,y)$ is the input image, $R(x,y)$ is the reference image,
-$B_i(u,v)$ is the $i$-th kernel basis function, $\otimes$ denotes
-convolution, $\sigma(x,y) = R(x,y)^{1/2}$ is an estimate of the error,
-and the sum over $x,y$ indicates summing over the stamp regions.
-
-In addition to the each of the \code{kernels}, an additional parameter
-for which we must solve is the difference in the background level
-between the \code{reference} and \code{input} images.  The appropriate
-term shall be added to the \code{matrix} and \code{vector}.
-
-In order to maintain flux conservation when the kernel is spatially
-variable, for each of the kernel basis functions apart from the first,
-the kernel actually employed shall be the first kernel function
-subtracted from the original kernel function.
-
-Having calculated the matrix equation for a stamp, its \code{status}
-is set to \code{PM_STAMP_USED}.
-
-Since this step is one of the major rate-limiting factors in image
-subtraction, care should be taken with optimization.
-
-\begin{prototype}
-psVector *pmSubtractionSolveEquation(psVector *solution,        // Solution vector, or NULL
-                                     const psArray *stamps // Array of stamps
-                                     );
-\end{prototype}
-
-\code{pmSubtractionSolveEquation} shall solve the matrix equation
-provided by each of the \code{stamps}, returning the \code{solution}
-vector.  This involves summing the \code{matrix} and \code{vector} of
-each of the stamps which have \code{status} set to
-\code{PM_STAMP_USED}, and multiplying the inverse of the matrix by the
-\code{vector}.  If the \code{solution} is \code{NULL}, then the
-function shall allocate and return a new vector; otherwise, the
-\code{solution} vector shall be modified in-place.  If \code{stamps}
-is \code{NULL}, then the function shall generate an error and return
-\code{NULL}.  The type of the \code{solution} vector should be
-\code{psF64}, since the matrix equation involves summing squares.
-
-
-\subsection{Rejection of stamps}
-
-\begin{prototype}
-bool pmSubtractionRejectStamps(psArray *stamps, // Array of stamps to check for rejection
-                               psImage *mask, // Mask image
-                               unsigned int badStampMaskVal, // Value to use in mask for bad stamp
-                               int footprint, // Region to mask if stamp is bad
-                               float sigmaRej, // Number of RMS deviations above zero at which to reject
-                               const psImage *refImage, // Reference image
-                               const psImage *inImage, // Input image
-                               const psVector *solution, // Solution vector
-                               const pmSubtractionKernels *kernels // Array of kernel parameters
-                               );
-\end{prototype}
-
-\code{pmSubtractionRejectStamps} shall apply the \code{solution} to
-the \code{stamps}, rejecting stamps for which the mean square
-residuals exceed \code{sigmaRej} RMS deviations from zero.
-\code{stamps} which are rejected have their \code{status} set to
-\code{PM_STAMP_REJECTED}, and have pixels within \code{footprint} of
-the corresponding position in the \code{mask} set to
-\code{badStampMaskVal} so they will not be used again.
-
-The deviations are calculated through extracting the stamps from the
-\code{refImage} and \code{inImage}, convolving the reference stamp by
-the best-fit kernel (derived from the \code{solutions} vector and the
-\code{kernels}), subtracting and then dividing by the stamp from the
-input image, and then squaring to obtain the mean square residual.
-
-\subsection{Visualization of kernel}
-
-Having solved for the best-fit kernel, it is often useful to visualize
-it.
-
-\begin{prototype}
-psImage *pmSubtractionKernelImage(psImage *out, const psVector *solution,
-                                  const pmSubtractionKernels *kernels, float x, float y);
-\end{prototype}
-
-\code{pmSubtractionKernelImage} shall create an image of the kernel
-from the \code{solution} vector and the \code{kernels}.  The relative
-position (between -1 and +1) on the image at which to evaluate the
-kernel (important if the kernel is spatially variable) is specified by
-\code{x} and \code{y}.  If \code{out} is \code{NULL}, then the
-function shall allocate a new image of sufficient size (matching the
-\code{precalc} images), and return the result; otherwise, \code{out}
-shall be modified in-place.
-
-
-\subsection{Example}
-
-Here is an example of what the image subtraction routine looks like,
-demonstrating how the various pieces fit together.  The inputs are:
-\begin{itemize}
-\item \code{psImage *reference}: Reference image
-\item \code{psImage *refMask}: Mask for reference image
-\item \code{psImage *input}: Input image
-\item \code{psImage *inMask}: Mask for input image
-\item \code{unsigned int maskVal}: Value to be masked
-\item \code{pmSubtractionKernelType kernelType}: Type of kernel to use
-\item \code{int kernelHalfSize}: Half the kernel size (full size is \code{2*kernelHalfSize + 1})
-\item \code{psVector *sigmas}: Widths for the ISIS Gaussians
-\item \code{psVector *polyOrders}: Polynomial orders for ISIS Gaussians
-\item \code{int spatialOrder}: Maximum spatial order for spatially variable kernel
-\item \code{float stampThreshold}: Threshold for finding stamps
-\item \code{int nStampsX, nStampsY}: Number of stamps in x and y
-\item \code{int stampSize}: Half size of stamp footprint
-\item \code{int numIter}: Number of iterations on the stamps
-\item \code{float sigmaRej}: Rejection threshold for stamps
-\end{itemize}
-
-The output is the subtracted image and the corresponding mask.
-
-\begin{verbatim}
-    // Mask around bad pixels in the reference image.  There are two cases to worry about:
-    // 1. Bad pixels within the kernel, which will affect the subtracted image
-    // 2. Bad pixels within the stamp, which affects the calculation of the kernel
-    psImage *subMask = psImageGrowMask(NULL, refMask, maskVal, kernelHalfSize, PS_MASK_NEAR_BAD);
-    (void)psImageGrowMask(subMask, refMask, maskVal, stampSize, PS_MASK_BAD_STAMP);
-    // Add in the mask for the input image.  Don't need to grow this, since it isn't convolved.
-    (void)psBinaryOp(subMask, subMask, "|", inMask);
-
-    // Generate kernel basis functions
-    psArray *kernels = NULL;            // Array of kernel basis functions
-    switch (kernelType) {
-      case PM_SUBTRACTION_KERNEL_POIS:
-        // Create the kernel basis functions
-        kernels = pmSubtractionKernelsGeneratePOIS(kernelHalfSize, spatialOrder);
-        break;
-      case PM_SUBTRACTION_KERNEL_ISIS:
-        kernels = pmSubtractionKernelsGenerateISIS(sigmas, polyOrders, kernelHalfSize, spatialOrder);
-        break;
-      default:
-        barf();
-    }
-
-    psArray *stamps = NULL;             // Array of stamps
-    psVector *kernelCoeffs = NULL;      // Coefficients for the kernels
-    bool rejected = true;               // Did we reject a stamp in the last iteration?
-
-    // Iterate for a solution
-    for (int iter = 0; iter < numIter && rejected; iter++) {
-
-        // Find stamps
-        stamps = pmSubtractionFindStamps(stamps, reference, subMask, maskVal | PS_MASK_BAD_STAMP,
-                                         stampThreshold, nStampsX, nStampsY, stampSize, kernelHalfSize);
-
-        // Generate and solve matrix equations
-        (void)pmSubtractionCalculateEquation(stamps, reference, input, kernels, stampSize);
-        kernelCoeffs = pmSubtractionSolveEquation(kernelCoeffs, stamps);
-
-        // Reject bad stamps
-        rejected = pmSubtractionRejectStamps(stamps, subMask, PS_MASK_BAD_STAMP, stampSize, sigmaRej,
-                                             reference, input, kernelCoeffs, kernels);
-    }
-
-    // Convolve the reference image
-    psImage *referenceConvolved = pmSubtractionConvolveImage(NULL, reference, subMask, kernelCoeffs, kernels);
-    // Subtract
-    psImage *subtracted = (psImage*)psBinaryOp(NULL, input, "-", referenceConvolved);
-
-    // What does the kernel look like?
-    psImage *kernelImage = pmSubtractionKernelImage(NULL, kernelCoeffs, kernels, 0.0, 0.0);
-    // Check/save kernel image, print statistics....
-
-    psFree(referenceConvolved);
-    psFree(stamps);
-    psFree(kernels);
-    psFree(kernelCoeffs);
-\end{verbatim}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\appendix
-
-\section{Basic Object Models}
-\label{ObjectModels}
-
-We specify a variety of basic object models which are required.
-Details of the model functional forms, parameters, and the derivatives
-are specified in the ADD.
-
-\subsubsection{Real 2D Gaussian}
-
-\begin{prototype}
-float pmMinLM_Gauss2D(psVector *deriv, psVector *params, psVector *x);
-\end{prototype}
-
-This function is a two-dimensional Gaussian with an elliptical
-cross-section and a constant local background.  
-
-The initial guess for the Gaussian parameters may be taken from the
-moments, peak value, and local sky.
-
-\subsubsection{Pseudo-Gaussian}
-
-\begin{prototype}
-float pmMinLM_PseudoGauss2D(psVector *deriv, psVector *params, psVector *x);
-\end{prototype}
-
-This function is a polynomial approximation of a 2D Gaussian otherwise
-very similar to the real Gaussian.  It is used in place of a real
-Gaussian for speed.
-
-The initial guess for the Gaussian parameters may be taken from the
-moments, peak value, and local sky.
-
-\subsubsection{Waussian}
-
-\begin{prototype}
-float pmMinLM_Wauss2D(psVector *deriv, psVector *params, psVector *x);
-\end{prototype}
-
-The Waussian is a modified polynomial approximation of a 2D Gaussian,
-with non-linear polynomial terms having variable coefficients, rather
-than the Taylor series values of 1/2 and 1/6.  
-
-\subsubsection{Twisted Gaussian}
-
-\begin{prototype}
-float pmMinLM_TwistGauss2D(psVector *deriv, psVector *params, psVector *x);
-\end{prototype}
-
-This function describes an object with power-law wings and a flattened
-core, where the core has a different contour from the wings.  
-
-The initial guess for the Gaussian parameters may be taken from the
-moments, peak value, and local sky.
-
-\tbd{future galaxy models to be implemented}
-
-\subsubsection{Sersic Galaxy Model}
-
-\begin{prototype}
-float pmMinLM_Sersic(psVector *deriv, psVector *params, psVector *x);
-\end{prototype}
-
-\subsubsection{Sersic with Core Galaxy Model}
-
-\begin{prototype}
-float pmMinLM_SersicCore(psVector *deriv, psVector *params, psVector *x);
-\end{prototype}
-
-\subsubsection{Pseudo Sersic Galaxy Model}
-
-\begin{prototype}
-float pmMinLM_PseudoSersic(psVector *deriv, psVector *params, psVector *x);
-\end{prototype}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Example Camera Configuration Files}
-
-\tbd{Some of these don't exactly match the specifications of this
-document yet, because they have been changed from the prototype, but
-it is hoped that they will be useful.  Questions are welcome.}
-
-\subsection{MegaCam Raw}
-
-\begin{verbatim}
-# The raw MegaCam data comes off the telescope with each of the chips stored in extensions of a MEF file.
-
-# How to identify this type
-RULE    METADATA
-        TELESCOP        STR     CFHT 3.6m
-        DETECTOR        STR     MegaCam
-        EXTEND          BOOL    T
-        NEXTEND         S32     72
+        SIMPLE          BOOL    TRUE
+        NAXIS           S32     2
+        TELESCOP        STR     ISP-1 
+        INSTRUME        STR     ISP-Apogee
+        DETECTOR        STR     ISP-Apogee-01
+        ISPCAMER        STR     Apogee U42
 END
 
 # How to read this data
-PHU             STR     FPA     # The FITS file represents an entire FPA
-EXTENSIONS      STR     CELL    # The extensions represent cells
+FILE    METADATA
+        PHU             STR     FPA     # The FITS file represents an entire FPA
+        EXTENSIONS      STR     NONE    # There are no extensions
+        FPA.NAME        STR     SEQID   # A PHU keyword for unique identifier within the hierarchy level
+END
 
 # What's in the FITS file?
-CONTENTS        METADATA
-        # Extension name, chip name:type
-        amp00   STR     ccd00:left
-        amp01   STR     ccd00:right
-        amp02   STR     ccd01:left
-        amp03   STR     ccd01:right
-        amp04   STR     ccd02:left
-        amp05   STR     ccd02:right
-        amp06   STR     ccd03:left
-        amp07   STR     ccd03:right
-        amp08   STR     ccd04:left
-        amp09   STR     ccd04:right
-        amp10   STR     ccd05:left
-        amp11   STR     ccd05:right
-        amp12   STR     ccd06:left
-        amp13   STR     ccd06:right
-        amp14   STR     ccd07:left
-        amp15   STR     ccd07:right
-        amp16   STR     ccd08:left
-        amp17   STR     ccd08:right
-        amp18   STR     ccd09:left
-        amp19   STR     ccd09:right
-        amp20   STR     ccd10:left
-        amp21   STR     ccd10:right
-        amp22   STR     ccd11:left
-        amp23   STR     ccd11:right
-        amp24   STR     ccd12:left
-        amp25   STR     ccd12:right
-        amp26   STR     ccd13:left
-        amp27   STR     ccd13:right
-        amp28   STR     ccd14:left
-        amp29   STR     ccd14:right
-        amp30   STR     ccd15:left
-        amp31   STR     ccd15:right
-        amp32   STR     ccd16:left
-        amp33   STR     ccd16:right
-        amp34   STR     ccd17:left
-        amp35   STR     ccd17:right
-        amp36   STR     ccd18:left
-        amp37   STR     ccd18:right
-        amp38   STR     ccd19:left
-        amp39   STR     ccd19:right
-        amp40   STR     ccd20:left
-        amp41   STR     ccd20:right
-        amp42   STR     ccd21:left
-        amp43   STR     ccd21:right
-        amp44   STR     ccd22:left
-        amp45   STR     ccd22:right
-        amp46   STR     ccd23:left
-        amp47   STR     ccd23:right
-        amp48   STR     ccd24:left
-        amp49   STR     ccd24:right
-        amp50   STR     ccd25:left
-        amp51   STR     ccd25:right
-        amp52   STR     ccd26:left
-        amp53   STR     ccd26:right
-        amp54   STR     ccd27:left
-        amp55   STR     ccd27:right
-        amp56   STR     ccd28:left
-        amp57   STR     ccd28:right
-        amp58   STR     ccd29:left
-        amp59   STR     ccd29:right
-        amp60   STR     ccd30:left
-        amp61   STR     ccd30:right
-        amp62   STR     ccd31:left
-        amp63   STR     ccd31:right
-        amp64   STR     ccd32:left
-        amp65   STR     ccd32:right
-        amp66   STR     ccd33:left
-        amp67   STR     ccd33:right
-        amp68   STR     ccd34:left
-        amp69   STR     ccd34:right
-        amp70   STR     ccd35:left
-        amp71   STR     ccd35:right
-END
+CONTENTS        STR     Chip:Cell:amplifier
 
 # Specify the cell data
 CELLS   METADATA
-        left    METADATA        # Left amplifier
-                CELL.BIASSEC    STR     HEADER:BIASSEC
-                CELL.TRIMSEC    STR     HEADER:DATASEC
-                CELL.XPARITY    S32     1       # We could have specified this as a DEFAULT, but this works
-        END
-        right   METADATA        # Right amplifier
-                CELL.BIASSEC    STR     HEADER:BIASSEC
-                CELL.TRIMSEC    STR     HEADER:DATASEC
-                CELL.XPARITY    S32     -1      # This cell is read out in the opposite direction
+        amplifier       METADATA
+                CELL.TRIMSEC.SOURCE     STR     HEADER
+                CELL.BIASSEC.SOURCE     STR     HEADER
+                CELL.TRIMSEC            STR     TRIMSEC
+                CELL.BIASSEC            STR     BIASSEC
         END
 END
@@ -4222,502 +1061,300 @@
 # How to translate PS concepts into FITS headers
 TRANSLATION     METADATA
-        FPA.NAME        STR     EXPNUM
-        FPA.AIRMASS     STR     AIRMASS
-        FPA.FILTER      STR     FILTER
-        FPA.POSANGLE    STR     ROTANGLE
+        FPA.OBSTYPE     STR     OBSTYPE
+        FPA.OBJECT      STR     OBSTYPE
+        FPA.FILTER      STR     FILTNAME
         FPA.RA          STR     RA
         FPA.DEC         STR     DEC
         FPA.RADECSYS    STR     RADECSYS
-        FPA.MJD         STR     MJD-OBS
+        FPA.ALT         STR     ALT
+        FPA.AZ          STR     AZ
+        FPA.POSANGLE    STR     ROTANGLE
+        FPA.AIRMASS     STR     AIRMASS
+        FPA.TIME        STR     MJD-OBS
+        CHIP.TEMP       STR     CCDTEMP
         CELL.EXPOSURE   STR     EXPTIME
         CELL.DARKTIME   STR     DARKTIME
-        CELL.XBIN       STR     CCDBIN1
-        CELL.YBIN       STR     CCDBIN2
+        CELL.TIME       STR     MJD-OBS
         CELL.GAIN       STR     GAIN
         CELL.READNOISE  STR     RDNOISE
-        CELL.SATURATION STR     SATURATE
+        CELL.XBIN       STR     XBIN
+        CELL.YBIN       STR     YBIN
+#       CELL.SATURATION STR     SATURATE        ### Currently set to 0 ???
+        CELL.BAD        STR     BADLEVEL
 END
 
 # Default PS concepts that may be specified by value
 DEFAULTS        METADATA
-        CELL.BAD                S32     0
-        CELL.YPARITY_DEPEND     STR     CHIP.NAME
-        CELL.YPARITY    METADATA
-                ccd00   S32     -1
-                ccd01   S32     -1
-                ccd02   S32     -1
-                ccd03   S32     -1
-                ccd04   S32     -1
-                ccd05   S32     -1
-                ccd06   S32     -1
-                ccd07   S32     -1
-                ccd08   S32     -1
-                ccd09   S32     -1
-                ccd10   S32     -1
-                ccd11   S32     -1
-                ccd12   S32     -1
-                ccd13   S32     -1
-                ccd14   S32     -1
-                ccd15   S32     -1
-                ccd16   S32     -1
-                ccd17   S32     -1
-                ccd18   S32     1
-                ccd19   S32     1
-                ccd20   S32     1
-                ccd21   S32     1
-                ccd22   S32     1
-                ccd23   S32     1
-                ccd24   S32     1
-                ccd25   S32     1
-                ccd26   S32     1
-                ccd27   S32     1
-                ccd28   S32     1
-                ccd29   S32     1
-                ccd30   S32     1
-                ccd31   S32     1
-                ccd32   S32     1
-                ccd33   S32     1
-                ccd34   S32     1
-                ccd35   S32     1
-        END
-END
-
-# How to translate PS concepts into database lookups
-DATABASE        METADATA
-        TYPE            dbEntry         TABLE           COLUMN          GIVENDBCOL      GIVENPS
-#       CELL.GAIN       dbEntry         Camera          gain            chipId,cellId   CHIP.NAME,CELL.NAME
-#       CELL.READNOISE  dbEntry         Camera          readNoise       chipId,cellId   CHIP.NAME,CELL.NAME
-
-# A database entry refers to a particular column (COLUMN) in a
-# particular table (TABLE), given certain PS concepts (GIVENPS) that
-# match certain database columns (GIVENDBCOL).
-
-END
-\end{verbatim}
-
-\subsection{MegaCam Splice}
-
-\begin{verbatim}
-# The spliced MecaCam data is stored in single extensions for each chip
-
-# How to recognise this type
-RULE    METADATA
-        TELESCOP        STR     CFHT 3.6m
-        DETECTOR        STR     MegaCam
-        EXTEND          BOOL    T
-        NEXTEND         S32     36
-END
-
-# How to read this data
-PHU             STR     FPA     # The FITS file represents an entire FPA
-EXTENSIONS      STR     CHIP    # The extensions represent chips
-
-# What's in the FITS file?
-CONTENTS        METADATA
-        # Extension name, components
-        ccd00           STR     left right
-        ccd01           STR     left right
-        ccd02           STR     left right
-        ccd03           STR     left right
-        ccd04           STR     left right
-        ccd05           STR     left right
-        ccd06           STR     left right
-        ccd07           STR     left right
-        ccd08           STR     left right
-        ccd09           STR     left right
-        ccd10           STR     left right
-        ccd11           STR     left right
-        ccd12           STR     left right
-        ccd13           STR     left right
-        ccd14           STR     left right
-        ccd15           STR     left right
-        ccd16           STR     left right
-        ccd17           STR     left right
-        ccd18           STR     left right
-        ccd19           STR     left right
-        ccd20           STR     left right
-        ccd21           STR     left right
-        ccd22           STR     left right
-        ccd23           STR     left right
-        ccd24           STR     left right
-        ccd25           STR     left right
-        ccd26           STR     left right
-        ccd27           STR     left right
-        ccd28           STR     left right
-        ccd29           STR     left right
-        ccd30           STR     left right
-        ccd31           STR     left right
-        ccd32           STR     left right
-        ccd33           STR     left right
-        ccd34           STR     left right
-        ccd35           STR     left right
-END
-
-# Specify the cells
-CELLS           METADATA
-        left            METADATA
-                CELL.BIASSEC    STR     HEADER:BSECA
-                CELL.TRIMSEC    STR     HEADER:TSECA
-        END
-
-        right           METADATA
-                CELL.BIASSEC    STR     HEADER:BSECB
-                CELL.TRIMSEC    STR     HEADER:TSECB
-        END
-END
-
-# How to translate PS concepts into FITS headers
-TRANSLATION     METADATA
-        FPA.NAME        STR     EXPNUM
-        FPA.AIRMASS     STR     AIRMASS
-        FPA.FILTER      STR     FILTER
-        FPA.POSANGLE    STR     ROTANGLE
-        FPA.RA          STR     RA
-        FPA.DEC         STR     DEC
-        FPA.RADECSYS    STR     RADECSYS
-        FPA.MJD         STR     MJD-OBS
-        CELL.EXPOSURE   STR     EXPTIME
-        CELL.DARKTIME   STR     DARKTIME
-        CELL.XBIN       STR     CCDBIN1
-        CELL.YBIN       STR     CCDBIN2
-        CELL.GAIN       STR     GAIN
-        CELL.READNOISE  STR     RDNOISE
-        CELL.SATURATION STR     SATURATE
-END
-
-# Default PS concepts that may be specified by value
-DEFAULTS        METADATA
-        CELL.BAD                S32     0
-        CELL.XPARITY            S32     1
-        CELL.YPARITY            S32     1
-END
-
-
-# How to translate PS concepts into database lookups
-DATABASE        METADATA
-        TYPE            dbEntry         TABLE           COLUMN          GIVENDBCOL      GIVENPS
-#       CELL.GAIN       dbEntry         Camera          gain            chipId,cellId   CHIP.NAME,CELL.NAME
-#       CELL.READNOISE  dbEntry         Camera          readNoise       chipId,cellId   CHIP.NAME,CELL.NAME
-
-# A database entry refers to a particular column (COLUMN) in a
-# particular table (TABLE), given certain PS concepts (GIVENPS) that
-# match certain database columns (GIVENDBCOL).
-
-END             
-\end{verbatim}
-
-\subsection{LRIS Blue}
-
-\begin{verbatim}
-# The Low Resolution Imager and Spectrograph (LRIS) blue side
-
-# We have no choice but to hard-code the various regions, because Keck
-# only stores them as:
-# WINDOW  = '1,0,0,2048,4096'
-# PREPIX  =                   51
-# POSTPIX =                   80
-# BINNING = '1,1     '
-# AMPPSIZE= '[1:1024,1:4096]'
-
-# I don't know how we would get the IPP to react to changes in the
-# windowing on the fly --- we have no mechanism for setting the region
-# sizes on the basis of the above keywords.  Therefore, we hard-code
-# the regions and assert on our assumptions in the RULE.
-
-
-# How to identify this type
-RULE    METADATA
-        TELESCOP        STR     Keck I
-        INSTRUME        STR     LRISBLUE
-        AMPLIST         STR     1,4,0,0
-        WINDOW          STR     1,0,0,2048,4096
-        PREPIX          S32     51
-        POSTPIX         S32     80
-        BINNING         STR     1,1
-        AMPPSIZE        STR     [1:1024,1:4096]
-        NAXIS1          S32     4620
-        NAXIS2          S32     4096
-END
-
-# How to read this data
-PHU             STR     FPA     # The FITS file represents an entire FPA
-EXTENSIONS      STR     NONE    # There are no extensions
-
-# What's in the FITS file?
-CONTENTS        METADATA
-        LeftChip        STR     amp1 amp2
-        RightChip       STR     amp3 amp4
-END
-
-# Specify the cell data
-CELLS   METADATA
-        amp1            METADATA
-                CELL.BIASSEC    STR     VALUE:[1:51,1:4096];[4301:4380,1:4096]
-                CELL.TRIMSEC    STR     VALUE:[205:1228,1:4096]
-                CELL.GAIN       STR     VALUE:1.2
-                CELL.READNOISE  STR     VALUE:5.6
-        END
-
-        amp2    METADATA
-                CELL.BIASSEC    STR     VALUE:[52:102,1:4096];[4381:4460,1:4096]
-                CELL.TRIMSEC    STR     VALUE:[1229:2252,1:4096]
-                CELL.GAIN       STR     VALUE:1.3
-                CELL.READNOISE  STR     VALUE:6.7
-        END
-
-        amp3            METADATA
-                CELL.BIASSEC    STR     VALUE:[103:153,1:4096];[4461:4540,1:4096]
-                CELL.TRIMSEC    STR     VALUE:[2253:3276,1:4096]
-                CELL.GAIN       STR     VALUE:1.4
-                CELL.READNOISE  STR     VALUE:7.8
-        END
-
-        amp4    METADATA
-                CELL.BIASSEC    STR     VALUE:[154:204,1:4096];[4541:4620,1:4096]
-                CELL.TRIMSEC    STR     VALUE:[3277:4300,1:4096]
-                CELL.GAIN       STR     VALUE:1.5
-                CELL.READNOISE  STR     VALUE:8.9
-        END
-END
-
-# How to translate PS concepts into FITS headers
-TRANSLATION     METADATA
-        FPA.AIRMASS     STR     AIRMASS
-        FPA.FILTER      STR     BLUFILT
-        FPA.POSANGLE    STR     ROTPOSN
-        FPA.RA          STR     RA
-        FPA.DEC         STR     DEC
-        CELL.EXPOSURE   STR     EXPOSURE
-        CELL.DARKTIME   STR     EXPOSURE        // No special darktime header; use exposure time
-        CELL.DATE       STR     DATE            // NOTE: There are TWO keywords called "DATE" (creation, exp)!
-        CELL.TIME       STR     UT
-END
-
-# Default PS concepts that may be specified by value
-DEFAULTS        METADATA
-        FPA.RADECSYS    STR     ICRS
-END
-\end{verbatim}
-
-\subsection{LRIS Red}
-
-\begin{verbatim}
-# The Low Resolution Imager and Spectrograph (LRIS) red side
-
-# We have no choice but to hard-code the various regions, because Keck
-# only stores them as:
-# WINDOW  = '0,0,0,2048,2048'
-# PREPIX  =                   20
-# POSTPIX =                   80
-# BINNING = '1,1     '
-# AMPPSIZE= '[1:1024,1:4096]'
-
-# I don't know how we would get the IPP to react to changes in the
-# windowing on the fly --- we have no mechanism for setting the region
-# sizes on the basis of the above keywords.  Therefore, we hard-code
-# the regions and assert on our assumptions in the RULE.
-
-
-# How to identify this type
-RULE    METADATA
-        TELESCOP        STR     Keck I
-        INSTRUME        STR     LRIS
-        AMPLIST         STR     2,1,0,0
-        WINDOW          STR     0,0,0,2048,2048
-        PREPIX          S32     20
-        POSTPIX         S32     80
-        BINNING         STR     1, 1
-        CCDPSIZE        STR     [1:2048,1:2048]
-        NAXIS1          S32     2248
-        NAXIS2          S32     2048
-        IMTYPE          STR     TWOAMPTOP
-END
-
-# How to read this data
-PHU             STR     CHIP    # The FITS file represents a single chip
-EXTENSIONS      STR     NONE    # There are no extensions
-
-# What's in the FITS file?
-CONTENTS        STR     LeftSide RightSide
-
-# Specify the cell data
-CELLS   METADATA
-        LeftSide        METADATA
-                CELL.BIASSEC    STR     VALUE:[1:20,1:2048];[2089:2168,1:2048]
-                CELL.TRIMSEC    STR     VALUE:[41:1064,1:2048]
-                CELL.GAIN       STR     VALUE:1.2
-                CELL.READNOISE  STR     VALUE:5.6
-        END
-
-        RightSide       METADATA
-                CELL.BIASSEC    STR     VALUE:[21:40,1:2048];[2169:2248,1:2048]
-                CELL.TRIMSEC    STR     VALUE:[1065:2088,1:2048]
-                CELL.GAIN       STR     VALUE:1.3
-                CELL.READNOISE  STR     VALUE:6.5
-        END
-END
-
-# How to translate PS concepts into FITS headers
-TRANSLATION     METADATA
-        FPA.AIRMASS     STR     AIRMASS
-        FPA.FILTER      STR     FILTER
-        FPA.POSANGLE    STR     POSANG
-        FPA.RA          STR     OBJ-RA
-        FPA.DEC         STR     OBJ-DEC
-        CELL.EXPOSURE   STR     EXPTIME
-        CELL.DARKTIME   STR     DARKTIME
-        CELL.DATE       STR     DATE-OBS
-        CELL.TIME       STR     TIME-OBS
-END
-
-# Default PS concepts that may be specified by value
-DEFAULTS        METADATA
-        FPA.RADECSYS    STR     ICRS
-END
-\end{verbatim}
-
-\subsection{GPC OTA}
-
-\begin{verbatim}
-# The raw GPC data comes off the telescope with each of the chips stored in separate files
-
-# How to identify this type
-RULE    METADATA
-#       TELESCOP        STR     PS1
-#       DETECTOR        STR     GPC1
-        EXTEND          BOOL    T
-        NEXTEND         S32     64
-        NAMPS           S32     64
-END
-
-# How to read this data
-PHU             STR     CHIP    # The FITS file represents a single chip
-EXTENSIONS      STR     CELL    # The extensions represent cells
-
-# What's in the FITS file?
-CONTENTS        METADATA
-        # Extension name, type
-        xy00    STR     pitch10u
-        xy01    STR     pitch10u
-        xy02    STR     pitch10u
-        xy03    STR     pitch10u
-        xy04    STR     pitch10u
-        xy05    STR     pitch10u
-        xy06    STR     pitch10u
-        xy07    STR     pitch10u
-        xy10    STR     pitch10u
-        xy11    STR     pitch10u
-        xy12    STR     pitch10u
-        xy13    STR     pitch10u
-        xy14    STR     pitch10u
-        xy15    STR     pitch10u
-        xy16    STR     pitch10u
-        xy17    STR     pitch10u
-        xy20    STR     pitch10u
-        xy21    STR     pitch10u
-        xy22    STR     pitch10u
-        xy23    STR     pitch10u
-        xy24    STR     pitch10u
-        xy25    STR     pitch10u
-        xy26    STR     pitch10u
-        xy27    STR     pitch10u
-        xy30    STR     pitch10u
-        xy31    STR     pitch10u
-        xy32    STR     pitch10u
-        xy33    STR     pitch10u
-        xy34    STR     pitch10u
-        xy35    STR     pitch10u
-        xy36    STR     pitch10u
-        xy37    STR     pitch10u
-        xy40    STR     pitch10u
-        xy41    STR     pitch10u
-        xy42    STR     pitch10u
-        xy43    STR     pitch10u
-        xy44    STR     pitch10u
-        xy45    STR     pitch10u
-        xy46    STR     pitch10u
-        xy47    STR     pitch10u
-        xy50    STR     pitch10u
-        xy51    STR     pitch10u
-        xy52    STR     pitch10u
-        xy53    STR     pitch10u
-        xy54    STR     pitch10u
-        xy55    STR     pitch10u
-        xy56    STR     pitch10u
-        xy57    STR     pitch10u
-        xy60    STR     pitch10u
-        xy61    STR     pitch10u
-        xy62    STR     pitch10u
-        xy63    STR     pitch10u
-        xy64    STR     pitch10u
-        xy65    STR     pitch10u
-        xy66    STR     pitch10u
-        xy67    STR     pitch10u
-        xy70    STR     pitch10u
-        xy71    STR     pitch10u
-        xy72    STR     pitch10u
-        xy73    STR     pitch10u
-        xy74    STR     pitch10u
-        xy75    STR     pitch10u
-        xy76    STR     pitch10u
-        xy77    STR     pitch10u
-END
-
-# Specify the cell data
-CELLS   METADATA
-        pitch10u        METADATA
-                CELL.BIASSEC    STR     VALUE:[575:606,1:594]
-                CELL.TRIMSEC    STR     VALUE:[1:574,1:594]
-        #       CELL.BIASSEC    STR     HEADER:BIASSEC
-        #       CELL.TRIMSEC    STR     HEADER:DATASEC
-        END
-
-        # This is just in here for fun
-        pitch12u        METADATA
-                CELL.BIASSEC    STR     VALUE:[1:10,1:512];[523:574,1:512]
-                CELL.TRIMSEC    STR     VALUE:[11:522,1:512]
-        #       CELL.BIASSEC    STR     HEADER:BIASSEC
-        #       CELL.TRIMSEC    STR     HEADER:TRIMSEC
-        END
-END
-
-
-# How to translate PS concepts into FITS headers
-TRANSLATION     METADATA
-        CELL.BIN        STR     CCDSUM
-        CELL.SATURATION STR     SATURATE
-END
-
-# Default PS concepts that may be specified by value
-DEFAULTS        METADATA
-        FPA.AIRMASS     F32     0.0
-        FPA.FILTER      STR     NONE
-        FPA.POSANGLE    F32     0.0
-        FPA.RA          STR     0:0:0
-        FPA.DEC         STR     0:0:0
-        FPA.RADECSYS    STR     ICRS
-        FPA.NAME        S32     0
-        FPA.MJD         F32     12345.6789
-        CELL.EXPOSURE   F32     0.0
-        CELL.DARKTIME   F32     0.0
-        CELL.GAIN       F32     1.0
-        CELL.READNOISE  F32     0.0
-        CELL.BAD        S32     0
-        CELL.BIN        S32     1
+        FPA.TIMESYS     STR     UTC
+        CELL.SATURATION F32     65535
+        CELL.READDIR    S32     1
+        CELL.TIMESYS    STR     UTC
+        CHIP.XPARITY    S32     1
+        CHIP.YPARITY    S32     1
+        CHIP.X0         S32     0
+        CHIP.Y0         S32     0
         CELL.XPARITY    S32     1
         CELL.YPARITY    S32     1
-END
-
-# How to translate PS concepts into database lookups
+        CELL.X0         S32     0
+        CELL.Y0         S32     0
+END
+
+FORMATS         METADATA
+        FPA.RA          STR     HOURS
+        FPA.DEC         STR     DEGREES
+        FPA.TIME        STR     MJD
+        CELL.TIME       STR     MJD
+END
+
+# PS Concepts to get from the database
 DATABASE        METADATA
-        TYPE            dbEntry         TABLE           COLUMN          GIVENDBCOL      GIVENPS
-        CELL.GAIN       dbEntry         Camera          gain            chipId,cellId   CHIP,CELL
-        CELL.READNOISE  dbEntry         Camera          readNoise       chipId,cellId   CHIP,CELL
-
-# A database entry refers to a particular column (COLUMN) in a
-# particular table (TABLE), given certain PS concepts (GIVENPS) that
-# match certain database columns (GIVENDBCOL).
-
+# None.
 END
 \end{verbatim}
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Recipes}
+
+\subsection{Locations}
+
+Recipes may be specified in a number of locations.  Firstly, they may
+be specified on the command line with the \code{-recipe} option,
+giving a symbolic name and a filename or another symbolic name to link
+to.  In addition, they may be specified in the site configuration and
+the camera configuration under the \code{RECIPES} metadata.  Note that
+the \code{PATH(STR)} in the site configuration defines the search
+paths for these files.
+
+\subsection{Contents}
+
+The contents of the recipe files depends on the particular recipe.
+
+\subsubsection{PPIMAGE}
+
+The \code{PPIMAGE} recipe contains options for \code{ppImage}:
+\begin{itemize}
+\item \code{MASK(BOOL)} indicates if bad pixels are to be masked.
+\item \code{MASK.VALUE(U8)} specifies a bitmask (matching the bad
+  pixel mask) for pixels to mask in the input image.
+\item \code{NONLIN(BOOL)} indicates if the non-linearity correction is
+  to be performed.
+\item \code{OVERSCAN(BOOL)} indicates if the overscan correction is to be performed.
+\item \code{BIAS(BOOL)} indicates if the bias correction is to be performed.
+\item \code{DARK(BOOL)} indicates if the dark correction is to be performed.
+\item \code{SHUTTER(BOOL)} indicates if the shutter correction is to be performed.
+\item \code{FLAT(BOOL)} indicates if the flat-field correction is to be performed.
+\item \code{FRINGE(BOOL)} indicates if the fringe correction is to be performed.
+\item \code{PHOTOM(BOOL)} indicates if the photometry is to be performed.
+\item \code{ASTROM.CHIP(BOOL)} indicates if the astrometry is to be performed on a chip level.
+\item \code{ASTROM.MOSAIC(BOOL)} indicates if the astrometry is to be performed on a mosaic (FPA) level.
+\item \code{BASE.FITS(BOOL)} indicates if the base detrended image is to be saved.
+\item \code{CHIP.FITS(BOOL)} indicates if the chip mosaicked image is to be saved.
+\item \code{FPA1.FITS(BOOL)} indicates if the FPA mosaicked image with first level binning is to be saved.
+\item \code{FPA2.FITS(BOOL)} indicates if the FPA mosaicked image with second level binning is to be saved.
+\item \code{BIN1.FITS(BOOL)} indicates if the chip mosaicked image with first level binning is to be saved.
+\item \code{BIN2.FITS(BOOL)} indicates if the chip mosaicked image with second level binning is to be saved.
+\item \code{BIN1.JPEG(BOOL)} indicates if the JPEG image with first level binning is to be saved.
+\item \code{BIN2.JPEG(BOOL)} indicates if the JPEG image with second level binning is to be saved.
+\item \code{NONLIN.DATA} may be:
+  \begin{itemize}
+  \item A vector of type \code{F32}, in which case it provides the
+    (ordinary) polynomial coefficients for the non-linear correction.
+  \item Of type \code{STR}, in which case it provides a filename with
+    the lookup table (consisting of two columns of values, the first
+    the input flux and the second the corresponding corrected flux).
+  \item Of type \code{METADATA}, in which case it is a menu, with menu
+    items with types and values according to one of the other two
+    options.  The menu key is provided by \code{NONLIN.SOURCE(STR}),
+    which gives a concept name to look up (\code{CHIP.NAME} would be a
+    good choice).
+  \end{itemize}
+\item \code{OVERSCAN.SINGLE(BOOL)} indicates if the entire overscan is
+  to be reduced to a single value.
+\item \code{OVERSCAN.FIT(STR)} indicates the type of fit that is to be
+  performed to the overscan (if \code{OVERSCAN.SINGLE} is
+  \code{FALSE}): \code{NONE}, \code{POLYNOMIAL} or \code{SPLINE}.
+\item \code{OVERSCAN.ORDER(S32)} gives the order of the polynomial fit
+  (or number of spline pieces).
+\item \code{OVERSCAN.STAT(STR)} gives the statistic to apply to the
+  overscan: \code{MEAN} or \code{MEDIAN}. \tbd{Would like to change
+  this to allow the full range of statistics.}
+\item \code{BIN1.XBIN(S32)} gives the level 1 binning in x
+\item \code{BIN2.YBIN(S32)} gives the level 1 binning in y
+\item \code{BIN2.XBIN(S32)} gives the level 2 binning in x
+\item \code{BIN2.YBIN(S32)} gives the level 2 binning in y:
+\item \code{PHOTCODE.RULE(STR)} gives a rule for producing a
+  photometry code, with values in curly brackets interpolated.
+\end{itemize}
+
+\subsubsubsection{Example}
+
+\begin{verbatim}
+### ppImage recipe configuration file
+
+# List of tasks to perform
+MASK            BOOL    FALSE           # Mask bad pixels
+MASK.VALUE      U8      0xff            # Only mask pixels matching this bitmask
+NONLIN          BOOL    FALSE           # Non-linearity correction
+OVERSCAN        BOOL    TRUE            # Overscan subtraction
+BIAS            BOOL    TRUE            # Bias subtraction
+DARK            BOOL    TRUE            # Dark subtraction
+FLAT            BOOL    TRUE            # Flat-field normalisation
+FRINGE          BOOL    FALSE           # Fringe subtraction
+PHOTOM          BOOL    FALSE           # Source identification and photometry
+ASTROM.CHIP     BOOL    FALSE           # Astrometry on chip
+ASTROM.MOSAIC   BOOL    FALSE           # Astrometry on mosaic
+
+BASE.FITS       BOOL    TRUE            # Save base detrended image?
+CHIP.FITS       BOOL    TRUE            # Save chip-mosaic-ed image? 
+FPA1.FITS       BOOL    TRUE            # Save 1st binned fpa image? 
+FPA2.FITS       BOOL    TRUE            # Save 2nd binned fpa image? 
+BIN1.FITS       BOOL    TRUE            # Save 1st binned chip image?
+BIN2.FITS       BOOL    TRUE            # Save 2nd binned chip image?
+BIN1.JPEG       BOOL    TRUE            # Save 1st binned jpeg?
+BIN2.JPEG       BOOL    FALSE           # Save 2nd binned jpeg?
+
+# Non-linearity correction
+NONLIN.SOURCE           STR     CHIP.NAME       # How to determine the source
+#@NONLIN.DATA           F32     0.0 1.001 0.001 # A polynomial
+#NONLIN.DATA            STR     nonlin.dat      # Filename for lookup table
+NONLIN.DATA             METADATA                # Source of non-linearity data
+        ccd00           STR     nonlin00.dat    # A lookup table 
+        @ccd01          F32     0.0 1.001 0.001 # A polynomial
+        @ccd02          F32     1.2345          # A polynomial
+END
+
+# Overscan subtraction
+OVERSCAN.SINGLE         BOOL    FALSE           # Reduce overscan to a single value?
+#OVERSCAN.FIT           STR     SPLINE          # NONE | POLYNOMIAL | SPLINE
+OVERSCAN.FIT            STR     POLYNOMIAL      # NONE | POLYNOMIAL | SPLINE
+OVERSCAN.ORDER          S32     5               # Order of polynomial fit
+OVERSCAN.STAT           STR     MEAN            # MEAN | MEDIAN
+
+# binned output image options
+BIN1.XBIN               S32     8
+BIN1.YBIN               S32     8
+BIN2.XBIN               S32     64
+BIN2.YBIN               S32     64
+
+PHOTCODE.RULE           STR     {CAMERA}.{FILTER.ID}.{CHIP.N}
+\end{verbatim}
+
+\subsubsection{PPMERGE}
+
+The \code{PPMERGE} recipe contains options for \code{ppMerge}:
+\begin{itemize}
+\item \code{ROWS(S32)} gives the number of rows to be read at once (a
+  number larger than the physical size will read all rows).
+\item \code{ELECTRONS(F32)} gives the minimum number of electrons for
+  useful signal. \tbd{Don't think this is implemented yet.}
+\item \code{SAMPLE(S32)} specifies a sampling frequency for
+  determining the background level.
+\item \code{REJ(F32)} specifies a rejection threshold, in standard
+  deviations.
+\item \code{ITER(S32)} specifies the number of rejection iterations.
+\item \code{FRACHIGH(F32)} gives the fraction of high pixels to reject immediately.
+\item \code{FRACLOW(F32)} gives the fraction of low pixels to reject immediately.
+\item \code{NKEEP(S32)} gives the minimum number of pixels in the stack to keep.
+\item \code{MASKVAL(S32)} gives the mask value for input data.
+\item \code{COMBINE(STR)} gives the statistic to use for combination.
+\item \code{BACKGROUND(STR)} gives the statistic to use to measure the background.
+\end{itemize}
+
+Statistics specified by a string (for \code{COMBINE} and
+\code{BACKGROUND}) may be one of \code{MEAN}, \code{MEDIAN},
+\code{ROBUST}, \code{FITTED} or \code{CLIPPED}.
+
+\subsubsubsection{Example}
+
+\begin{verbatim}
+# Recipe configuration for ppMerge
+ 
+ROWS            S32     128             # Number of rows to read at once
+ELECTRONS       F32     100.0           # Minimum number of electrons for useful signal
+SAMPLE          S32     100             # Sampling factor for measuring the background
+REJ             F32     3.0             # Rejection threshold (sigma)
+ITER            S32     1               # Number of rejection iterations
+FRACHIGH        F32     0.3             # Fraction of high pixels to reject immediately
+FRACLOW         F32     0.1             # Fraction of low pixels to reject immediately
+NKEEP           S32     5               # Minimum number of pixels in stack to keep
+MASKVAL         S32     0xff            # Mask value for input data
+### Statistics options: MEAN | MEDIAN | ROBUST | FITTED | CLIPPED
+COMBINE         STR     MEAN            # Statistic to use for combination: 
+BACKGROUND      STR     MEDIAN          # Statistic to use to measure the background
+\end{verbatim}
+
+
+\subsubsection{PPSTATS}
+
+The \code{PPSTATS} recipe contains options for \code{ppStats} or its
+library used within another program:
+\begin{itemize}
+\item \code{SAMPLE(F32)} specifies the fraction of the cell to sample
+  (for statistical measurements).
+\item \code{MASKVAL(U8)} specifies a mask value to use for the
+  statistics.
+\item \code{HEADER(STR)} specifies headers (may be listed, separated
+  by whitespace) to print.  Multiple \code{HEADER} entries may exist,
+  if it is declared \code{MULTI}.
+\item \code{CONCEPT(STR)} specifies concepts (may be listed, separated
+  by whitespace) to print.  Multiple \code{CONCEPT} entries may exist,
+  if it is declared \code{MULTI}.
+\item \code{STAT(STR)} specifies statistics (may be listed, separated
+  by whitespace) to print.  Multiple \code{STAT} entries may exist, if
+  it is declared \code{MULTI}.  Acceptable statistics names are those
+  parsed by \code{psStatsOptionFromString}.
+\end{itemize}
+
+\subsubsubsection{Example}
+
+\begin{verbatim}
+### ppStats recipe for Phase 0 with MegaCam
+
+# Options governing statistics
+SAMPLE          F32     0.1     # Fraction of cell to sample
+MASKVAL         U8      0xff    # Mask value to use for statistics
+
+# Define the outputs as MULTI
+HEADER          MULTI
+CONCEPT         MULTI
+STAT            MULTI
+
+# Values to return
+HEADER          STR     OBSERVER        # Observer name
+CONCEPT         STR     FPA.OBJECT      # Object name
+CONCEPT         STR     FPA.OBSTYPE     # Observation type
+CONCEPT         STR     FPA.FILTER      # Filter
+CONCEPT         STR     FPA.RA FPA.DEC  # Telescope pointing
+CONCEPT         STR     FPA.AIRMASS     # Airmass
+CONCEPT         STR     FPA.ALT FPA.AZ  # Telescopy alt/az
+CONCEPT         STR     FPA.POSANGLE    # Rotator angle
+CONCEPT         STR     CHIP.TEMP       # Detector temperature
+CONCEPT         STR     CELL.EXPOSURE   # Exposure time
+CONCEPT         STR     CELL.TIME       # Time of exposure
+STAT            STR     ROBUST_MEDIAN   # Background estimator
+STAT            STR     ROBUST_STDEV    # Background standard deviation estimator
+\end{verbatim}
+
+\subsubsection{PSPHOT}
+
+\tbd{EAM to fill this in.}
+
+\subsubsection{PSASTRO}
+
+\tbd{EAM to fill this in.}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Revision Change Log}
+%\input{ChangeLog.tex}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%\bibliographystyle{plain}
+%\bibliography{panstarrs}
+
+\end{document}
+
