Index: trunk/psModules/src/objects/pmSourceIO.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO.c	(revision 35577)
+++ trunk/psModules/src/objects/pmSourceIO.c	(revision 35610)
@@ -58,6 +58,6 @@
 #define BLANK_HEADERS "BLANK.HEADERS"   // Name of metadata in camera configuration containing header names
                                         // for putting values into a blank PHU
-static bool pmReadoutReadXSRC(pmFPAfile *file, char * exttype, psMetadata *hduHeader, psString xsrcname, psArray *sources, long *sourceIndex);
-static bool pmReadoutReadXFIT(pmFPAfile *file, char * exttype, psMetadata *hduHeader, psString xfitname, psArray *sources, long *sourceIndex);
+static bool pmReadoutReadXSRC(pmFPAfile *file, pmReadout *readout, char * exttype, psMetadata *hduHeader, psString xsrcname, psArray *sources, long *sourceIndex);
+static bool pmReadoutReadXFIT(pmFPAfile *file, pmReadout *readout, char * exttype, psMetadata *hduHeader, psString xfitname, psArray *sources, long *sourceIndex);
 static bool pmReadoutReadXRAD(pmFPAfile *file, pmReadout *readout, char * exttype, psMetadata *hduHeader, psString xfitname, psArray *sources, long *sourceIndex);
 
