Index: trunk/ppSim/src/ppSimLoadSpots.c
===================================================================
--- trunk/ppSim/src/ppSimLoadSpots.c	(revision 17628)
+++ trunk/ppSim/src/ppSimLoadSpots.c	(revision 17628)
@@ -0,0 +1,68 @@
+#include "ppSim.h"
+
+bool ppSimLoadSpots (pmFPA *fpa, pmConfig *config) {
+
+    bool mdok;
+    assert (stars);
+
+    psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, PPSIM_RECIPE); // Recipe
+
+    bool forcedPhot = psMetadataLookupBool(&mdok, recipe, "FORCED.PHOT"); // Density of fakes
+    if (!forcedPhot) return true;
+
+    // Read catalogue stars using psastro
+    // XXX probably need to modify this...
+    psMetadata *astroRecipe = psMetadataLookupPtr(NULL, config->recipes, PSASTRO_RECIPE);
+    if (!astroRecipe) {
+        psError(PSASTRO_ERR_CONFIG, false, "Can't find recipe %s", PSASTRO_RECIPE);
+        return NULL;
+    }
+
+    // Size of FPA
+    psRegion *bounds = ppSimFPABounds (fpa);
+    float radius = 0.5 * PS_MAX(bounds->x1 - bounds->x0, bounds->y1 - bounds->y0) * scale;
+    psFree(bounds);
+
+    float x0fpa = 0.5*(bounds->x0 + bounds->x1);
+    float y0fpa = 0.5*(bounds->y0 + bounds->y1);
+
+    // XXX need to use the WCS to define the overlap region
+    psMetadataAdd(astroRecipe, PS_LIST_TAIL, "RA_MIN",  PS_DATA_F32 | PS_META_REPLACE, "", ra0 - radius);
+    psMetadataAdd(astroRecipe, PS_LIST_TAIL, "RA_MAX",  PS_DATA_F32 | PS_META_REPLACE, "", ra0 + radius);
+    psMetadataAdd(astroRecipe, PS_LIST_TAIL, "DEC_MIN", PS_DATA_F32 | PS_META_REPLACE, "", dec0 - radius);
+    psMetadataAdd(astroRecipe, PS_LIST_TAIL, "DEC_MAX", PS_DATA_F32 | PS_META_REPLACE, "", dec0 + radius);
+    psArray *refStars = psastroLoadRefstars(config);
+    if (!refStars || refStars->n == 0) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to find reference stars.");
+        psFree(refStars);
+        return NULL;
+    }
+    psLogMsg("ppSim", PS_LOG_INFO, "Adding %ld reference stars", refStars->n);
+
+    // convert the pmAstromObj sources to the storage format used by the CMF files
+
+    long oldSize = stars->n;
+    stars = psArrayRealloc (stars, refStars->n);
+
+    // Conversion loop
+    for (long i = 0; i < refStars->n; i++) {
+        ppSimStar *star = ppSimStarAlloc ();
+
+        pmAstromObj *ref = refStars->data[i]; // Reference star
+        star->ra  = ref->sky->r; // RA of star
+        star->dec = ref->sky->d; // Dec of star
+        star->mag = ref->Mag;       // Magnitude of star
+
+        // Apply rotation, make FPA center of boresite
+	// convert the ra,dec to x,y using examples in psastro.
+        // star->x = cos(pa) * xi - sin(pa) * eta + x0fpa;
+        // star->y = sin(pa) * xi + cos(pa) * eta + y0fpa;
+
+        stars->data[oldSize + i] = star;
+
+        psTrace("ppSim", 10, "Adding catalogue star: %.1f,%.1f --> %.2f\n", star->x, star->y, star->flux);
+    }
+
+    // XXX these need to be saved on PSPHOT.INPUT.CMF
+    return true;
+}
Index: trunk/ppSim/src/ppSimMosaicChip.c
===================================================================
--- trunk/ppSim/src/ppSimMosaicChip.c	(revision 17628)
+++ trunk/ppSim/src/ppSimMosaicChip.c	(revision 17628)
@@ -0,0 +1,36 @@
+#include "ppSim.h"
+
+// XXX this is essentially identical to ppImageMosaicChip
+bool ppSimMosaicChip(pmConfig *config, const psMaskType blankMask, const pmFPAview *view,
+                       const char *outFile, const char *inFile)
+{
+    bool status;                        // Status of MD lookup
+
+    pmFPAfile *in = psMetadataLookupPtr(&status, config->files, inFile); // Input file
+    if (!status) {
+        psErrorStackPrint(stderr, "Can't find required I/O file!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    pmFPAfile *out = psMetadataLookupPtr(&status, config->files, outFile); // Output file
+    if (!status) {
+        psErrorStackPrint(stderr, "Can't find required I/O file!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    pmChip *outChip = pmFPAviewThisChip(view, out->fpa);
+    pmChip *inChip = pmFPAviewThisChip(view, in->fpa);
+    if (!outChip->hdu && !outChip->parent->hdu) {
+        const char *name = psMetadataLookupStr(&status, in->fpa->concepts, "FPA.NAME"); // Name of FPA
+        pmFPAAddSourceFromView(out->fpa, name, view, out->format);
+    }
+
+    psTrace("pmChipMosaic", 5, "mosaic chip %s to %s (xbin,ybin: %d,%d to %d,%d)\n",
+            in->name, out->name, in->xBin, in->yBin, out->xBin, out->yBin);
+
+    // XXX mosaic the chip, making a deep copy.  this has the side effect of making the
+    // output image products pure trimmed images, but also increases the memory footprint.
+    status = pmChipMosaic(outChip, inChip, true, blankMask);
+    return status;
+}
+
Index: trunk/ppSim/src/ppSimPhotom.c
===================================================================
--- trunk/ppSim/src/ppSimPhotom.c	(revision 17628)
+++ trunk/ppSim/src/ppSimPhotom.c	(revision 17628)
@@ -0,0 +1,43 @@
+# include "ppSim.h"
+
+// In this function, we perform the psphot analysis routine for the chip-mosaicked images
+bool ppSimPhotom (pmConfig *config, pmFPAview *view) {
+
+    bool status;
+    pmCell *cell;
+    pmReadout *readout;
+
+    psphotModelClassInit ();
+
+    // find or define a pmFPAfile PSPHOT.INPUT
+    pmFPAfile *input = psMetadataLookupPtr (&status, config->files, "PSPHOT.INPUT");
+    if (!status) {
+        psError(PSPHOT_ERR_CONFIG, false, "PSPHOT.INPUT I/O file is not defined");
+        return false;
+    }
+
+    // we make a new copy of the output chip to keep psphot from modifying the output image
+    // XXX is this needed for ppSim? (yes, unless we do not do photometry and make a simulated image)
+    pmChip *oldChip = pmFPAviewThisChip (view, input->src);
+    pmChip *newChip = pmFPAviewThisChip (view, input->fpa);
+    pmChipCopy (newChip, oldChip);
+
+    // iterate over the cells and readout for this chip
+    while ((cell = pmFPAviewNextCell (view, input->fpa, 1)) != NULL) {
+        psLogMsg ("ppSimPhotom", 5, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
+        if (! cell->process || ! cell->file_exists) { continue; }
+
+        // process each of the readouts
+        while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
+            if (! readout->data_exists) { continue; }
+
+            // run the actual photometry analysis
+            if (!psphotReadout (config, view)) {
+                psError(psErrorCodeLast(), false, "failure in psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
