Index: /trunk/archive/scripts/src/concepts.txt
===================================================================
--- /trunk/archive/scripts/src/concepts.txt	(revision 4385)
+++ /trunk/archive/scripts/src/concepts.txt	(revision 4386)
@@ -27,4 +27,8 @@
 FPA.RADECSYS		System of RA,Dec (e.g., J2000 or ICRS)
 FPA.NAME		An identifier (e.g., observation number) for the FPA instance
+FPA.DATE		UT date (YYYY-MM-DD)
+FPA.TIME		UT time (HH:MM:SS.sss)
+FPA.DATETIME		UT date and time (YYYY-MM-DDTHH:MM:SS.ss)
+FPA.MJD			Modified Julian Date
 
 Chip-level:
@@ -43,7 +47,7 @@
 CELL.GAIN		CCD gain (e/ADU)
 CELL.READNOISE		CCD read noise (e)
+CELL.SATURATION		CCD saturation point (ADU)
+CELL.BAD		CCD bad pixel point (ADU)
 
-CELL.XOFFSET		Offset on the CCD of window start in x
-CELL.YOFFSET		Offset on the CCD of window start in y
 CELL.XBIN		Binning in x
 CELL.YBIN		Binning in y
@@ -55,13 +59,57 @@
 value to become out of sync).  And there is no reason why (most)
 concepts lower down can't be specified higher up, and simply be
-inherited.  The exception to this is the OBSNUM (observation number),
-which allows an FPA to be identified given a cell, etc.
+inherited.  The exception to this is the FPA.NAME (observation
+number), which allows an FPA to be identified given a cell, etc.
+
+There are so many ways of specifying dates and times.  We probably
+want a high-level function, psCellGetTimeObs() to sort through all of the
+possibilities.
+
+Similarly with binning: CCDSUM is a common header, or the bin factors
+might be in separate headers.
 
 
-These are optional:
+Retrieval
+=========
 
-DB.HOST		Database host name (for psDBInit)
-DB.NAME		Database name (for psDBInit)
-DB.USER		Database user name (for psDBInit)
-DB.PASSWORD	Database password (for psDBInit)
+Each of the concepts can be retrieved in the following ways:
 
+1. FITS header translation: the camera configuration contains a
+   "TRANSLATION" entry, which gives the concept along with the FITS
+   header equivalent.
+
+2. Database: the camera configuration "DATABASE" entry contains
+   information on how to poll the database for the required concept.
+   The DATABASE entry contains metadatas specified using the TYPE:
+
+	TYPE		dbEntry		TABLE		COLUMN		GIVENDBCOL	GIVENPS
+
+   An example DATABASE entry is:
+
+	CELL.GAIN	dbEntry		Camera		gain		chipId,cellId	CHIP.NAME,CELL.NAME
+
+   This says, in the database, you basically do: "SELECT gain IN
+   Camera where chipId == CHIP.NAME and cellId == CELL.NAME" (where I
+   have, no doubt, taken liberty with the SQL query).  In this case,
+   CHIP.NAME and CELL.NAME are looked up before the query is executed,
+   using means other than a DB query (otherwise we could get stuck in
+   an infinite loop).
+
+3. Defaults: the camera configuration "DEFAULTS" entry contains
+   default values.  These default values may simply be specified, or
+   they may be dependent upon another value.  In the latter case, an
+   additional keyword, "CONCEPT_DEPEND", where "CONCEPT" is the
+   concept of interest, and "DEPEND" is literal, is specified with the
+   value being the concept on which it is dependent.  Then, the
+   concept is a METADATA type, with the elements being values of the
+   other concept on which it is dependent.  An example is helpful:
+
+	CELL.YPARITY_DEPEND	STR	CHIP.NAME
+	CELL.YPARITY	METADATA
+		ccd00	S32	-1
+		ccd35	S32	1
+	END
+
+   This says that the CELL.YPARITY is dependent upon the CHIP.NAME:
+   ccd00 has negative parity, and ccd35 has positive parity.
+
Index: /trunk/archive/scripts/src/gpc1_raw.config
===================================================================
--- /trunk/archive/scripts/src/gpc1_raw.config	(revision 4385)
+++ /trunk/archive/scripts/src/gpc1_raw.config	(revision 4386)
@@ -11,6 +11,4 @@
 PHU		STR	CHIP	# The FITS file represents a single chip
 EXTENSIONS	STR	CELL	# The extensions represent cells
-EXTENSION_KEY	STR	EXTNAME	# You get the extensions by looking at the EXTNAME header
-IDENTIFIER	STR	OBSID	# We identify the observation by the observation Id in the header
 
 # What's in the FITS file?
@@ -104,18 +102,93 @@
 # 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
+	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
+	CELL.XPARITY	S32	1
+	CELL.YPARITY	S32	1
+	CELL.TEST_DEPEND	STR	CELL.NAME
+	CELL.TEST	METADATA
+		xy00	S32	00
+		xy01	S32	01
+		xy02	S32	02
+		xy03	S32	03
+		xy04	S32	04
+		xy05	S32	05
+		xy06	S32	06
+		xy07	S32	07
+		xy10	S32	10
+		xy11	S32	11
+		xy12	S32	12
+		xy13	S32	13
+		xy14	S32	14
+		xy15	S32	15
+		xy16	S32	16
+		xy17	S32	17
+		xy20	S32	20
+		xy21	S32	21
+		xy22	S32	22
+		xy23	S32	23
+		xy24	S32	24
+		xy25	S32	25
+		xy26	S32	26
+		xy27	S32	27
+		xy30	S32	30
+		xy31	S32	31
+		xy32	S32	32
+		xy33	S32	33
+		xy34	S32	34
+		xy35	S32	35
+		xy36	S32	36
+		xy37	S32	37
+		xy40	S32	40
+		xy41	S32	41
+		xy42	S32	42
+		xy43	S32	43
+		xy44	S32	44
+		xy45	S32	45
+		xy46	S32	46
+		xy47	S32	47
+		xy50	S32	50
+		xy51	S32	51
+		xy52	S32	52
+		xy53	S32	53
+		xy54	S32	54
+		xy55	S32	55
+		xy56	S32	56
+		xy57	S32	57
+		xy60	S32	60
+		xy61	S32	61
+		xy62	S32	62
+		xy63	S32	63
+		xy64	S32	64
+		xy65	S32	65
+		xy66	S32	66
+		xy67	S32	67
+		xy70	S32	70
+		xy71	S32	71
+		xy72	S32	72
+		xy73	S32	73
+		xy74	S32	74
+		xy75	S32	75
+		xy76	S32	76
+		xy77	S32	77
+	END
 END
 
Index: /trunk/archive/scripts/src/ipprc.config
===================================================================
--- /trunk/archive/scripts/src/ipprc.config	(revision 4385)
+++ /trunk/archive/scripts/src/ipprc.config	(revision 4386)
@@ -3,7 +3,7 @@
 
 ### Database configuration