@@ -1093,5 +1093,5 @@
             if (XSRC_OUTPUT && xsrcname) {
 		// a cmf file may have an XSRC extension, but it is not required
-                if (!pmReadoutReadXSRC(file, exttype, hdu->header, xsrcname, sources, sourceIndex)) {
+                if (!pmReadoutReadXSRC(file, readout, exttype, hdu->header, xsrcname, sources, sourceIndex)) {
 		    // do anything?
                 }
@@ -1100,5 +1100,5 @@
             if (XFIT_OUTPUT && xfitname) {
 		// a cmf file may have an XFIT extension, but it is not required
-                if (!pmReadoutReadXFIT(file, exttype, hdu->header, xfitname, sources, sourceIndex)) {
+                if (!pmReadoutReadXFIT(file, readout, exttype, hdu->header, xfitname, sources, sourceIndex)) {
 		    // do anything?
                 }
@@ -1243,5 +1243,5 @@
 // XXX: We might be able to macroize this and reuse for the other types
 
-static bool pmReadoutReadXSRC(pmFPAfile *file, char *exttype, psMetadata *hduHeader, psString xsrcname, psArray *sources, long *sourceIndex) 
+static bool pmReadoutReadXSRC(pmFPAfile *file, pmReadout *readout, char *exttype, psMetadata *hduHeader, psString xsrcname, psArray *sources, long *sourceIndex) 
 {
     if (!psFitsMoveExtNameClean (file->fits, xsrcname)) {
@@ -1263,5 +1263,5 @@
 # define PM_SOURCES_READ_XSRC(NAME,TYPE)				\
     if (!strcmp (exttype, NAME)) {					\
-	status = pmSourcesRead_##TYPE##_XSRC(file->fits, hduHeader, sources, sourceIndex); \
+	status = pmSourcesRead_##TYPE##_XSRC(file->fits, readout, hduHeader, tableHeader, sources, sourceIndex); \
     }									
 
@@ -1282,5 +1282,5 @@
 }
 
-static bool pmReadoutReadXFIT(pmFPAfile *file, char *exttype, psMetadata *hduHeader, psString extname, psArray *sources, long *sourceIndex) 
+static bool pmReadoutReadXFIT(pmFPAfile *file, pmReadout *readout, char *exttype, psMetadata *hduHeader, psString extname, psArray *sources, long *sourceIndex) 
 {
     if (!psFitsMoveExtNameClean (file->fits, extname)) {
@@ -1302,5 +1302,5 @@
 # define PM_SOURCES_READ_XFIT(NAME,TYPE)				\
     if (!strcmp (exttype, NAME)) {					\
-	status = pmSourcesRead_##TYPE##_XFIT(file->fits, hduHeader, sources, sourceIndex); \
+	status = pmSourcesRead_##TYPE##_XFIT(file->fits, readout, hduHeader, tableHeader, sources, sourceIndex); \
     }									
 
@@ -1340,5 +1340,5 @@
 # define PM_SOURCES_READ_XRAD(NAME,TYPE)				\
     if (!strcmp (exttype, NAME)) {					\
-	status = pmSourcesRead_##TYPE##_XRAD(file->fits, readout, hduHeader, sources, sourceIndex); \
+	status = pmSourcesRead_##TYPE##_XRAD(file->fits, readout, hduHeader, tableHeader, sources, sourceIndex); \
     }									
 
Index: trunk/psModules/src/objects/pmSourceIO.h
===================================================================
--- trunk/psModules/src/objects/pmSourceIO.h	(revision 35577)
+++ trunk/psModules/src/objects/pmSourceIO.h	(revision 35610)
@@ -22,7 +22,7 @@
   bool pmSourcesWrite_##TYPE##_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe); \
   psArray *pmSourcesRead_##TYPE (psFits *fits, psMetadata *header); \
-  bool pmSourcesRead_##TYPE##_XSRC (psFits *fits, psMetadata *header, psArray *sources, long *index); \
-  bool pmSourcesRead_##TYPE##_XFIT (psFits *fits, psMetadata *header, psArray *sources, long *index); \
-  bool pmSourcesRead_##TYPE##_XRAD (psFits *fits, pmReadout *readout, psMetadata *header, psArray *sources, long *index);\
+  bool pmSourcesRead_##TYPE##_XSRC (psFits *fits, pmReadout *readout, psMetadata *header, psMetadata *tableHeader, psArray *sources, long *index); \
+  bool pmSourcesRead_##TYPE##_XFIT (psFits *fits, pmReadout *readout, psMetadata *header, psMetadata *tableHeader, psArray *sources, long *index); \
+  bool pmSourcesRead_##TYPE##_XRAD (psFits *fits, pmReadout *readout, psMetadata *header, psMetadata *tableHeader, psArray *sources, long *index);\
   
 // All of these functions need to use the same API, even if not all elements are used in a specific case
Index: trunk/psModules/src/objects/pmSourceIO_CMF.c.in
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF.c.in	(revision 35577)
+++ trunk/psModules/src/objects/pmSourceIO_CMF.c.in	(revision 35610)
@@ -457,6 +457,14 @@
     bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
 
-    psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
-    psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
+    // First look for radial bin definition in readout->analysis ...
+    psVector *radMin = psMetadataLookupPtr (&status, readout->analysis, "RADIAL.ANNULAR.BINS.LOWER");
+    psVector *radMax = psMetadataLookupPtr (&status, readout->analysis, "RADIAL.ANNULAR.BINS.UPPER");
+    if (!radMin) {
+        // .. if not found use the recipe values
+        radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
+        radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
+    }
+    psAssert(radMin != NULL, "unable to find RADIAL.ANNULAR.BINS.LOWER");
+    psAssert(radMax != NULL, "unable to find RADIAL.ANNULAR.BINS.LOWER");
     psAssert (radMin->n == radMax->n, "inconsistent annular bins");
 
@@ -610,5 +618,66 @@
 }
 
-bool pmSourcesRead_CMF_@CMFMODE@_XSRC(psFits *fits, psMetadata *hduHeader, psArray *sources, long *sourceIndex)
+static bool setRadialBinsInAnalysis(pmReadout *readout, psMetadata *tableHeader)
+{
+    if (!readout->analysis) {
+        readout->analysis = psMetadataAlloc();
+    }
+
+    bool status;
+    psVector *oldRMin = psMetadataLookupVector(&status, readout->analysis, "RADIAL.ANNULAR.BINS.LOWER");
+    psVector *oldRMax = psMetadataLookupVector(&status, readout->analysis, "RADIAL.ANNULAR.BINS.UPPER");
+
+    psVector *rMin = psVectorAllocEmpty(20, PS_TYPE_F32);
+    psVector *rMax = psVectorAllocEmpty(20, PS_TYPE_F32);
+
+    for (int i = 0; ; i++) {
+        char key [24];
+        sprintf(key, "RMIN_%02d", i);
+        psF32 rMinVal = psMetadataLookupF32(&status, tableHeader, key);
+        if (!status) {
+            break;
+        }
+        psVectorAppend(rMin, rMinVal);
+
+        sprintf(key, "RMAX_%02d", i);
+        psF32 rMaxVal = psMetadataLookupF32(&status, tableHeader, key);
+        if (!status) {
+            break;
+        }
+        psVectorAppend(rMax, rMaxVal);
+    }
+
+    if (rMin->n != rMax->n) {
+        psError(PS_ERR_UNKNOWN, true, "number of RMIN entries %ld does not equal number of RMAX entries %ld", 
+            rMin->n, rMax->n);
+        return false;
+    }
+
+    if (oldRMin) {
+        if (oldRMin->n != rMin->n) {
+            psError(PS_ERR_UNKNOWN, true, "number of RMIN entries in header: %ld does not equal number of RMAX entries in analysis: %ld", 
+                rMin->n, oldRMin->n);
+            return false;
+        }
+    } else {
+        psMetadataAddVector(readout->analysis, PS_LIST_TAIL, "RADIAL.ANNULAR.BINS.LOWER", PS_META_REPLACE, "", rMin);
+    }
+    psFree(rMin);
+
+    if (oldRMax) {
+        if (oldRMax->n != rMax->n) {
+            psError(PS_ERR_UNKNOWN, true, "number of RMIN entries in header: %ld does not equal number of RMAX entries in analysis: %ld", 
+                rMax->n, oldRMax->n);
+            return false;
+        }
+    } else {
+        psMetadataAddVector(readout->analysis, PS_LIST_TAIL, "RADIAL.ANNULAR.BINS.UPPER", PS_META_REPLACE, "", rMax);
+    }
+    psFree(rMax);
+
+    return true;
+}
+
+bool pmSourcesRead_CMF_@CMFMODE@_XSRC(psFits *fits, pmReadout *readout, psMetadata *hduHeader, psMetadata *tableHeader, psArray *sources, long *sourceIndex)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -626,4 +695,9 @@
     float exptime = psMetadataLookupF32(&status, hduHeader, "EXPTIME");
     float magOffset = zeropt + 2.5*log10(exptime);
+
+    if (!setRadialBinsInAnalysis(readout, tableHeader)) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to save radial bins in analysis");
+        return false;
+    }
 
     for (long i = 0; i < numSources; i++) {
@@ -920,5 +994,5 @@
 }
 
-bool pmSourcesRead_CMF_@CMFMODE@_XFIT(psFits *fits, psMetadata *hduHeader, psArray *sources, long *sourceIndex)
+bool pmSourcesRead_CMF_@CMFMODE@_XFIT(psFits *fits, pmReadout *readout, psMetadata *hduHeader, psMetadata *tableHeader, psArray *sources, long *sourceIndex)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -1043,8 +1117,14 @@
 
     // we use this just to define the output vectors (which must be present for all objects)
-    psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
-    psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
+    // First look for radial bin definition in readout->analysis ...
+    psVector *radMin = psMetadataLookupPtr (&status, readout->analysis, "RADIAL.ANNULAR.BINS.LOWER");
+    psVector *radMax = psMetadataLookupPtr (&status, readout->analysis, "RADIAL.ANNULAR.BINS.UPPER");
+    if (!radMin) {
+        // .. if not found use the recipe values
+        radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
+        radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
+    }
+    psAssert (radMin, "this must have been defined and tested earlier!");
     psAssert (radMax, "this must have been defined and tested earlier!");
-    psAssert (radMax->n, "this must have been defined and tested earlier!");
     psAssert (radMin->n == radMax->n, "inconsistent annular bins");
 
@@ -1167,5 +1247,5 @@
 }
 
-bool pmSourcesRead_CMF_@CMFMODE@_XRAD(psFits *fits, pmReadout *readout, psMetadata *hduHeader, psArray *sources, long *sourceIndex)
+bool pmSourcesRead_CMF_@CMFMODE@_XRAD(psFits *fits, pmReadout *readout, psMetadata *hduHeader, psMetadata *tableHeader, psArray *sources, long *sourceIndex)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -1176,4 +1256,9 @@
     if (numSources == 0) {
         psError(psErrorCodeLast(), false, "XRAD Table contains no entries\n");
+        return false;
+    }
+
+    if (!setRadialBinsInAnalysis(readout, tableHeader)) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to save radial bins in analysis");
         return false;
     }
