Index: trunk/psModules/src/objects/pmFootprint.c
===================================================================
--- trunk/psModules/src/objects/pmFootprint.c	(revision 30049)
+++ trunk/psModules/src/objects/pmFootprint.c	(revision 30621)
@@ -255,3 +255,14 @@
 }
 
+// create a new footprint with the same span set as the input footprint
+pmFootprint *pmFootprintCopyData(pmFootprint *inFoot, psImage *image) {
+
+    pmFootprint *outFoot = pmFootprintAlloc(inFoot->nspans, image);
+    for (int i = 0; i < inFoot->nspans; i++) {
+	pmSpan *span = inFoot->spans->data[i];
+	pmFootprintAddSpan(outFoot, span->y, span->x0, span->x1);
+    }
+    return outFoot;
+}
+
 /************************************************************************************************************/
Index: trunk/psModules/src/objects/pmFootprint.h
===================================================================
--- trunk/psModules/src/objects/pmFootprint.h	(revision 30049)
+++ trunk/psModules/src/objects/pmFootprint.h	(revision 30621)
@@ -27,4 +27,6 @@
 
 bool pmFootprintAllocEmptySpans (pmFootprint *footprint, int nSpans);
+
+pmFootprint *pmFootprintCopyData(pmFootprint *inFoot, psImage *image);
 
 pmFootprint *pmFootprintNormalize(pmFootprint *fp);
Index: trunk/psModules/src/objects/pmFootprintAssignPeaks.c
===================================================================
--- trunk/psModules/src/objects/pmFootprintAssignPeaks.c	(revision 30049)
+++ trunk/psModules/src/objects/pmFootprintAssignPeaks.c	(revision 30621)
@@ -24,5 +24,5 @@
 /*
  * Given a psArray of pmFootprints and another of pmPeaks, assign the peaks to the
- * footprints in which that fall; if they _don't_ fall in a footprint, add a suitable
+ * footprints in which they fall; if they _don't_ fall in a footprint, add a suitable
  * one to the list.
  */
@@ -83,8 +83,18 @@
 
 	// XXX are we allowed to have peak-less footprints??
-	if (!fp->peaks->n) continue;
+	if (fp->peaks->n == 0) continue;
+	if (fp->peaks->n == 1) continue;
 
         fp->peaks = psArraySort(fp->peaks, pmPeakSortBySN);
 
+	// XXX check for an assert on duplicates (I don't think they can happen, but
+	// let's double check for now)
+
+	for (int j = 1; j < fp->peaks->n; j++) {
+	    psAssert (fp->peaks->data[j] != fp->peaks->data[j-1], "duplicate peak!");
+	}
+	continue;
+
+	// XXX WHY am I culling duplicates?  how can there be duplicates?
 	// XXX EAM : the algorithm below should be much faster than using psArrayRemove if
 	// the number of peaks in the footprint is large, or if there are no duplicates.
@@ -93,5 +103,5 @@
 
 	// track the number of good peaks in the footprint
-	int nGood = 1;
+	int lastGood = 0;
 
 	// check for duplicates