-DBSERVER	STR	ippdb.ifa.hawaii.edu
-DBUSER		STR	ipp
-DBPASSWORD	STR	password
+DBSERVER	STR	ippdb.ifa.hawaii.edu	# Database host name (for psDBInit)
+DBUSER		STR	ipp			# Database user name (for psDBInit)
+DBPASSWORD	STR	password		# Database password (for psDBInit)
 
 ### Setups for each camera system
Index: /trunk/archive/scripts/src/lris_blue.config
===================================================================
--- /trunk/archive/scripts/src/lris_blue.config	(revision 4385)
+++ /trunk/archive/scripts/src/lris_blue.config	(revision 4386)
@@ -32,6 +32,4 @@
 PHU		STR	FPA	# The FITS file represents an entire FPA
 EXTENSIONS	STR	NONE	# There are no extensions
-EXTENSION_KEY	STR	EXTNAME	# This is actually irrelevant since there are no extensions
-IDENTIFIER	STR	EXPNUM	# We identify the observation by the exposure number in the header
 
 # What's in the FITS file?
Index: /trunk/archive/scripts/src/lris_red.config
===================================================================
--- /trunk/archive/scripts/src/lris_red.config	(revision 4386)
+++ /trunk/archive/scripts/src/lris_red.config	(revision 4386)
@@ -0,0 +1,73 @@
+# 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
+	DETECTOR	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
+
Index: /trunk/archive/scripts/src/megacam_raw.config
===================================================================
--- /trunk/archive/scripts/src/megacam_raw.config	(revision 4385)
+++ /trunk/archive/scripts/src/megacam_raw.config	(revision 4386)
@@ -12,51 +12,157 @@
 PHU		STR	FPA	# The FITS file represents an entire FPA
 EXTENSIONS	STR	CELL	# The extensions represent cells
-EXTENSION_KEY	STR	EXTNAME	# You get the extensions by looking at the EXTNAME header
-IDENTIFIER	STR	OBSID	# We identify the observation by the observation Id in the header
 
 # What's in the FITS file?
 CONTENTS	METADATA
 	# Extension name, chip name:type
-	amp00	STR	ccd00:science
-	amp01	STR	ccd00:science
-	amp02	STR	ccd01:science
-	amp03	STR	ccd01:science
-	guide	STR	guide:guide		# A guide CCD thrown in, just for fun
+	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
-	science	METADATA	# A science CCD
-		CELL.BIASSEC	STR	VALUE:[1:10,1:4096];[1035:1084,1:4096]
-		CELL.TRIMSEC	STR	VALUE:[11:1034,1:4096]
-	#	CELL.BIASSEC	STR	HEADER:BIASSEC
-	#	CELL.TRIMSEC	STR	HEADER:TRIMSEC
+	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
-
-	guide	METADATA	# A guide CCD
-		CELL.BIASSEC	STR	VALUE:[1:10,1:1024];[1035:1084,1:1024]
-		CELL.TRIMSEC	STR	VALUE:[11:1034,1:1024]
-	#	CELL.BIASSEC	STR	HEADER:BIASSEC
-	#	CELL.TRIMSEC	STR	HEADER:TRIMSEC
+	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
 	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	POSANG
-	FPA.RA		STR	OBJ-RA
-	FPA.DEC		STR	OBJ-DEC
-	CELL.EXPOSURE	STR	EXPOSURE
-	CELL.DARKTIME	STR	EXPOSURE	# No specific darktime header; use exposure time
-	CELL.DATE	STR	DATE-OBS
-	CELL.TIME	STR	TIME-OBS
+	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
-	FPA.RADECSYS	STR	ICRS
+	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
+		ccd20	S32	1
+		ccd31	S32	1
+		ccd32	S32	1
+		ccd33	S32	1
+		ccd34	S32	1
+		ccd35	S32	1
+	END
 END
 
@@ -64,6 +170,6 @@
 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
+#	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
@@ -72,2 +178,3 @@
 
 END
+
Index: /trunk/archive/scripts/src/megacam_splice.config
===================================================================
--- /trunk/archive/scripts/src/megacam_splice.config	(revision 4385)
+++ /trunk/archive/scripts/src/megacam_splice.config	(revision 4386)
@@ -11,28 +11,56 @@
 PHU		STR	FPA	# The FITS file represents an entire FPA
 EXTENSIONS	STR	CHIP	# The extensions represent chips
-EXTENSION_KEY	STR	EXTNAME	# You get the extensions by looking at the EXTNAME header
-IDENTIFIER	STR	OBSID	# We identify the observation by the observation Id in the header
 
 # What's in the FITS file?
 CONTENTS	METADATA
 	# Extension name, components
-	ccd00		STR	LeftAmp RightAmp
-	ccd01		STR	LeftAmp RightAmp
+	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
-	LeftAmp		METADATA
-		CELL.BIASSEC	STR	VALUE:[1:10,1:2048];[2069:2118,1:2048]
-		CELL.TRIMSEC	STR	VALUE:[21:1044,1:2048]
-	#	CELL.BIASSEC	STR	HEADER:BIASSECA
-	#	CELL.TRIMSEC	STR	HEADER:TRIMSECA
+	left		METADATA
+		CELL.BIASSEC	STR	HEADER:BSECA
+		CELL.TRIMSEC	STR	HEADER:TSECA
 	END
 
-	RightAmp	METADATA
-		CELL.BIASSEC	STR	VALUE:[11:20,1:2048];[2119:2168,1:2048]
-		CELL.TRIMSEC	STR	VALUE:[1045:2068,1:2048]
-	#	CELL.BIASSEC	STR	HEADER:BIASSECB
-	#	CELL.TRIMSEC	STR	HEADER:TRIMSECB
+	right		METADATA
+		CELL.BIASSEC	STR	HEADER:BSECB
+		CELL.TRIMSEC	STR	HEADER:TSECB
 	END
 END
@@ -40,20 +68,34 @@
 # 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
+        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 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
+#	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
Index: /trunk/archive/scripts/src/papFocalPlane.c
===================================================================
--- /trunk/archive/scripts/src/papFocalPlane.c	(revision 4385)
+++ /trunk/archive/scripts/src/papFocalPlane.c	(revision 4386)
@@ -44,15 +44,14 @@
     psMetadataItem *newItem = psMetadataItemAlloc(valueName, value->type, value->comment, value->data.V);
 
