Index: /trunk/psModules/src/camera/pmFPAMaskWeight.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAMaskWeight.c	(revision 20094)
+++ /trunk/psModules/src/camera/pmFPAMaskWeight.c	(revision 20095)
@@ -212,4 +212,8 @@
     if (!mdok || isnan(readnoise)) {
         psError(PS_ERR_IO, true, "CELL.READNOISE is not set --- unable to set weight.\n");
+        return false;
+    }
+    if (psMetadataLookup(cell->concepts, "CELL.READNOISE.UPDATE")) {
+        psError(PS_ERR_IO, true, "CELL.READNOISE has not yet been updated for the gain");
         return false;
     }
Index: /trunk/psModules/src/concepts/pmConcepts.c
===================================================================
--- /trunk/psModules/src/concepts/pmConcepts.c	(revision 20094)
+++ /trunk/psModules/src/concepts/pmConcepts.c	(revision 20095)
@@ -598,5 +598,5 @@
         // Install the standard concepts
         conceptRegisterF32("CELL.GAIN", "CCD gain (e/count)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
-        conceptRegisterF32("CELL.READNOISE", "CCD read noise (e)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
+        conceptRegisterF32("CELL.READNOISE", "CCD read noise (e)", p_pmConceptParse_CELL_READNOISE, p_pmConceptFormat_CELL_READNOISE, true, PM_FPA_LEVEL_CELL);
         conceptRegisterF32("CELL.SATURATION", "Saturation level (counts)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
         conceptRegisterF32("CELL.BAD", "Bad level (counts)", NULL, NULL, true, PM_FPA_LEVEL_CELL);
Index: /trunk/psModules/src/concepts/pmConceptsStandard.c
===================================================================
--- /trunk/psModules/src/concepts/pmConceptsStandard.c	(revision 20094)
+++ /trunk/psModules/src/concepts/pmConceptsStandard.c	(revision 20095)
@@ -46,4 +46,87 @@
     return NAN;
 }
+
+
+psMetadataItem *p_pmConceptParse_CELL_READNOISE(const psMetadataItem *concept,
+                                                const psMetadataItem *pattern,
+                                                pmConceptSource source,
+                                                const psMetadata *cameraFormat,
+                                                const pmFPA *fpa,
+                                                const pmChip *chip,
+                                                const pmCell *cell)
+{
+    assert(concept);
+    assert(pattern);
+    assert(cameraFormat);
+    assert(cell);
+
+    float rn = psMetadataItemParseF32(concept); // Read noise
+    if (isfinite(rn)) {
+        bool mdok;                      // Status of MD lookup
+        psMetadata *formats = psMetadataLookupMetadata(&mdok, cameraFormat, "FORMATS");
+        if (mdok && formats) {
+            psString format = psMetadataLookupStr(&mdok, formats, pattern->name);
+            if (mdok && strlen(format) > 0) {
+                if (strcasecmp(format, "ADU") == 0) {
+                    float gain = psMetadataLookupF32(NULL, cell->concepts, "CELL.GAIN"); // Gain (e/ADU)
+                    if (!isfinite(gain)) {
+                        // Will need to update the readnoise once the gain is available
+                        psMetadataAddBool(cell->concepts, PS_LIST_TAIL, "CELL.READNOISE.UPDATE",
+                                          PS_META_REPLACE,
+                                          "Need to update CELL.READNOISE when the gain is available.", true);
+                    } else {
+                        rn *= gain;
+                    }
+                } else {
+                    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unrecognised format for CELL.READNOISE: %s",
+                            format);
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    return psMetadataItemAllocF32(pattern->name, pattern->comment, rn);
+}
+
+psMetadataItem *p_pmConceptFormat_CELL_READNOISE(const psMetadataItem *concept,
+                                                 pmConceptSource source,
+                                                 const psMetadata *cameraFormat,
+                                                 const pmFPA *fpa,
+                                                 const pmChip *chip,
+                                                 const pmCell *cell)
+{
+    assert(concept);
+    assert(cell);
+    assert(concept->type == PS_TYPE_F32);
+
+    float rn = concept->data.F32;       // Read noise
+    if (isfinite(rn)) {
+        bool mdok;                      // Status of MD lookup
+        psMetadata *formats = psMetadataLookupMetadata(&mdok, cameraFormat, "FORMATS");
+        if (mdok && formats) {
+            psString format = psMetadataLookupStr(&mdok, formats, concept->name);
+            if (mdok && strlen(format) > 0) {
+                if (strcasecmp(format, "ADU") == 0) {
+                    if (!psMetadataLookup(cell->concepts, "CELL.READNOISE.UPDATE")) {
+                        // Gain correction has been applied, so we need to reverse it to format
+                        float gain = psMetadataLookupF32(NULL, cell->concepts, "CELL.GAIN"); // Gain (e/ADU)
+                        if (!isfinite(gain)) {
+                            psWarning("CELL.READNOISE is supposed to be in ADU, but CELL.GAIN isn't set");
+                        }
+                        rn /= gain;
+                    }
+                } else {
+                    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unrecognised format for CELL.READNOISE: %s",
+                            format);
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    return psMetadataItemAllocF32(concept->name, concept->comment, rn);
+}
+
 
 // TELTEMPS : parse a list of the form 'X1 X2 X3 X4 X5 ...' : for now use median
Index: /trunk/psModules/src/concepts/pmConceptsStandard.h
===================================================================
--- /trunk/psModules/src/concepts/pmConceptsStandard.h	(revision 20094)
+++ /trunk/psModules/src/concepts/pmConceptsStandard.h	(revision 20095)
@@ -4,6 +4,6 @@
  * @author Paul Price, IfA
  *
- * @version $Revision: 1.12 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-12-08 03:15:37 $
+ * @version $Revision: 1.13 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2008-10-13 21:20:36 $
  * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -19,12 +19,29 @@
     );
 
+/// Parse the CELL.READNOISE concept to do ADU->e correction if required
+psMetadataItem *p_pmConceptParse_CELL_READNOISE(const psMetadataItem *concept,
+                                                const psMetadataItem *pattern,
+                                                pmConceptSource source,
+                                                const psMetadata *cameraFormat,
+                                                const pmFPA *fpa,
+                                                const pmChip *chip,
+                                                const pmCell *cell);
+
+/// Format the CELL.READNOISE concept to do e->ADU correction if required
+psMetadataItem *p_pmConceptFormat_CELL_READNOISE(const psMetadataItem *concept,
+                                                 pmConceptSource source,
+                                                 const psMetadata *cameraFormat,
+                                                 const pmFPA *fpa,
+                                                 const pmChip *chip,
+                                                 const pmCell *cell);
+
 // Parse the TELTEMPS concept : parse a list of the form 'X1 X2 X3 X4 X5 ...' : for now use median
 psMetadataItem *p_pmConceptParse_TELTEMPS(const psMetadataItem *concept,
-					  const psMetadataItem *pattern,
-					  pmConceptSource source,
-					  const psMetadata *cameraFormat,
-					  const pmFPA *fpa,
-					  const pmChip *chip,
-					  const pmCell *cell);
+                                          const psMetadataItem *pattern,
+                                          pmConceptSource source,
+                                          const psMetadata *cameraFormat,
+                                          const pmFPA *fpa,
+                                          const pmChip *chip,
+                                          const pmCell *cell);
 
 /// Parse the FPA.FILTER concept to apply a lookup table
Index: /trunk/psModules/src/concepts/pmConceptsUpdate.c
===================================================================
--- /trunk/psModules/src/concepts/pmConceptsUpdate.c	(revision 20094)
+++ /trunk/psModules/src/concepts/pmConceptsUpdate.c	(revision 20095)
@@ -25,64 +25,75 @@
         // Check for cell concepts updates
 
-	bool xStatus, yStatus; // Status of MD lookups
-	psImageBinning *binning = psImageBinningAlloc();
-	binning->nXbin = psMetadataLookupS32(&xStatus, cell->concepts, "CELL.XBIN");
-	binning->nYbin = psMetadataLookupS32(&yStatus, cell->concepts, "CELL.YBIN");
-	if (!xStatus || !yStatus) {
-	    // XXX should this be an error condition?
-	    psFree (binning);
-	    return true;
-	}
-	if (!binning->nXbin || !binning->nXbin) {
-	    // XXX should this be an error condition?
-	    psFree (binning);
-	    return true;
-	}
+        // CELL.READNOISE needs to be updated if specified in ADU
+        if (psMetadataLookup(cell->concepts, "CELL.READNOISE.UPDATE")) {
+            float gain = psMetadataLookupF32(NULL, cell->concepts, "CELL.GAIN"); // Gain for cell
+            if (isfinite(gain)) {
+                psMetadataItem *rn = psMetadataLookup(cell->concepts, "CELL.READNOISE"); // Read noise
+                psAssert(rn && rn->type == PS_TYPE_F32, "Should be of the correct type");
+                rn->data.F32 *= gain;
+                psMetadataRemoveKey(cell->concepts, "CELL.READNOISE.UPDATE");
+            }
+        }
+
+        bool xStatus, yStatus; // Status of MD lookups
+        psImageBinning *binning = psImageBinningAlloc();
+        binning->nXbin = psMetadataLookupS32(&xStatus, cell->concepts, "CELL.XBIN");
+        binning->nYbin = psMetadataLookupS32(&yStatus, cell->concepts, "CELL.YBIN");
+        if (!xStatus || !yStatus) {
+            // XXX should this be an error condition?
+            psFree (binning);
+            return true;
+        }
+        if (!binning->nXbin || !binning->nXbin) {
+            // XXX should this be an error condition?
+            psFree (binning);
+            return true;
+        }
 
         // CELL.TRIMSEC needs to be updated for the binning
         if (psMetadataLookup(cell->concepts, "CELL.TRIMSEC.UPDATE")) {
-	    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC"); // Trim section
-	    *trimsec = psImageBinningSetRuffRegion (binning, *trimsec);
-	    // force integer pixels : truncate x0, roundup x1:
-	    trimsec->x0 = (int)trimsec->x0;
-	    if (trimsec->x1 > (int)trimsec->x1) {
-		trimsec->x1 = (int)trimsec->x1 + 1;
-	    } else {
-		trimsec->x1 = (int)trimsec->x1;
-	    }		
-	    trimsec->y0 = (int)trimsec->y0;
-	    if (trimsec->y1 > (int)trimsec->y1) {
-		trimsec->y1 = (int)trimsec->y1 + 1;
-	    } else {
-		trimsec->y1 = (int)trimsec->y1;
-	    }		
-	    psMetadataRemoveKey(cell->concepts, "CELL.TRIMSEC.UPDATE");
+            psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC"); // Trim section
+            *trimsec = psImageBinningSetRuffRegion (binning, *trimsec);
+            // force integer pixels : truncate x0, roundup x1:
+            trimsec->x0 = (int)trimsec->x0;
+            if (trimsec->x1 > (int)trimsec->x1) {
+                trimsec->x1 = (int)trimsec->x1 + 1;
+            } else {
+                trimsec->x1 = (int)trimsec->x1;
+            }
+            trimsec->y0 = (int)trimsec->y0;
+            if (trimsec->y1 > (int)trimsec->y1) {
+                trimsec->y1 = (int)trimsec->y1 + 1;
+            } else {
+                trimsec->y1 = (int)trimsec->y1;
+            }
+            psMetadataRemoveKey(cell->concepts, "CELL.TRIMSEC.UPDATE");
         }
 
         // CELL.BIASSEC needs to be updated for the binning
         if (psMetadataLookup(cell->concepts, "CELL.BIASSEC.UPDATE")) {
-	    psList *biassecs = psMetadataLookupPtr(NULL, cell->concepts, "CELL.BIASSEC"); // Bias sections
-	    psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, true); // Iterator
-	    psRegion *biassec; // Bias region, from iteration
-	    while ((biassec = psListGetAndIncrement(biassecsIter))) {
-		*biassec = psImageBinningSetRuffRegion (binning, *biassec);
-		// force integer pixels : truncate x0, roundup x1:
-		biassec->x0 = (int)biassec->x0;
-		if (biassec->x1 > (int)biassec->x1) {
-		    biassec->x1 = (int)biassec->x1 + 1;
-		} else {
-		    biassec->x1 = (int)biassec->x1;
-		}		
-		biassec->y0 = (int)biassec->y0;
-		if (biassec->y1 > (int)biassec->y1) {
-		    biassec->y1 = (int)biassec->y1 + 1;
-		} else {
-		    biassec->y1 = (int)biassec->y1;
-		}		
-	    }
-	    psFree(biassecsIter);
-	    psMetadataRemoveKey(cell->concepts, "CELL.BIASSEC.UPDATE");
+            psList *biassecs = psMetadataLookupPtr(NULL, cell->concepts, "CELL.BIASSEC"); // Bias sections
+            psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, true); // Iterator
+            psRegion *biassec; // Bias region, from iteration
+            while ((biassec = psListGetAndIncrement(biassecsIter))) {
+                *biassec = psImageBinningSetRuffRegion (binning, *biassec);
+                // force integer pixels : truncate x0, roundup x1:
+                biassec->x0 = (int)biassec->x0;
+                if (biassec->x1 > (int)biassec->x1) {
+                    biassec->x1 = (int)biassec->x1 + 1;
+                } else {
+                    biassec->x1 = (int)biassec->x1;
+                }
+                biassec->y0 = (int)biassec->y0;
+                if (biassec->y1 > (int)biassec->y1) {
+                    biassec->y1 = (int)biassec->y1 + 1;
+                } else {
+                    biassec->y1 = (int)biassec->y1;
+                }
+            }
+            psFree(biassecsIter);
+            psMetadataRemoveKey(cell->concepts, "CELL.BIASSEC.UPDATE");
         }
-	psFree (binning);
+        psFree (binning);
     }
 