@@ -100,12 +110,13 @@
 	// (if sorted list has A, B, A, B ...)
 	for (int j = 1; j < fp->peaks->n; j++) { 
-	    if (fp->peaks->data[j] == fp->peaks->data[nGood]) {
+	    if (fp->peaks->data[j] == fp->peaks->data[lastGood]) {
 		// everything on the array has its own mem reference; free and drop this one
 		psFree (fp->peaks->data[j]);
 		fp->peaks->data[j] = NULL;
 	    } else {
-		nGood ++;
+		lastGood ++;
 	    }
 	}
+	int nGood = lastGood + 1;
 
 	// no deleted peaks, go to next footprint
Index: trunk/psModules/src/objects/pmFootprintCullPeaks.c
===================================================================
--- trunk/psModules/src/objects/pmFootprintCullPeaks.c	(revision 30049)
+++ trunk/psModules/src/objects/pmFootprintCullPeaks.c	(revision 30621)
@@ -28,5 +28,5 @@
   * Examine the peaks in a pmFootprint, and throw away the ones that are not sufficiently
   * isolated.  More precisely, for each peak find the highest coll that you'd have to traverse
-  * to reach a still higher peak --- and if that coll's more than nsigma DN below your
+  * to reach a still higher peak --- and if that coll's more (less?) than nsigma DN below your
   * starting point, discard the peak.
   */
@@ -99,5 +99,5 @@
         float threshold = flux - nsigma_delta*stdev_pad;
 
-        if (isnan(threshold) || threshold < min_threshold) {
+        if (isnan(threshold)) {
             // min_threshold is assumed to be below the detection threshold,
             // so all the peaks are pmFootprint, and this isn't the brightest
@@ -109,4 +109,8 @@
             threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON;
         }
+
+	if (threshold < min_threshold) {
+	    threshold = min_threshold;
+	}
 
 	// init peakFootprint here?
Index: trunk/psModules/src/objects/pmModel.c
===================================================================
--- trunk/psModules/src/objects/pmModel.c	(revision 30049)
+++ trunk/psModules/src/objects/pmModel.c	(revision 30621)
@@ -70,5 +70,6 @@
     tmp->fitRadius = 0;
     tmp->flags = PM_MODEL_STATUS_NONE;
-    tmp->residuals = NULL;              // XXX should the model own this memory?
+    tmp->residuals = NULL;              // do not free: the model does not own this memory
+    tmp->isPCM = false;
 
     psS32 Nparams = pmModelClassParameterCount(type);
@@ -108,6 +109,7 @@
 pmModel *pmModelCopy (pmModel *model)
 {
-    PS_ASSERT_PTR_NON_NULL(model, NULL);
-
+    if (model == NULL) {
+	return NULL;
+    }
     pmModel *new = pmModelAlloc (model->type);
 
Index: trunk/psModules/src/objects/pmModel.h
===================================================================
--- trunk/psModules/src/objects/pmModel.h	(revision 30049)
+++ trunk/psModules/src/objects/pmModel.h	(revision 30621)
@@ -43,4 +43,5 @@
     float fitRadius;                    ///< fit radius actually used
     pmResiduals *residuals;             ///< normalized PSF residuals
+    bool isPCM;				///< is this model fitted with PSF-convolution?
 
     // functions for this model which depend on the model class
Index: trunk/psModules/src/objects/pmPCMdata.h
===================================================================
--- trunk/psModules/src/objects/pmPCMdata.h	(revision 30049)
+++ trunk/psModules/src/objects/pmPCMdata.h	(revision 30621)
@@ -83,4 +83,6 @@
     pmPCMdata *pcm);
 
+psKernel *pmPCMkernelFromPSF (pmSource *source, int nPix);
+
 bool pmSourceModelGuessPCM (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal);
 
Index: trunk/psModules/src/objects/pmPSFtry.c
===================================================================
--- trunk/psModules/src/objects/pmPSFtry.c	(revision 30049)
+++ trunk/psModules/src/objects/pmPSFtry.c	(revision 30621)
@@ -84,5 +84,13 @@
 
     for (int i = 0; i < sources->n; i++) {
-        test->sources->data[i] = pmSourceCopy (sources->data[i]);
+	pmSource *sourceOld = sources->data[i];
+	pmSource *sourceNew = pmSourceCopy (sourceOld);
+
+	// save a reference so we can get back to the original
+	// this is specifically used in psphotChooosePSF to unflag the candidate PSF sources
+	// which were not actually used to generate a PSF model
+	sourceNew->parent = sourceOld; 
+
+        test->sources->data[i] = sourceNew;
     }
 
Index: trunk/psModules/src/objects/pmPSFtryFitEXT.c
===================================================================
--- trunk/psModules/src/objects/pmPSFtryFitEXT.c	(revision 30049)
+++ trunk/psModules/src/objects/pmPSFtryFitEXT.c	(revision 30621)
@@ -65,7 +65,9 @@
         if (!source->moments) {
             psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no moments\n", i, source->peak->x, source->peak->y);
             continue;
         }
         if (!source->moments->nPixels) {
+            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no pixels\n", i, source->peak->x, source->peak->y);
             psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
             continue;
@@ -74,6 +76,6 @@
         source->modelEXT = pmSourceModelGuess (source, options->type);
         if (source->modelEXT == NULL) {
+            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
             psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
             continue;
         }
@@ -91,6 +93,6 @@
         // exclude the poor fits
         if (!status) {
+            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
             psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
             continue;
         }
Index: trunk/psModules/src/objects/pmPSFtryFitPSF.c
===================================================================
--- trunk/psModules/src/objects/pmPSFtryFitPSF.c	(revision 30049)
+++ trunk/psModules/src/objects/pmPSFtryFitPSF.c	(revision 30621)
@@ -81,4 +81,5 @@
         if (source->modelPSF == NULL) {
             psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_MODEL;
+            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : bad PSF fit\n", i, source->peak->x, source->peak->y);
             continue;
         }
Index: trunk/psModules/src/objects/pmPSFtryModel.c
===================================================================
--- trunk/psModules/src/objects/pmPSFtryModel.c	(revision 30049)
+++ trunk/psModules/src/objects/pmPSFtryModel.c	(revision 30621)
@@ -52,4 +52,23 @@
 // mask values indicate the reason the source was rejected:
 
+// XXX some test code (delete eventually)
+// bool countMaskedSources(pmPSFtry *try, char *msg) {
+// 
+//     int N1 = 0;
+//     int N2 = 0;
+//     for (int i = 0; i < try->sources->n; i++) {
+//         pmSource *source = try->sources->data[i];
+//     	// fprintf (stderr, "%llx : %d\n", (long long int) source, (source->mode & PM_SOURCE_MODE_PSFSTAR));
+//     	if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
+//     	    N1 ++;
+//         }
+//     	if (try->mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
+//     	    N2 ++;
+//         }
+//     }
+//     fprintf (stderr, "%s : masked: %d or %d of %ld\n", msg, N1, N2, try->sources->n);
+//     return true;
+// }
+
 // generate a pmPSFtry with a copy of the test PSF sources
 pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal)
@@ -203,4 +222,5 @@
             chisq->data.F32[i] = 0.0;
             mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;
+            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : no PSF model\n", i, source->peak->x, source->peak->y);
         } else {
             flux->data.F32[i] = source->modelPSF->params->data.F32[PM_PAR_I0];
Index: trunk/psModules/src/objects/pmSource.c
===================================================================
--- trunk/psModules/src/objects/pmSource.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSource.c	(revision 30621)
@@ -61,5 +61,5 @@
     psFree(tmp->moments);
     psFree(tmp->diffStats);
-    psFree(tmp->radial);
+    psFree(tmp->radialAper);
     psFree(tmp->blends);
     psTrace("psModules.objects", 10, "---- end ----\n");
@@ -126,5 +126,6 @@
     source->extpars = NULL;
     source->diffStats = NULL;
-    source->radial = NULL;
+    source->radialAper = NULL;
+    source->parent = NULL;
 
     source->region = psRegionSet(NAN, NAN, NAN, NAN);
@@ -159,5 +160,5 @@
 affecting the original.  This Copy can be used to allow multiple fit attempts on the same
 object.  The pixels, variance, and mask arrays all point to the same original subarrays.  The
-peak and moments point at the original values.
+peak and moments point at the original values.  The models, blends, and XXX are NOT copied
 *****************************************************************************/
 pmSource *pmSourceCopy(pmSource *in)
@@ -167,7 +168,4 @@
     }
     pmSource *source = pmSourceAlloc ();
-
-    // keep the original ID so we can find map back to the original
-    P_PM_SOURCE_SET_ID(source, in->id);
 
     // peak has the same values as the original
@@ -203,50 +201,4 @@
 }
 