-    if (fpa) {
+    if (fpa && strncmp(valueName, "FPA", 3) == 0) {
 	psMetadataAddItem(fpa->values, newItem, PS_LIST_TAIL, PS_META_REPLACE);
     }
-    if (chip) {
+    if (chip && strncmp(valueName, "CHIP", 4) == 0) {
 	psMetadataAddItem(chip->values, newItem, PS_LIST_TAIL, PS_META_REPLACE);
     }
-    if (cell) {
+    if (cell && strncmp(valueName, "CELL", 4) == 0) {
 	psMetadataAddItem(cell->values, newItem, PS_LIST_TAIL, PS_META_REPLACE);
     }
 
-    psFree(newItem);
 }
 
@@ -65,8 +64,13 @@
 {
     bool mdStatus = true;		// Status of MD lookup
+    psMetadata *translation = psMetadataLookupMD(&mdStatus, fpa->camera, "TRANSLATION"); // FITS translation
+    if (! mdStatus) {
+	psError(PS_ERR_IO, false, "Unable to find TRANSLATION in camera configuration.\n");
+	return NULL;
+    }
 
     // Look for how to translate the concept into a FITS header name
-    const char *header = psMetadataLookupString(&mdStatus, fpa->fits, valueName);
-    if (strlen(header) > 0) {
+    const char *header = psMetadataLookupString(&mdStatus, translation, valueName);
+    if (mdStatus && strlen(header) > 0) {
 	// We have a FITS header to look up --- search each level
 	if (cell->header) {
@@ -110,8 +114,49 @@
     )
 {
-    psMetadataItem *defItem = psMetadataLookup((psMetadata*)fpa->defaults, valueName);
+    bool mdOK = true;			// Status of MD lookup
+    psMetadata *defaults = psMetadataLookupMD(&mdOK, fpa->camera, "DEFAULTS");
+    if (! mdOK) {
+	psError(PS_ERR_IO, false, "Unable to find DEFAULTS in camera configuration.\n");
+	return NULL;
+    }
+
+    psMetadataItem *defItem = psMetadataLookup(defaults, valueName);
     if (defItem) {
+	if (defItem->type == PS_META_META) {
+	    // A dependent default
+	    psTrace(__func__, 7, "Evaluating dependent default....\n");
+	    psMetadata *dependents = defItem->data.V; // The list of dependents
+	    // Find out what it depends on
+	    psString dependName = psStringCopy(valueName);
+	    psStringAppend(&dependName, "_DEPEND");
+	    psString dependsOn = psMetadataLookupString(&mdOK, defaults, dependName);
+	    if (! mdOK) {
+		psError(PS_ERR_IO, false, "Unable to find %s in camera configuration for dependent default"
+			" --- ignored\n", dependName);
+		// XXX: Need to clean up before returning
+		return NULL;
+	    }
+	    psFree(dependName);
+	    // Find the value of the dependent concept
+	    psMetadataItem *depItem = getValueFromCache(fpa, chip, cell, dependsOn);
+	    if (! depItem) {
+		depItem = getValueFromHeader(fpa, chip, cell, dependsOn);
+	    }
+	    if (! depItem) {
+		psError(PS_ERR_IO, true, "Unable to find value for %s (required for %s)\n", dependsOn,
+			valueName);
+		return NULL;
+	    }
+	    if (depItem->type != PS_META_STR) {
+		psError(PS_ERR_IO, true, "Value of %s is not of type string, as required for dependency"
+			" --- ignored.\n", dependsOn);
+	    }
+
+	    defItem = psMetadataLookup(dependents, depItem->data.V);	// This is now what we were after
+	}
 	setValueInCache(fpa, chip, cell, valueName, defItem);
     }
+
+    // XXX: Need to clean up before returning
     return defItem;			// defItem is either NULL or points to what was desired
 }
@@ -125,79 +170,85 @@
     )
 {
-    if (fpa->db) {
-	// The database has been initialised
-	bool mdStatus = true;		// Status of MD lookup
-	psMetadata *dbLookup = psMetadataLookupMD(&mdStatus, fpa->database, valueName);
-	if (dbLookup) {
-	    const char *tableName = psMetadataLookupString(&mdStatus, dbLookup, "TABLE"); // Name of the table
-	    const char *colName = psMetadataLookupString(&mdStatus, dbLookup, "COLUMN"); // Name of the column
-	    const char *givenCols = psMetadataLookupString(&mdStatus, dbLookup, "GIVENDBCOL");	// Name of "where" columns
-	    const char *givenPS = psMetadataLookupString(&mdStatus, dbLookup, "GIVENPS"); // Values for "where" columns
-	    
-	    // Now, need to get the "given"s
-	    if (strlen(givenCols) || strlen(givenPS)) {
-		psList *cols = papSplit(givenCols, ",;"); // List of column names
-		psList *values = papSplit(givenPS, ",;"); // List of value names for the columns
-		psMetadata *selection = psMetadataAlloc(); // The stuff to select in the DB
-		if (cols->size != values->size) {
-		    psLogMsg(__func__, PS_LOG_WARN, "The GIVENDBCOL and GIVENPS entries for %s do not have "
-			     "the same number of entries --- ignored.\n", valueName);
+    if (! fpa->db) {
+	// No database initialised
+	return NULL;
+    }
+
+    bool mdStatus = true;		// Status of MD lookup
+    psMetadata *database = psMetadataLookupMD(&mdStatus, fpa->camera, "DATABASE");
+    if (! mdStatus) {
+	// No error, because not everyone needs to use the DB
+	return NULL;
+    }
+
+    psMetadata *dbLookup = psMetadataLookupMD(&mdStatus, database, valueName);
+    if (dbLookup) {
+	const char *tableName = psMetadataLookupString(&mdStatus, dbLookup, "TABLE"); // Name of the table
+	const char *colName = psMetadataLookupString(&mdStatus, dbLookup, "COLUMN"); // Name of the column
+	const char *givenCols = psMetadataLookupString(&mdStatus, dbLookup, "GIVENDBCOL");	// Name of "where" columns
+	const char *givenPS = psMetadataLookupString(&mdStatus, dbLookup, "GIVENPS"); // Values for "where" columns
+	
+	// Now, need to get the "given"s
+	if (strlen(givenCols) || strlen(givenPS)) {
+	    psList *cols = papSplit(givenCols, ",;"); // List of column names
+	    psList *values = papSplit(givenPS, ",;"); // List of value names for the columns
+	    psMetadata *selection = psMetadataAlloc(); // The stuff to select in the DB
+	    if (cols->size != values->size) {
+		psLogMsg(__func__, PS_LOG_WARN, "The GIVENDBCOL and GIVENPS entries for %s do not have "
+			 "the same number of entries --- ignored.\n", valueName);
+	    } else {
+		// Iterators for the lists
+		psListIterator *colsIter = psListIteratorAlloc(cols, PS_LIST_HEAD, false);
+		psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false);
+		char *column = NULL;	// Name of the column
+		while (column = psListGetAndIncrement(colsIter)) {
+		    const char *name = psListGetAndIncrement(valuesIter); // Name for the value
+		    if (!strlen(column) || !strlen(name)) {
+			psLogMsg(__func__, PS_LOG_WARN, "One of the columns or value names for %s is "
+				 " empty --- ignored.\n", valueName);
+		    } else {
+			// Search for the value name
+			psMetadataItem *item = getValueFromCache(fpa, chip, cell, name);
+			if (! item) {
+			    item = getValueFromHeader(fpa, chip, cell, name);
+			}
+			if (! item) {
+			    item = getValueFromDefault(fpa, chip, cell, name);
+			}
+			if (! item) {
+			    psLogMsg(__func__, PS_LOG_ERROR, "Unable to find the value name %s for DB "
+				     " lookup on %s --- ignored.\n", name, valueName);
+			} else {
+			    // We need to create a new psMetadataItem.  I don't think we can't simply hack
+			    // the existing one, since that could conceivably cause memory leaks
+			    psMetadataItem *newItem = psMetadataItemAlloc(valueName, item->type,
+									  item->comment, item->data.V);
+			    psMetadataAddItem(selection, newItem, PS_LIST_TAIL, PS_META_REPLACE);
+			    psFree(newItem);
+			}
+		    }
+		} // Iterating through the columns
+		
+		psArray *dbResult = psDBSelectRows(fpa->db, tableName, selection, 2); // Lookup result
+		// Note that we use limit=2 in order to test if there are multiple rows returned
+		
+		psMetadataItem *result = NULL; // The final result of the DB lookup
+		if (dbResult->n == 0) {
+		    psLogMsg(__func__, PS_LOG_WARN, "Unable to find any rows in DB for %s --- ignored\n", 
+			     valueName);
 		} else {
-		    // Iterators for the lists
-		    psListIterator *colsIter = psListIteratorAlloc(cols, PS_LIST_HEAD, false);
-		    psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false);
-		    char *column = NULL;	// Name of the column
-		    while (column = psListGetAndIncrement(colsIter)) {
-			const char *name = psListGetAndIncrement(valuesIter); // Name for the value
-			if (!strlen(column) || !strlen(name)) {
-			    psLogMsg(__func__, PS_LOG_WARN, "One of the columns or value names for %s is "
-				     " empty --- ignored.\n", valueName);
-			} else {
-			    // Search for the value name
-			    psMetadataItem *item = getValueFromCache(fpa, chip, cell, name);
-			    if (! item) {
-				item = getValueFromHeader(fpa, chip, cell, name);
-			    }
-			    if (! item) {
-				item = getValueFromDefault(fpa, chip, cell, name);
-			    }
-			    if (! item) {
-				psLogMsg(__func__, PS_LOG_ERROR, "Unable to find the value name %s for DB "
-					 " lookup on %s --- ignored.\n", name, valueName);
-			    } else {
-				// We need to create a new psMetadataItem.  I don't think we can't simply hack
-				// the existing one, since that could conceivably cause memory leaks
-				psMetadataItem *newItem = psMetadataItemAlloc(valueName, item->type,
-									      item->comment, item->data.V);
-				psMetadataAddItem(selection, newItem, PS_LIST_TAIL, PS_META_REPLACE);
-				psFree(newItem);
-			    }
-			}
-		    } // Iterating through the columns
-		    
-		    psArray *dbResult = psDBSelectRows(fpa->db, tableName, selection, 2); // Result of lookup
-		    // Note that we use limit=2 in order to test if there are multiple rows returned
-
-		    psMetadataItem *result = NULL; // The final result of the DB lookup
-		    if (dbResult->n == 0) {
-			psLogMsg(__func__, PS_LOG_WARN, "Unable to find any rows in DB for %s --- ignored\n", 
-				 valueName);
-		    } else {
-			if (dbResult-> n > 1) {
-			    psLogMsg(__func__, PS_LOG_WARN, "Multiple rows returned in DB lookup for %s --- "
-				     " using the first one only.\n", valueName);
-			}
-			result = (psMetadataItem*)dbResult->data[0];
+		    if (dbResult-> n > 1) {
+			psLogMsg(__func__, PS_LOG_WARN, "Multiple rows returned in DB lookup for %s --- "
+				 " using the first one only.\n", valueName);
 		    }
-		    // XXX: Need to clean up before returning
-		    return result;
+		    result = (psMetadataItem*)dbResult->data[0];
 		}
-	    }
-	} // Doing the "given"s.
-    }
-
-    // XXX: Need to clean up before returning
-
-    // If we've fallen through somehow, we didn't get anything.
+		// XXX: Need to clean up before returning
+		return result;
+	    }
+	}
+    } // Doing the "given"s.
+
+    // Shouldn't get here
     return NULL;
 }
@@ -209,17 +260,31 @@
 			       )
 {
+    psTrace(__func__, 3, "Trying to retrieve %s for %s:%s...\n", valueName, chipName, cellName);
+
     bool mdStatus = true;		// Status of MD lookup
     papChip *chip = psMetadataLookupChip(&mdStatus, fpa->chips, chipName); // The chip
+    if (!mdStatus) {
+	psError(PS_ERR_IO, false, "Unable to find chip named %s\n", chipName);
+	return NULL;
+    }
     papCell *cell = psMetadataLookupCell(&mdStatus, chip->cells, cellName); // The cell
+    if (!mdStatus) {
+	psError(PS_ERR_IO, false, "Unable to find cell named %s in chip %s\n", cellName, chipName);
+	return NULL;
+    }
 
     // Try cache, headers, database, defaults in order
+    psTrace(__func__, 5, "Trying caches....\n");
     psMetadataItem *item = getValueFromCache(fpa, chip, cell, valueName);
     if (! item) {
+	psTrace(__func__, 5, "Trying headers....\n");
 	item = getValueFromHeader(fpa, chip, cell, valueName);
     }
     if (! item) {
+	psTrace(__func__, 5, "Trying database....\n");
 	item = getValueFromDB(fpa, chip, cell, valueName);
     }
     if (! item) {
+	psTrace(__func__, 5, "Trying defaults....\n");
 	item = getValueFromDefault(fpa, chip, cell, valueName);
     }
@@ -245,5 +310,4 @@
     }
 
-    psFree(item);
     return value;
 }
@@ -266,5 +330,4 @@
     }
 
-    psFree(item);
     return value;
 }