-/******************************************************************************
-pmSourceCopyData(): this creates a new, duplicate source with the same parameters as the
-original (but is actually a new source at the same location)
-*****************************************************************************/
-pmSource *pmSourceCopyData(pmSource *in)
-{
-    if (in == NULL) {
-        return(NULL);
-    }
-    // this copy is used to allow multiple fit attempts on the
-    // same object.  the pixels, variance, and mask arrays all point to
-    // the same original subarrays.  the peak and moments point at
-    // the original values.
-    pmSource *source = pmSourceAlloc ();
-
-    // this is actually the same peak as the original, is this the correct way to handle this?
-    if (in->peak != NULL) {
-        source->peak = pmPeakAlloc (in->peak->x, in->peak->y, in->peak->value, in->peak->type);
-        source->peak->xf = in->peak->xf;
-        source->peak->yf = in->peak->yf;
-        source->peak->flux = in->peak->flux;
-        source->peak->SN = in->peak->SN;
-    }
-
-    // copy the values in the moments structure
-    if (in->moments != NULL) {
-        source->moments  =  pmMomentsAlloc();
-        *source->moments = *in->moments;
-    }
-
-    // These images are all views to the parent.
-    // We want a new view, but pointing at the same pixels.
-    source->pixels   = psImageCopyView(NULL, in->pixels);
-    source->variance   = psImageCopyView(NULL, in->variance);
-    source->maskView = in->maskView ? psImageCopyView(NULL, in->maskView) : NULL;
-
-    // the maskObj is a unique mask array; create a new mask image
-    source->maskObj = in->maskObj ? psImageCopy (NULL, in->maskObj, PS_TYPE_IMAGE_MASK) : NULL;
-
-    source->type = in->type;
-    source->mode = in->mode;
-    source->imageID = in->imageID;
-
-    return(source);
-}
-
 // x,y are defined in the parent image coords of readout->image
 bool pmSourceDefinePixels(pmSource *mySource,
@@ -300,4 +252,5 @@
     newRegion = psRegionForImage (readout->image, newRegion);
 
+    // re-define if required by region or absence of pixels
     extend = false;
     extend |= (int)(newRegion.x0) < (int)(mySource->region.x0);
@@ -335,4 +288,37 @@
     }
     return extend;
+}
+
+bool pmSourceRedefinePixelsByRegion(pmSource *mySource,
+				    const pmReadout *readout,
+				    psRegion newRegion)
+{
+    PS_ASSERT_PTR_NON_NULL(mySource, false);
+    PS_ASSERT_PTR_NON_NULL(readout, false);
+    PS_ASSERT_PTR_NON_NULL(readout->image, false);
+
+    // re-create the subimage
+    psFree (mySource->pixels);
+    psFree (mySource->variance);
+    psFree (mySource->maskView);
+	
+    mySource->pixels   = psImageSubset(readout->image,    newRegion);
+    mySource->variance = psImageSubset(readout->variance, newRegion);
+    mySource->maskView = psImageSubset(readout->mask,     newRegion);
+    mySource->region   = newRegion;
+
+    // re-copy the main mask pixels.  NOTE: the user will need to reset the object mask
+    // pixels (eg, with psImageKeepCircle)
+    mySource->maskObj = psImageCopy (mySource->maskObj, mySource->maskView, PS_TYPE_IMAGE_MASK);
+
+    // drop the old modelFlux pixels and force the user to re-create
+    psFree (mySource->modelFlux);
+    mySource->modelFlux = NULL;
+
+    // drop the old psfImage pixels and force the user to re-create
+    psFree (mySource->psfImage);
+    mySource->psfImage = NULL;
+
+    return true;
 }
 
@@ -675,5 +661,5 @@
             if ((source->moments->SN > PSF_SN_LIM) && (radius < PSF_CLUMP_NSIGMA)) {
                 source->type = PM_SOURCE_TYPE_STAR;
-                source->mode |= PM_SOURCE_MODE_PSFSTAR;
+                source->tmpFlags |= PM_SOURCE_TMPF_CANDIDATE_PSFSTAR;
                 Npsf ++;
                 continue;
@@ -934,6 +920,5 @@
 }
 
-// construct a realization of the source model
-// XXX this function should optionally save an existing psf image from modelFlux
+// construct a realization of the PSF model at the location of this source
 bool pmSourceCachePSF (pmSource *source, psImageMaskType maskVal) {
     PS_ASSERT_PTR_NON_NULL(source, false);
@@ -1020,12 +1005,10 @@
     }
 
-    if (!addNoise) {
-	if (add) {
-	    status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
-	    source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
-	} else {
-	    status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
-	    source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
-	}
+    if (add) {
+	status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
+	source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
+    } else {
+	status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
+	source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     }
 
Index: trunk/psModules/src/objects/pmSource.h
===================================================================
--- trunk/psModules/src/objects/pmSource.h	(revision 30049)
+++ trunk/psModules/src/objects/pmSource.h	(revision 30621)
@@ -35,4 +35,5 @@
     PM_SOURCE_TMPF_SIZE_CR_CANDIDATE = 0x0008,
     PM_SOURCE_TMPF_MOMENTS_MEASURED  = 0x0010,
+    PM_SOURCE_TMPF_CANDIDATE_PSFSTAR = 0x0020,
 } pmSourceTmpF;
 
@@ -42,4 +43,16 @@
  *  simplest measurement of a source is the location and flux of the peak pixel
  *  associated with the source:
+ *
+ * a pmSource is the information about a (possible) blob of flux in a specific image.  A source
+ * may represent an insignificant or undetected source.  There may be multiple representations
+ * of an image (eg, alternate smoothed copies); sources on alternate images may have a pointer
+ * to the version on the primary image (source->parent).  A set of sources on different, but
+ * related images (eg, multiple exposures or different filters) which (may) represent the same
+ * astronomical object are grouped together with the pmPhotObj type (set pmPhotObj.h).
+ * 
+ * A single source may be fitted with multiple models (not at the same time!).  The PSF model
+ * fit is a fit of the position (optionally) and the flux to the PSF model at the location of
+ * the source.  Alternate model fits are extended source models. The best model fit is used to
+ * subtract the object from the image.
  *
  *  XXX do I have to re-organize this (again!) to allow an arbitrary set of extended model fits??