@@ -288,5 +351,4 @@
     }
 
-    psFree(item);
     return value;
 }
@@ -310,5 +372,4 @@
     }
 
-    psFree(item);
     return value;
 }
@@ -318,8 +379,6 @@
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-papFPA *papFPAAlloc(psMetadata *fits, // FITS translation info
-		    psMetadata *database, // Database lookup info
-		    psMetadata *defaults, // Defaults info
-		    psDB *db		// Database handle
+papFPA *papFPAAlloc(const psMetadata *camera, // Camera configuration
+		    psDB *db		// Database
     )
 {
@@ -327,15 +386,16 @@
     psMemSetDeallocator(fpa, (psFreeFcn)p_papFPAFree);
 
-    // Fill in the various components
-    fpa->fits = psMemIncrRefCounter(fits);
-    fpa->database = psMemIncrRefCounter(database);
-    fpa->defaults = psMemIncrRefCounter(defaults);
+    // Fill in the components
+    fpa->fromTangentPlane = NULL;
+    fpa->toTangentPlane = NULL;
+    fpa->projection = NULL;
 
     fpa->values = psMetadataAlloc();
+    fpa->camera = psMemIncrRefCounter((psPtr)camera);
+    fpa->db = db;
+    fpa->chips = psMetadataAlloc();
+
+    fpa->pixels = NULL;
     fpa->header = NULL;
-    fpa->db = psMemIncrRefCounter(db);
-
-    fpa->chips = psMetadataAlloc();
-    fpa->images = NULL;
 
     return fpa;
@@ -344,31 +404,42 @@
 void p_papFPAFree(papFPA *fpa)
 {
-    psFree((psPtr)fpa->fits);
-    psFree((psPtr)fpa->database);
-    psFree((psPtr)fpa->defaults);
+    psFree(fpa->fromTangentPlane);
+    psFree(fpa->toTangentPlane);
+    psFree(fpa->projection);
 
     psFree(fpa->values);
+    psFree((psPtr)fpa->camera);
+    psFree(fpa->db);
+    psFree(fpa->chips);
+
+    psFree(fpa->pixels);
     psFree(fpa->header);
-    if (fpa->db) {
-	psDBCleanup((psDB*)fpa->db);
-    }
-
-    psFree(fpa->chips);
-    psFree(fpa->images);
-}
-
-papChip *papChipAlloc(papFPA *fpa,		// FPA to which the chip belongs
-		    const char *name	// Name of the chip
+}
+
+papChip *papChipAlloc(papFPA *fpa,	// FPA to which the chip belongs
+		      const char *name	// Name of the chip
     )
 {
     papChip *chip = psAlloc(sizeof(papChip)); // The chip
     psMemSetDeallocator(chip, (psFreeFcn)p_papChipFree);
-    psMetadataAdd(fpa->chips, PS_LIST_TAIL, name, PS_META_CHIP, "Added on allocation of chip", chip);
+
+    // Push onto the FPA
+    psMetadataAdd(fpa->chips, PS_LIST_TAIL, name, PS_META_CHIP, "Chip added on allocation", chip);
+
+    // Fill in the components
+    *(int*)&chip->col0 = 0;		// Good enough for now
+    *(int*)&chip->row0 = 0;		// Good enough for now
+
+    chip->toFPA = NULL;
+    chip->fromFPA = NULL;
 
     chip->values = psMetadataAlloc();
+    chip->cells = psMetadataAlloc();
+
+    chip->pixels = NULL;
     chip->header = NULL;
 
-    chip->cells = psMetadataAlloc();
-    chip->images = NULL;
+    psMetadataAdd(chip->values, PS_LIST_TAIL, "CHIP.NAME", PS_META_STR, "Name of the chip",
+		  psStringCopy(name));
 
     return chip;
@@ -377,24 +448,43 @@
 void p_papChipFree(papChip *chip)
 {
+    psFree(chip->toFPA);
+    psFree(chip->fromFPA);
+
     psFree(chip->values);
+    psFree(chip->cells);
+
+    psFree(chip->pixels);
     psFree(chip->header);
-    psFree(chip->cells);
-    psFree(chip->images);
 }
 
 papCell *papCellAlloc(papChip *chip,	// Chip to which the cell belongs
-		    const char *name,	// Name of the cell
-		    int nReadouts	// Number of readouts contained
+		      const char *name,	// Name of the cell
+		      int nReadouts	// Number of readouts contained
     )
 {
     papCell *cell = psAlloc(sizeof(papCell)); // The cell
     psMemSetDeallocator(cell, (psFreeFcn)p_papCellFree);
-    psMetadataAdd(chip->cells, PS_LIST_TAIL, name, PS_META_CELL, "Added on allocation of cell", cell);
+
+    // Push onto the chip
+    psMetadataAdd(chip->cells, PS_LIST_TAIL, name, PS_META_CELL, "Cell added on allocation", cell);
+
+    // Fill in components
+    *(int*)&cell->col0 = 0;		// Good enough for now
+    *(int*)&cell->row0 = 0;		// Good enough for now
+
+    cell->toChip = NULL;
+    cell->fromChip = NULL;
+    cell->toFPA = NULL;
+    cell->toTP = NULL;
+    cell->toSky = NULL;
 
     cell->values = psMetadataAlloc();
+    cell->readouts = psArrayAlloc(nReadouts);
+
+    cell->pixels = NULL;
     cell->header = NULL;
 
-    cell->readouts = psArrayAlloc(nReadouts);
-    cell->images = NULL;
+    psMetadataAdd(cell->values, PS_LIST_TAIL, "CELL.NAME", PS_META_STR, "Name of the cell",
+		  psStringCopy(name));
 
     return cell;
@@ -403,8 +493,15 @@
 void p_papCellFree(papCell *cell)
 {
+    psFree(cell->toChip);
+    psFree(cell->fromChip);
+    psFree(cell->toFPA);
+    psFree(cell->toTP);
+    psFree(cell->toSky);
+
     psFree(cell->values);
+    psFree(cell->readouts);
+
+    psFree(cell->pixels);
     psFree(cell->header);
-    psFree(cell->readouts);
-    psFree(cell->images);
 }
 
Index: /trunk/archive/scripts/src/papFocalPlane.h
===================================================================
--- /trunk/archive/scripts/src/papFocalPlane.h	(revision 4385)
+++ /trunk/archive/scripts/src/papFocalPlane.h	(revision 4386)
@@ -9,46 +9,55 @@
 #define PS_META_CELL PS_META_UNKNOWN
 
-
 typedef struct {
-    // How to get information
-    const psMetadata *defaults;		// IPP concepts supplied with defaults
-    const psMetadata *database;		// IPP concepts supplied from database lookup
-    const psMetadata *fits;		// IPP concepts supplied from FITS headers
-    
-    // A source of information
+    // Astrometric transformations
+    psPlaneDistort* fromTangentPlane;	// Transformation from tangent plane to focal plane
+    psPlaneDistort* toTangentPlane;	// Transformation from focal plane to tangent plane
+    psProjection *projection;		// Projection from tangent plane to sky
+    // Information
     psMetadata *values;			// Important values (cached)
-    psMetadata *header;			// The FITS header
-    psDB *db;				// The database handle
-
-    // Lower levels
+    const psMetadata *camera;		// Camera configuration
+    psDB *db;				// Database
     psMetadata *chips;			// The chips (referred to by name)
-
-    psArray *images;			// The pixel data, if it corresponds to this level
+    // FITS data
+    psArray *pixels;			// The pixel data, if it corresponds to this level
+    psMetadata *header;			// The FITS header, if it corresponds to this level
 } papFPA;
 
 typedef struct {
-    // Sources of information
+    // Offset specifying position on focal plane
+    const int col0;			// Offset from the left of FPA
+    const int row0;			// Offset from the bottom of FPA
+    // Astrometric transformations
+    psPlaneTransform* toFPA;		// Transformation from chip to FPA coordinates
+    psPlaneTransform* fromFPA;		// Transformation from FPA to chip coordinates
+    // Information
     psMetadata *values;			// Important values (cached)
-    psMetadata *header;			// The FITS header
-
-    // Lower levels
     psMetadata *cells;			// The cells (referred to by name)
-
-    psArray *images;			// The pixel data, if it corresponds to this level
+    // FITS data
+    psArray *pixels;			// The pixel data, if it corresponds to this level
+    psMetadata *header;			// The FITS header, if it corresponds to this level
 } papChip;
 
 typedef struct {
-    // Sources of information
+    // Offset specifying position on chip
+    const int col0;			// Offset from the left of chip
+    const int row0;			// Offset from the bottom of chip
+    // Astrometric transformations
+    psPlaneTransform* toChip;		// Transformations from cell to chip coordinates
+    psPlaneTransform* fromChip;		// Transformations from cell to chip coordinates
+    psPlaneTransform* toFPA;		// Transformations from cell to FPA coordinates
+    psPlaneTransform* toTP;		// Transformations from cell to FPA coordinates
+    psPlaneTransform* toSky;		// Transformations from cell to tangent plane coordinates
+    // Information
     psMetadata *values;			// Important values (cached)
-    psMetadata *header;			// The FITS header
-
-    // Lower levels
     psArray *readouts;			// The readouts (referred to by number)
-
-    psArray *images;			// The pixel data, if it corresponds to this level
+    // FITS data
+    psArray *pixels;			// The pixel data, if it corresponds to this level
+    psMetadata *header;			// The FITS header, if it corresponds to this level
 } papCell;
 
 
 typedef struct {
+    // Details for position on the cell
     const int col0;			// Offset from the left of cell.
     const int row0;			// Offset from the bottom of cell.
@@ -57,7 +66,8 @@
     const unsigned int colBins;		// Amount of binning in x-dimension
     const unsigned int rowBins;		// Amount of binning in y-dimension
-    psImage* image;			// The pixels
+    // Information
+    psImage *image;			// The pixels
     psList *overscans;			// Array of subimages containing the overscan region(s)
-    psMetadata* values;			// readout-level metadata
+    psMetadata *values;			// readout-level metadata
 } papReadout;
 
@@ -68,5 +78,5 @@
 			       const char *cellName, // The name of the cell
 			       const char *valueName // Name of value
-			       );
+    );
 
 // Type-specific functions provided as a convenience to the user
@@ -94,12 +104,10 @@
 
 // Allocators and deallocators
-papFPA *papFPAAlloc(psMetadata *fits, // FITS translation info
-		    psMetadata *database, // Database lookup info
-		    psMetadata *defaults, // Defaults info
-		    psDB *db		// Database handle
+papFPA *papFPAAlloc(const psMetadata *camera, // Camera configuration
+		    psDB *db		// Database
     );
 void p_papFPAFree(papFPA *fpa);
 
-papChip *papChipAlloc(papFPA *fpa,		// FPA to which the chip belongs
+papChip *papChipAlloc(papFPA *fpa,	// FPA to which the chip belongs
 		    const char *name	// Name of the chip
     );
@@ -107,14 +115,14 @@
 
 papCell *papCellAlloc(papChip *chip,	// Chip to which the cell belongs
-		    const char *name,	// Name of the cell
-		    int nReadouts	// Number of readouts contained
+		      const char *name,	// Name of the cell
+		      int nReadouts	// Number of readouts contained
     );
 void p_papCellFree(papCell *cell);
 
 papReadout *papReadoutAlloc(papCell *cell,	// Cell to which the readout belongs
-			  int readoutNum, // Number of the readout
-			  psImage *image, // The pixels
-			  psList *overscans, // The overscan images
-			  int col0, int row0, int colParity, int rowParity, int colBin, int rowBin // Data
+			    int readoutNum, // Number of the readout
+			    psImage *image, // The pixels
+			    psList *overscans, // The overscan images
+			    int col0, int row0, int colParity, int rowParity, int colBin, int rowBin // Data
     );
 void p_papReadoutFree(papReadout *readout);
Index: /trunk/archive/scripts/src/papmodule.h
===================================================================
--- /trunk/archive/scripts/src/papmodule.h	(revision 4385)
+++ /trunk/archive/scripts/src/papmodule.h	(revision 4386)
@@ -5,2 +5,3 @@
 #include "papStuff.h"
 #include "psAdditionals.h"
+#include "papFocalPlane.h"
Index: /trunk/archive/scripts/src/pmFPARead.c
===================================================================
--- /trunk/archive/scripts/src/pmFPARead.c	(revision 4385)
+++ /trunk/archive/scripts/src/pmFPARead.c	(revision 4386)
@@ -12,12 +12,14 @@
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-// Copy a metadata
-static psMetadata *metadataCopy(psMetadata *md)
-{
-    psMetadata *new = psMetadataAlloc();// The metadata to return
-    psMetadataIterator *mdIter = psMetadataIteratorAlloc(md, PS_LIST_HEAD, NULL); // Iterator for the MD
+// Copy metadata elements into another metadata
+static void metadataCopy(psMetadata *to, // Metadata to which to copy
+			 psMetadata *from // Metdata from which to copy
+    )
+{
+    psMetadataIterator *mdIter = psMetadataIteratorAlloc(from, PS_LIST_HEAD, NULL); // Iterator for the MD
     psMetadataItem *item = NULL;	// Item from the metadata
     while (item = psMetadataGetAndIncrement(mdIter)) {
-	if (! psMetadataAddItem(new, item, PS_LIST_TAIL, PS_META_REPLACE)) {
+	psTrace(__func__, 9, "Adding %s to metadata...\n", item->name);
+	if (! psMetadataAddItem(to, item, PS_LIST_TAIL, PS_META_REPLACE)) {
 	    psLogMsg(__func__, PS_LOG_WARN, "Unable to add item (%s: %s) to metadata: ignored\n", item->name,
 		     item->comment);
@@ -25,6 +27,4 @@
     }
     psFree(mdIter);
-
-    return new;
 }
 
@@ -46,10 +46,5 @@
 	return NULL;
     } else {
-#if 0
-	psMetadata *newCell = metadataCopy(cellData); // A copy of the cell, to be returned
-	return newCell;
-#else
-	return psMemIncrRefCounter(cellData);
-#endif
+	return cellData;
     }
 }
@@ -62,5 +57,10 @@
     )
 {
-    if (! psFitsMoveExtName(fits, extName)) {
+    if (strncmp(extName, "PHU", 3) == 0) {
+	if (!psFitsMoveExtNum(fits, 0, false)) {
+	    psError(PS_ERR_IO, false, "Unable to find PHU in FITS file!\n");
+	    return false;
+	}
+    } else if (! psFitsMoveExtName(fits, extName)) {
 	psError(PS_ERR_IO, false, "Unable to find extension %s in FITS file!\n", extName);
 	return false;
@@ -79,5 +79,5 @@
 
     int numPlanes = 1;			// Number of planes
-    if (nAxis > 3) {
+    if (nAxis == 3) {
 	numPlanes = psMetadataLookupS32(&mdStatus, *header, "NAXIS3");
 	if (!mdStatus) {
@@ -251,18 +251,11 @@
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-papFPA *pmFPARead(const psMetadata *camera, // The camera configuration
-		  psFits *fits // A FITS file
-    )
-{
+papFPA *pmFPARead(psFits *fits, // A FITS file
+		  const psMetadata *camera, // The camera configuration
+		  psDB *db		// Database
+    )
+{
+    papFPA *fpa = papFPAAlloc(camera, db); // The FPA to fill out
     bool mdStatus = true;		// Status from metadata lookups
-    // Get the configuration information out of the camera config
-    psMetadata *translation = psMetadataLookupMD(&mdStatus, camera, "TRANSLATION");
-    psMetadata *database = psMetadataLookupMD(&mdStatus, camera, "DATABASE");
-    psMetadata *defaults = psMetadataLookupMD(&mdStatus, camera, "DEFAULTS");
-    psDB *dbh = NULL;
-
-    // Generate a build tree
-    papFPA *fpa = papFPAAlloc(translation, database, defaults, dbh); // The FPA to fill out
-
     const char *phuType = psMetadataLookupString(&mdStatus, camera, "PHU"); // What is the PHU?
     const char *extType = psMetadataLookupString(&mdStatus, camera, "EXTENSIONS"); // What's in the extensions?
@@ -286,6 +279,5 @@
 		const char *extName = contentItem->name; // The name of the extension
 		papChip *chip = papChipAlloc(fpa, extName); // The chip
-		readExtension(&(chip->images), &(chip->header), fits, extName);
-
+		readExtension(&(chip->pixels), &(chip->header), fits, extName);
 		if (contentItem->type != PS_META_STR) {
 		    psLogMsg(__func__, PS_LOG_WARN, "Type of content item (%x) is not string: ignored\n",
@@ -293,4 +285,5 @@
 		} else {
 		    const char *content = contentItem->data.V; // The content of the extension
+		    psTrace(__func__, 7, "Content of %s is: %s\n", extName, content);
 		    psList *cellNames = papSplit(content, " ,"); // A list of the component cells
 		    psListIterator *cellNamesIter = psListIteratorAlloc(cellNames, PS_LIST_HEAD, NULL);
@@ -298,7 +291,8 @@
 		    while (cellName = psListGetAndIncrement(cellNamesIter)) {
 			// Get the cell data
-			papCell *cell = papCellAlloc(chip, cellName, ((psArray*)chip->images)->n); // The cell
-			cell->values = getCellData(camera, cellName);
-			portionCell(cell, chip->images, chip->header);
+			papCell *cell = papCellAlloc(chip, cellName, ((psArray*)chip->pixels)->n); // The cell
+			psMetadata *cellData = getCellData(camera, cellName);
+			metadataCopy(cell->values, cellData);
+			portionCell(cell, chip->pixels, chip->header);
 		    }
 		    psFree(cellNamesIter);
@@ -309,4 +303,5 @@
 	} else if (strncmp(extType, "CELL", 4) == 0) {
 	    // Extensions are cells; Content contains a chip name and cell type
+	    psMetadata *chipNumbers = psMetadataAlloc(); // Given a chip name, holds the chip number
 	    while (contentItem = psMetadataGetAndIncrement(contentsIter)) {
 		const char *extName = contentItem->name; // The name of the extension
@@ -324,18 +319,25 @@
 			const char *chipName = psListGet(contents, 0); // The name of the chip
 			const char *cellType = psListGet(contents, 1); // The type of cell
+			psTrace(__func__, 7, "Extension is cell of type %s, from chip %s\n", cellType,
+				chipName);
 
 			papChip *chip = psMetadataLookupChip(&mdStatus, fpa->chips, chipName); // The chip
 			if (! mdStatus && ! chip) {
-			    papChip *chip = papChipAlloc(fpa, "CHIP");
+			    chip = papChipAlloc(fpa, chipName);
 			}
 			// The cell
 			psArray *images = NULL;
 			psMetadata *header = NULL;
+			psTrace(__func__, 7, "Reading extension %s\n", extName);
 			readExtension(&images, &header, fits, extName);
-			papCell *cell = papCellAlloc(chip, extName, images->n); // The cell
-			cell->images = images;
+			psTrace(__func__, 7, "Allocating cell %s\n", cellType);
+			papCell *cell = papCellAlloc(chip, cellType, images->n); // The cell
+			cell->pixels = images;
 			cell->header = header;
-			cell->values = getCellData(camera, extName);
-			portionCell(cell, cell->images, cell->header);
+			psMetadata *cellData = getCellData(camera, cellType);
+			metadataCopy(cell->values, cellData);
+			psTrace(__func__, 7, "Portioning cell....\n");
+			portionCell(cell, cell->pixels, cell->header);
+			psTrace(__func__, 7, "Done.\n");
 		    }
 		}
@@ -344,5 +346,5 @@
 	} else if (strncmp(extType, "NONE", 4) == 0) {
 	    // No extensions; Content contains metadata, each entry is a chip with its component cells
-	    readExtension(&(fpa->images), &(fpa->header), fits, "PHU");
+	    readExtension(&(fpa->pixels), &(fpa->header), fits, "PHU");
 	    while (contentItem = psMetadataGetAndIncrement(contentsIter)) {
 		const char *chipName = contentItem->name; // The name of the chip
@@ -353,12 +355,13 @@
 		} else {
 		    const char *content = contentItem->data.V; // The content of the extension
-		    papChip *chip = papChipAlloc(fpa, "CHIP"); // The chip
+		    papChip *chip = papChipAlloc(fpa, content); // The chip
 		    psList *cellNames = papSplit(content, ", "); // Split the list of cells
 		    psListIterator *cellNamesIter = psListIteratorAlloc(cellNames, PS_LIST_HEAD, false);
 		    char *cellName = NULL; // Name of the cell
 		    while (cellName = psListGetAndIncrement(cellNamesIter)) {
-			papCell *cell = papCellAlloc(chip, "CELL", ((psArray*)fpa->images)->n); // The cell
-			cell->values = getCellData(camera, cellName);
-			portionCell(cell, fpa->images, fpa->header);
+			papCell *cell = papCellAlloc(chip, cellName, ((psArray*)fpa->pixels)->n); // The cell
+			psMetadata *cellData = getCellData(camera, cellName);
+			metadataCopy(cell->values, cellData);
+			portionCell(cell, fpa->pixels, fpa->header);
 		    }
 		    psFree(cellNamesIter);
@@ -380,5 +383,5 @@
 	if (strncmp(extType, "NONE", 4) == 0) {
 	    // There are no extensions --- only the PHU
-	    readExtension(&(fpa->images), &(fpa->header), fits, "PHU");
+	    readExtension(&(fpa->pixels), &(fpa->header), fits, "PHU");
 
 	    const char *contents = psMetadataLookupString(&mdStatus, camera, "CONTENTS");
@@ -392,7 +395,8 @@
 	    const char *cellName = NULL;
 	    while (cellName = psListGetAndIncrement(cellIter)) {
-		papCell *cell = papCellAlloc(chip, cellName, ((psArray*)fpa->images)->n); // The cell
-		cell->values = getCellData(camera, cellName);
-		portionCell(cell, fpa->images, fpa->header);
+		papCell *cell = papCellAlloc(chip, cellName, ((psArray*)fpa->pixels)->n); // The cell
+		psMetadata *cellData = getCellData(camera, cellName);
+		metadataCopy(cell->values, cellData);
+		portionCell(cell, fpa->pixels, fpa->header);
 	    }
 	    psFree(cellIter);
@@ -433,8 +437,9 @@
 		    readExtension(&images, &header, fits, extName);
 		    papCell *cell = papCellAlloc(chip, extName, images->n); // The cell
-		    cell->images = images;
+		    cell->pixels = images;
 		    cell->header = header;
-		    cell->values = getCellData(camera, cellType);
-		    portionCell(cell, cell->images, cell->header);
+		    psMetadata *cellData = getCellData(camera, cellType);
+		    metadataCopy(cell->values, cellData);
+		    portionCell(cell, cell->pixels, cell->header);
 		}
 	    } // Iterating through contents
@@ -455,10 +460,15 @@
     }
 
-    
-    // Print out the build tree
+    return fpa;
+}
+
+void pmFPAPrint(papFPA *fpa		// FPA to print
+    )
+{
+    // Print out the focal plane
     psMetadataIterator *fpaIter = psMetadataIteratorAlloc(fpa->chips, PS_LIST_HEAD, NULL); // Iterator for FPA
     psMetadataItem *fpaItem = NULL;	// Item from metadata
     psTrace("pmFPARead", 0, "FPA:\n");
-    if (fpa->images) {
+    if (fpa->pixels) {
 	psTrace("pmFPARead", 1, "---> FPA contains pixels.\n");
     }
@@ -469,5 +479,5 @@
 	    psTrace("pmFPARead", 1, "Chip: %s\n", fpaItem->name);
 	    papChip *chip = fpaItem->data.V; // The chip
-	    if (chip->images) {
+	    if (chip->pixels) {
 		psTrace("pmFPARead", 2, "---> Chip contains pixels.\n");
 	    }
@@ -481,5 +491,5 @@
 		    psTrace("pmFPARead", 2, "Cell: %s\n", chipItem->name);
 		    papCell *cell = chipItem->data.V; // The cell
-		    if (cell->images) {
+		    if (cell->pixels) {
 			psTrace("pmFPARead", 3, "---> Cell contains pixels.\n");
 		    }
@@ -494,4 +504,7 @@
 			  case PS_META_F32:
 			    psTrace("pmFPARead", 3, "%s: %f\n", cellItem->name, cellItem->data.F32);
+			    break;
+			  case PS_META_S32:
+			    psTrace("pmFPARead", 3, "%s: %d\n", cellItem->name, cellItem->data.S32);
 			    break;
 			  case PS_META_META:
@@ -527,6 +540,3 @@
     } // Iterating through FPA
     psFree(fpaIter);
-
-    return fpa;
-
-}
+}
Index: /trunk/archive/scripts/src/pmFPARead.h
===================================================================
--- /trunk/archive/scripts/src/pmFPARead.h	(revision 4385)
+++ /trunk/archive/scripts/src/pmFPARead.h	(revision 4386)
@@ -5,8 +5,12 @@
 
 // Read the contents of a FITS file (format specified by the camera configuration) into memory
-papFPA *pmFPARead(const psMetadata *camera, // The camera configuration
-		  psFits *fits // A FITS file
+papFPA *pmFPARead(psFits *fits, // A FITS file
+		  const psMetadata *camera, // The camera configuration
+		  psDB *db		// Database handle
     );
 
+// Print out the FPA
+void pmFPAPrint(papFPA *fpa		// FPA to print
+    );
 
 #endif
Index: /trunk/archive/scripts/src/psAdditionals.c
===================================================================
--- /trunk/archive/scripts/src/psAdditionals.c	(revision 4385)
+++ /trunk/archive/scripts/src/psAdditionals.c	(revision 4386)
@@ -47,5 +47,5 @@
 	}
     } else if (item->type != PS_META_STR) {
-	// The value at the key isn't metadata
+	// The value at the key isn't of the desired type
 	if (status) {
 	    *status = false;
@@ -76,5 +76,5 @@
 	}
     } else if (item->type != PS_META_CHIP) {
-	// The value at the key isn't metadata
+	// The value at the key isn't of the desired type
 	if (status) {
 	    *status = false;
@@ -105,5 +105,5 @@
 	}
     } else if (item->type != PS_META_CELL) {
-	// The value at the key isn't metadata
+	// The value at the key isn't of the desired type
 	if (status) {
 	    *status = false;
Index: /trunk/archive/scripts/src/test_pmFPARead.c
===================================================================
--- /trunk/archive/scripts/src/test_pmFPARead.c	(revision 4385)
+++ /trunk/archive/scripts/src/test_pmFPARead.c	(revision 4386)
@@ -25,8 +25,9 @@
 #endif
 
-    psTraceSetLevel("readMultipleRegions", 0);
-    psTraceSetLevel("portions", 0);
-    psTraceSetLevel("pmFPARead", 10);
-    
+    (void)psTraceSetLevel(".", 10);
+    (void)psTraceSetLevel("readMultipleRegions", 0);
+    (void)psTraceSetLevel("portions", 0);
+    (void)psTraceSetLevel("pmFPARead", 10);
+    (void)psTraceSetLevel("pmFPAfromHeader", 10);
 
     if (argc != 3) {
@@ -34,23 +35,28 @@
 	exit(EXIT_FAILURE);
     }
-    const char *configName = argv[1];
+    const char *cameraName = argv[1];
     const char *imageName = argv[2];
-	
+
     int badLines = 0;			// Number of bad lines in camera configuration
-
-    (void)psTraceSetLevel("pmFPAfromHeader", 10);
-
-    psMetadata *camera = psMetadataConfigParse(NULL, &badLines, configName, true); // Camera config
-
+    psMetadata *camera = psMetadataConfigParse(NULL, &badLines, cameraName, true); // Read camera config file
     if (badLines > 0) {
-	printf("%d bad lines encountered while reading %s\n", badLines, configName);
+	psLogMsg(__func__, PS_LOG_WARN, "%d bad lines encountered while reading camera configuration %s\n",
+		 badLines, cameraName);
     }
 
-    printf("Camera information:\n");
-    psMetadataPrint(camera, 0);
-   
     psFits *fits = psFitsAlloc(imageName);
-    papFPA *fpa = pmFPARead(camera, fits);
+    papFPA *fpa = pmFPARead(fits, camera, NULL);
+    (void)pmFPAPrint(fpa);
 
+    printf("Test: %d %d\n", psCellGetValueS32(fpa, "ccd15", "left", "CELL.XPARITY"),
+	   psCellGetValueS32(fpa, "ccd15", "right", "CELL.XPARITY"));
+    printf("Test: %d %d\n", psCellGetValueS32(fpa, "ccd15", "left", "CELL.YPARITY"),
+	   psCellGetValueS32(fpa, "ccd15", "right", "CELL.YPARITY"));
+    printf("Test: %d %d\n", psCellGetValueS32(fpa, "ccd15", "left", "CELL.YPARITY"),
+	   psCellGetValueS32(fpa, "ccd15", "right", "CELL.YPARITY"));
+
+//    (void)pmFPAPrint(fpa);
+
+    // Tidy up
     psMemCheckCorruption(true);
 