@@ -54,9 +67,9 @@
     pmPeak  *peak;                      ///< Description of peak pixel.
     psImage *pixels;                    ///< Rectangular region including object pixels.
-    psImage *variance;                    ///< Image variance.
+    psImage *variance;			///< Image variance.
     psImage *maskObj;                   ///< unique mask for this object which marks included pixels associated with objects.
     psImage *maskView;                  ///< view into global image mask for this object region
     psImage *modelFlux;                 ///< cached copy of the best model for this source
-    psImage *psfImage;                   ///< cached copy of the psf model for this source
+    psImage *psfImage;			///< cached copy of the psf model for this source
     pmMoments *moments;                 ///< Basic moments measured for the object.
     pmModel *modelPSF;                  ///< PSF Model fit (parameters and type)
@@ -89,5 +102,6 @@
     pmSourceExtendedPars *extpars;      ///< extended source parameters
     pmSourceDiffStats *diffStats;       ///< extra parameters for difference detections
-    pmSourceRadialApertures *radial;	///< radial flux in circular apertures
+    psArray *radialAper;		///< radial flux in circular apertures
+    pmSource *parent;			///< reference to the master source from which this is derived
     int imageID;
 };
@@ -162,4 +176,10 @@
 );
 
+bool pmSourceRedefinePixelsByRegion (
+    pmSource *mySource,   ///< source to be re-defined
+    const pmReadout *readout,   ///< base the source on this readout
+    psRegion newRegion ///< region for source pixel definition
+);
+
 /** pmSourcePSFClump()
  *
Index: trunk/psModules/src/objects/pmSourceExtendedPars.c
===================================================================
--- trunk/psModules/src/objects/pmSourceExtendedPars.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceExtendedPars.c	(revision 30621)
@@ -17,21 +17,5 @@
 #endif
 
-// #include <stdio.h>
-// #include <math.h>
-// #include <string.h>
 #include <pslib.h>
-// #include "pmHDU.h"
-// #include "pmFPA.h"
-// #include "pmFPAMaskWeight.h"
-// #include "pmSpan.h"
-// #include "pmFootprint.h"
-// #include "pmPeaks.h"
-// #include "pmMoments.h"
-// #include "pmResiduals.h"
-// #include "pmGrowthCurve.h"
-// #include "pmTrend2D.h"
-// #include "pmPSF.h"
-// #include "pmModel.h"
-// #include "pmSource.h"
 #include "pmSourceExtendedPars.h"
 
Index: trunk/psModules/src/objects/pmSourceFitPCM.c
===================================================================
--- trunk/psModules/src/objects/pmSourceFitPCM.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceFitPCM.c	(revision 30621)
@@ -89,4 +89,7 @@
     if (!fitStatus) pcm->modelConv->flags |= PM_MODEL_STATUS_NONCONVERGE;
 
+    // once we have fitted a model, we need to record that this model is a PCM model:
+    pcm->modelConv->isPCM = true;
+
     // models can go insane: reject these
     bool onPic = true;
Index: trunk/psModules/src/objects/pmSourceIO.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO.c	(revision 30621)
@@ -59,12 +59,13 @@
 
 // lookup the EXTNAME values used for table data and image header segments
-static bool sourceExtensions(psString *headname, // Extension name for header
-                             psString *dataname, // Extension name for data
-                             psString *deteffname, // Extension name for detection efficiency
-                             psString *xsrcname, // Extension name for extended sources
-                             psString *xfitname, // Extension name for extended fits
-                             const pmFPAfile *file, // File of interest
-                             const pmFPAview *view // View to level of interest
-                             )
+bool pmSourceIOextnames(psString *headname,    // Extension name for image header
+			psString *dataname,    // Extension name for PSF table data
+			psString *deteffname,  // Extension name for detection efficiency
+			psString *xsrcname,    // Extension name for extended non-parametric measurements
+			psString *xfitname,    // Extension name for extended fitted measurements
+			psString *xradname,    // Extension name for radial apertures
+			const pmFPAfile *file, // File of interest
+			const pmFPAview *view  // View to level of interest
+    )
 {
     bool status;                        // Status of MD lookup
@@ -87,5 +88,5 @@
     }
 
-    // EXTNAME for table data
+    // EXTNAME for PSF table data
     if (dataname) {
         const char *rule = psMetadataLookupStr(&status, menu, "CMF.DATA");
@@ -107,5 +108,5 @@
     }
 
-    // EXTNAME for extended source data table
+    // EXTNAME for extended source non-parametric measurements
     if (xsrcname) {
         const char *rule = psMetadataLookupStr(&status, menu, "CMF.XSRC");
@@ -117,6 +118,6 @@
     }
 
+    // EXTNAME for extended source fitted measurements
     if (xfitname) {
-        // EXTNAME for extended source data table
         const char *rule = psMetadataLookupStr(&status, menu, "CMF.XFIT");
         if (!rule) {
@@ -125,4 +126,14 @@
         }
         *xfitname = pmFPAfileNameFromRule (rule, file, view);
+    }
+
+    // EXTNAME for radial apertures
+    if (xradname) {
+        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XRAD");
+        if (!rule) {
+            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XRAD in EXTNAME.RULES in camera.config");
+            return false;
+        }
+        *xradname = pmFPAfileNameFromRule (rule, file, view);
     }
 
@@ -344,4 +355,7 @@
 	    status &= pmSourcesWrite_##TYPE##_XFIT (file->fits, readout, sources, file->header, xfitname); \
 	}								\
+	if (xradname) {							\
+	    status &= pmSourcesWrite_##TYPE##_XRAD (file->fits, readout, sources, file->header, xradname, recipe); \
+	}								\
     }
 
@@ -449,4 +463,5 @@
         bool XSRC_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_ANALYSIS");
         bool XFIT_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_FITS");
+        bool XRAD_OUTPUT = psMetadataLookupBool(&status, recipe, "RADIAL_APERTURES");
 
         // define the EXTNAME values for the different data segments:
@@ -456,8 +471,10 @@
         psString xsrcname = NULL;
         psString xfitname = NULL;
-        if (!sourceExtensions(&headname, &dataname, &deteffname, 
-			      XSRC_OUTPUT ? &xsrcname : NULL,
-                              XFIT_OUTPUT ? &xfitname : NULL, 
-			      file, view)) {
+        psString xradname = NULL;
+        if (!pmSourceIOextnames(&headname, &dataname, &deteffname, 
+				XSRC_OUTPUT ? &xsrcname : NULL,
+				XFIT_OUTPUT ? &xfitname : NULL, 
+				XRAD_OUTPUT ? &xradname : NULL, 
+				file, view)) {
             return false;
         }
@@ -539,5 +556,7 @@
 		psMetadataAddStr (outhead, PS_LIST_TAIL, "XFITNAME", PS_META_REPLACE, "name of XFIT table extension", xfitname);
             }
-    
+            if (xradname) {
+		psMetadataAddStr (outhead, PS_LIST_TAIL, "XRADNAME", PS_META_REPLACE, "name of XRAD table extension", xradname);
+            }
 
             // these are case-sensitive since the EXTYPE is case-sensitive
@@ -563,5 +582,4 @@
         }
 
-
 	// write out the detection efficiency TABLE segments
 	if (deteffname) {
@@ -583,4 +601,5 @@
 	psFree (xsrcname);
 	psFree (xfitname);
+	psFree (xradname);
 	psFree (deteffname);
 
@@ -593,4 +612,5 @@
 	psFree (xsrcname);
 	psFree (xfitname);
+	psFree (xradname);
 	psFree (deteffname);
 	return false;
@@ -939,5 +959,5 @@
         psString dataname = NULL;
         psString deteffname = NULL;
-        if (!sourceExtensions(&headname, &dataname, &deteffname, NULL, NULL, file, view)) {
+        if (!pmSourceIOextnames(&headname, &dataname, &deteffname, NULL, NULL, NULL, file, view)) {
             return false;
         }
Index: trunk/psModules/src/objects/pmSourceIO.h
===================================================================
--- trunk/psModules/src/objects/pmSourceIO.h	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO.h	(revision 30621)
@@ -30,40 +30,50 @@
 bool pmSourcesWrite_SMPDATA_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_SMPDATA_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_SMPDATA_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_PS1_DEV_0(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_PS1_DEV_0_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_PS1_DEV_0_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_PS1_DEV_0_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_PS1_DEV_1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_PS1_DEV_1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_PS1_DEV_1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_PS1_DEV_1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_PS1_CAL_0(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_PS1_CAL_0_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_PS1_CAL_0_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_PS1_CAL_0_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_CMF_PS1_V1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_V1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_V1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_CMF_PS1_V1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_CMF_PS1_V2(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_V2_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_V2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_CMF_PS1_V2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_CMF_PS1_V3(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_V3_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_V3_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_CMF_PS1_V3_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_CMF_PS1_SV1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_SV1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_SV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_CMF_PS1_SV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_CMF_PS1_DV1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_DV1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_DV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_CMF_PS1_DV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 bool pmSourcesWrite_CMF_PS1_DV2(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_DV2_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 bool pmSourcesWrite_CMF_PS1_DV2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_CMF_PS1_DV2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
 
 psArray *pmSourcesReadCMP (char *filename, psMetadata *header);
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c	(revision 30621)
@@ -676,2 +676,7 @@
     return true;
 }
+
+bool pmSourcesWrite_CMF_PS1_DV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c	(revision 30621)
@@ -737,2 +737,7 @@
     return true;
 }
+
+bool pmSourcesWrite_CMF_PS1_DV2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c	(revision 30621)
@@ -20,4 +20,5 @@
 
 #include "pmConfig.h"
+#include "pmErrorCodes.h"
 #include "pmDetrendDB.h"
 
@@ -71,5 +72,4 @@
     psF32 errMag, chisq, apRadius;
     psS32 nPix, nDOF;
-    char keyword1[80], keyword2[80];
 
     pmChip *chip = readout->parent->parent;
@@ -103,4 +103,5 @@
     table = psArrayAllocEmpty (sources->n);
 
+# if (0)
     // we use this just to define the output vectors (which must be present for all objects)
     bool status = false;
@@ -118,5 +119,5 @@
       psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
     }
-
+# endif
 
     // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
@@ -258,4 +259,6 @@
         psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                     source->mode2);
 
+# if (0)
+	// XXX if we have raw radial apertures, write them out here
 	psVector *radFlux    = psVectorAlloc(radMax->n, PS_TYPE_F32);
 	psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32);
@@ -284,4 +287,5 @@
 	psFree (radFluxErr);
 	psFree (radFill);
+# endif
 
         // XXX not sure how to get this : need to load Nimages with weight?
@@ -781,2 +785,137 @@
     return true;
 }
+
+// **** write out the radial flux values for the sources for a given matched-PSF image
+// **** how do we distinguish the matched-PSF images from the non-matched version
+bool pmSourcesWrite_CMF_PS1_SV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+
+    psArray *table;
+    psMetadata *row;
+    psF32 xPos, yPos;
+    char keyword1[80], keyword2[80];
+
+    // create a header to hold the output data
+    psMetadata *outhead = psMetadataAlloc ();
+
+    // write the links to the image header
+    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "radial flux table extension", extname);
+
+    // we use this just to define the output vectors (which must be present for all objects)
+    bool status = false;
+    psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
+    psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
+    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");
+
+    // write the radial profile apertures to header
+    for (int i = 0; i < radMax->n; i++) {
+      sprintf (keyword1, "RMIN_%02d", i);
+      sprintf (keyword2, "RMAX_%02d", i);
+      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
+      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
+    }
+
+    psVector *fwhmValues = psMetadataLookupVector(&status, readout->analysis, "STACK.PSF.FWHM.VALUES");
+    if (!fwhmValues) {
+	psError (PM_ERR_CONFIG, true, "convolved or measured FWHM is not defined for this readout");
+	return false;
+    }
+
+    // let's write these out in S/N order
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    table = psArrayAllocEmpty (sources->n);
+
+    // we write out all sources, regardless of quality.  the source flags tell us the state
+    for (int i = 0; i < sources->n; i++) {
+
+        pmSource *source = sources->data[i];
+
+        // skip sources without radial aper measurements (or insufficient)
+        if (source->radialAper == NULL) continue;
+        psAssert (source->radialAper->n == fwhmValues->n, "inconsistent radial aperture set");
+
+	for (int entry = 0; entry < fwhmValues->n; entry++) {
+
+	    // choose the convolved EXT model, if available, otherwise the simple one
+	    pmSourceRadialApertures *radialAper = source->radialAper->data[entry];
+	    assert (radialAper);
+
+	    bool useMoments = true;
+	    useMoments = (useMoments && source->moments);          // can't if there are no moments
+	    useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
+	    useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
+
+	    if (useMoments) {
+		xPos = source->moments->Mx;
+		yPos = source->moments->My;
+	    } else {
+		xPos = source->peak->xf;
+		yPos = source->peak->yf;
+	    }
+
+	    row = psMetadataAlloc ();
+
+	    // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)
+	    psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET",         0, "IPP detection identifier index",             source->seq);
+	    psMetadataAddF32 (row, PS_LIST_TAIL, "X_APER",           0, "Center of aperture measurements",            xPos);
+	    psMetadataAddF32 (row, PS_LIST_TAIL, "Y_APER",           0, "Center of aperture measurements",            yPos);
+	    psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM",         0, "FWHM of matched PSF",                        fwhmValues->data.F32[entry]);
+
+	    // XXX if we have raw radial apertures, write them out here
+	    psVector *radFlux    = psVectorAlloc(radMax->n, PS_TYPE_F32);
+	    psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32);
+	    psVector *radFill    = psVectorAlloc(radMax->n, PS_TYPE_F32);
+	    psVectorInit (radFlux,    NAN);
+	    psVectorInit (radFluxErr, NAN);
+	    psVectorInit (radFill,    NAN);
+	    if (!radialAper->flux) goto write_annuli;
+	    if (!radialAper->fill) goto write_annuli;
+	    psAssert (radialAper->flux->n <= radFlux->n, "inconsistent vector lengths");
+	    psAssert (radialAper->fill->n <= radFlux->n, "inconsistent vector lengths");
+
+	    // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux
+	    for (int j = 0; j < radialAper->flux->n; j++) {
+		radFlux->data.F32[j]    = radialAper->flux->data.F32[j];
+		radFluxErr->data.F32[j] = radialAper->fluxErr->data.F32[j];
+		radFill->data.F32[j]    = radialAper->fill->data.F32[j];
+	    }
+
+	write_annuli:
+	    psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX",     PS_DATA_VECTOR, "flux within annuli",    radFlux);
+	    psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_ERR", PS_DATA_VECTOR, "flux error in annuli",  radFluxErr);
+	    psMetadataAdd (row, PS_LIST_TAIL, "APER_FILL",     PS_DATA_VECTOR, "fill factor of annuli", radFill);
+	    psFree (radFlux);
+	    psFree (radFluxErr);
+	    psFree (radFill);
+
+	    psArrayAdd (table, 100, row);
+	    psFree (row);
+	}
+    }
+
+    if (table->n == 0) {
+        if (!psFitsWriteBlank (fits, outhead, extname)) {
+            psError(psErrorCodeLast(), false, "Unable to write empty sources file.");
+            psFree(outhead);
+            psFree(table);
+            return false;
+        }
+        psFree (outhead);
+        psFree (table);
+        return true;
+    }
+
+    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
+    if (!psFitsWriteTable (fits, outhead, table, extname)) {
+        psError(psErrorCodeLast(), false, "writing ext data %s\n", extname);
+        psFree (outhead);
+        psFree(table);
+        return false;
+    }
+    psFree (outhead);
+    psFree (table);
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 30621)
@@ -721,2 +721,7 @@
     return false;
 }
+
+bool pmSourcesWrite_CMF_PS1_V1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 30621)
@@ -724,2 +724,7 @@
     return true;
 }
+
+bool pmSourcesWrite_CMF_PS1_V2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c	(revision 30621)
@@ -762,2 +762,7 @@
     return true;
 }
+
+bool pmSourcesWrite_CMF_PS1_V3_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_PS1_CAL_0.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 30621)
@@ -702,2 +702,7 @@
     return true;
 }
+
+bool pmSourcesWrite_PS1_CAL_0_XRAD (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_PS1_DEV_0.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_PS1_DEV_0.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_PS1_DEV_0.c	(revision 30621)
@@ -248,2 +248,7 @@
     return true;
 }
+
+bool pmSourcesWrite_PS1_DEV_0_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_PS1_DEV_1.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 30621)
@@ -588,2 +588,7 @@
     return true;
 }
+
+bool pmSourcesWrite_PS1_DEV_1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
Index: trunk/psModules/src/objects/pmSourceIO_SMPDATA.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO_SMPDATA.c	(revision 30049)
+++ trunk/psModules/src/objects/pmSourceIO_SMPDATA.c	(revision 30621)
@@ -222,2 +222,7 @@
     return true;
 } 
+
+bool pmSourcesWrite_SMPDATA_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+} 
