Index: /branches/eam_branch_20070817/psphot/src/models/pmModel_STRAIL.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/models/pmModel_STRAIL.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/models/pmModel_STRAIL.c	(revision 14545)
@@ -12,11 +12,12 @@
 *****************************************************************************/ 
  
-# define PM_MODEL_FUNC       pmModelFunc_STRAIL
-# define PM_MODEL_FLUX       pmModelFlux_STRAIL
-# define PM_MODEL_GUESS      pmModelGuess_STRAIL
-# define PM_MODEL_LIMITS     pmModelLimits_STRAIL
-# define PM_MODEL_RADIUS     pmModelRadius_STRAIL
-# define PM_MODEL_FROM_PSF   pmModelFromPSF_STRAIL
-# define PM_MODEL_FIT_STATUS pmModelFitStatus_STRAIL
+# define PM_MODEL_FUNC       	  pmModelFunc_STRAIL
+# define PM_MODEL_FLUX       	  pmModelFlux_STRAIL
+# define PM_MODEL_GUESS      	  pmModelGuess_STRAIL
+# define PM_MODEL_LIMITS     	  pmModelLimits_STRAIL
+# define PM_MODEL_RADIUS     	  pmModelRadius_STRAIL
+# define PM_MODEL_FROM_PSF   	  pmModelFromPSF_STRAIL
+# define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_STRAIL
+# define PM_MODEL_FIT_STATUS      pmModelFitStatus_STRAIL
 
 psF32 PM_MODEL_FUNC(psVector *deriv, 
@@ -474,6 +475,9 @@
  
 //fixed I think...no good way of guessing as far as I can tell 
-bool PM_MODEL_GUESS (pmModel *model, pmSource *source) { 
- 
+bool PM_MODEL_GUESS (void *inModel, void *inSource)
+{ 
+    pmModel *model = inModel;
+    pmSource *source = inSource;
+
     pmMoments *Smoments = source->moments; 
     psF32     *params  = model->params->data.F32; 
@@ -516,5 +520,9 @@
  
 //fixed 
-bool PM_MODEL_FROM_PSF (pmModel *modelPSF, pmModel *modelFLT, pmPSF *psf) { 
+bool PM_MODEL_FROM_PSF (void *inModelPSF, void *inModelFLT, void *inPSF)
+{
+    pmModel *modelPSF = inModelPSF;
+    pmModel *modelFLT = inModelFLT;
+    pmPSF *psf = inPSF;
  
     psF32 *out = modelPSF->params->data.F32; 
@@ -535,6 +543,60 @@
 } 
  
+// construct the PSF model from the FLT model and the psf
+// XXX is this sufficiently general do be a global function, not a pmModelClass function?
+bool PM_MODEL_PARAMS_FROM_PSF (void *inModel, void *inPSF, float Xo, float Yo, float Io)
+{
+    pmModel *model = inModel;
+    pmPSF *psf = inPSF;
+
+    psF32 *PAR = model->params->data.F32;
+
+    // we require these two parameters to exist
+    assert (psf->params_NEW->n > PM_PAR_YPOS);
+    assert (psf->params_NEW->n > PM_PAR_XPOS);
+
+    PAR[PM_PAR_SKY]  = 0.0;
+    PAR[PM_PAR_I0]   = Io;
+    PAR[PM_PAR_XPOS] = Xo;
+    PAR[PM_PAR_YPOS] = Yo;
+    
+    // supply the model-fitted parameters, or copy from the input
+    for (int i = 0; i < psf->params_NEW->n; i++) {
+	if (i == PM_PAR_SKY) continue;
+	psPolynomial2D *poly = psf->params_NEW->data[i];
+	assert (poly);
+	PAR[i] = psPolynomial2DEval(poly, Xo, Yo);
+    }
+
+    // the 2D PSF model fits polarization terms (E0,E1,E2)
+    // convert to shape terms (SXX,SYY,SXY)
+    // XXX user-defined value for limit?
+    if (!pmPSF_FitToModel (PAR, 0.1)) {
+	psError(PM_ERR_PSF, false, "Failed to fit object at (r,c) = (%.1f,%.1f)", Xo, Yo);
+	return false;
+    }
+
+    // apply the model limits here: this truncates excessive extrapolation
+    // XXX do we need to do this still?  should we put in asserts to test?
+    for (int i = 0; i < psf->params_NEW->n; i++) {
+        // apply the limits to all components or just the psf-model parameters?
+        if (psf->params_NEW->data[i] == NULL)
+            continue;
+
+	bool status = true;
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MIN, i, PAR, NULL);
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MAX, i, PAR, NULL);
+	if (!status) {
+	    psTrace ("psModules.objects", 5, "Hitting parameter limits at (r,c) = (%.1f, %.1f)", Xo, Yo);
+	    model->flags |= PM_MODEL_STATUS_LIMITS;
+	}
+    }
+    return(true);
+}
+
 //done I think 
-bool PM_MODEL_FIT_STATUS (pmModel *model) { 
+bool PM_MODEL_FIT_STATUS (void *inModel)
+{
+    pmModel *model = inModel;
  
     psF32 dP; 
@@ -566,3 +628,4 @@
 # undef PM_MODEL_RADIUS
 # undef PM_MODEL_FROM_PSF
+# undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
Index: /branches/eam_branch_20070817/psphot/src/models/pmModel_TEST1.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/models/pmModel_TEST1.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/models/pmModel_TEST1.c	(revision 14545)
@@ -16,19 +16,17 @@
  *****************************************************************************/
 
-# define PM_MODEL_FUNC       pmModelFunc_TEST1
-# define PM_MODEL_FLUX       pmModelFlux_TEST1
-# define PM_MODEL_GUESS      pmModelGuess_TEST1
-# define PM_MODEL_LIMITS     pmModelLimits_TEST1
-# define PM_MODEL_RADIUS     pmModelRadius_TEST1
-# define PM_MODEL_FROM_PSF   pmModelFromPSF_TEST1
-# define PM_MODEL_FIT_STATUS pmModelFitStatus_TEST1
-
-// XXX consider changing to form PAR[SXY]*(1/PAR[SXX]^2 + 1/PAR[SYY]^2)*X*Y
-// this would provide natural limits on PAR[SXY] of -0.25 : +0.25
+# define PM_MODEL_FUNC       	  pmModelFunc_TEST1
+# define PM_MODEL_FLUX       	  pmModelFlux_TEST1
+# define PM_MODEL_GUESS      	  pmModelGuess_TEST1
+# define PM_MODEL_LIMITS     	  pmModelLimits_TEST1
+# define PM_MODEL_RADIUS     	  pmModelRadius_TEST1
+# define PM_MODEL_FROM_PSF   	  pmModelFromPSF_TEST1
+# define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_TEST1
+# define PM_MODEL_FIT_STATUS      pmModelFitStatus_TEST1
 
 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y)
 psF32 PM_MODEL_FUNC(psVector *deriv,
-                         const psVector *params,
-                         const psVector *pixcoord)
+		    const psVector *params,
+		    const psVector *pixcoord)
 {
     psF32 *PAR = params->data.F32;
@@ -125,6 +123,8 @@
 
 // make an initial guess for parameters
-bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
-{
+bool PM_MODEL_GUESS (void *inModel, void *inSource)
+{
+    pmModel *model = inModel;
+    pmSource *source = inSource;
 
     pmMoments *moments = source->moments;
@@ -160,5 +160,5 @@
     norm = 0.0;
 
-    # define DZ 0.25
+# define DZ 0.25
 
     float f0 = 1.0;
@@ -207,6 +207,9 @@
 }
 
-bool PM_MODEL_FROM_PSF (pmModel *modelPSF, pmModel *modelFLT, pmPSF *psf)
-{
+bool PM_MODEL_FROM_PSF (void *inModelPSF, void *inModelFLT, void *inPSF)
+{
+    pmModel *modelPSF = inModelPSF;
+    pmModel *modelFLT = inModelFLT;
+    pmPSF *psf = inPSF;
 
     psF32 *out = modelPSF->params->data.F32;
@@ -232,9 +235,62 @@
 }
 
+// construct the PSF model from the FLT model and the psf
+// XXX is this sufficiently general do be a global function, not a pmModelClass function?
+bool PM_MODEL_PARAMS_FROM_PSF (void *inModel, void *inPSF, float Xo, float Yo, float Io)
+{
+    pmModel *model = inModel;
+    pmPSF *psf = inPSF;
+
+    psF32 *PAR = model->params->data.F32;
+
+    // we require these two parameters to exist
+    assert (psf->params_NEW->n > PM_PAR_YPOS);
+    assert (psf->params_NEW->n > PM_PAR_XPOS);
+
+    PAR[PM_PAR_SKY]  = 0.0;
+    PAR[PM_PAR_I0]   = Io;
+    PAR[PM_PAR_XPOS] = Xo;
+    PAR[PM_PAR_YPOS] = Yo;
+    
+    // supply the model-fitted parameters, or copy from the input
+    for (int i = 0; i < psf->params_NEW->n; i++) {
+	if (i == PM_PAR_SKY) continue;
+	psPolynomial2D *poly = psf->params_NEW->data[i];
+	assert (poly);
+	PAR[i] = psPolynomial2DEval(poly, Xo, Yo);
+    }
+
+    // the 2D PSF model fits polarization terms (E0,E1,E2)
+    // convert to shape terms (SXX,SYY,SXY)
+    // XXX user-defined value for limit?
+    if (!pmPSF_FitToModel (PAR, 0.1)) {
+	psError(PM_ERR_PSF, false, "Failed to fit object at (r,c) = (%.1f,%.1f)", Xo, Yo);
+	return false;
+    }
+
+    // apply the model limits here: this truncates excessive extrapolation
+    // XXX do we need to do this still?  should we put in asserts to test?
+    for (int i = 0; i < psf->params_NEW->n; i++) {
+        // apply the limits to all components or just the psf-model parameters?
+        if (psf->params_NEW->data[i] == NULL)
+            continue;
+
+	bool status = true;
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MIN, i, PAR, NULL);
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MAX, i, PAR, NULL);
+	if (!status) {
+	    psTrace ("psModules.objects", 5, "Hitting parameter limits at (r,c) = (%.1f, %.1f)", Xo, Yo);
+	    model->flags |= PM_MODEL_STATUS_LIMITS;
+	}
+    }
+    return(true);
+}
+
 // XXX double-check these definitions below
 // this test is invalid if the parameters are derived
 // from the PSF model
-bool PM_MODEL_FIT_STATUS (pmModel *model)
-{
+bool PM_MODEL_FIT_STATUS (void *inModel)
+{
+    pmModel *model = inModel;
 
     psF32 dP;
@@ -265,3 +321,4 @@
 # undef PM_MODEL_RADIUS
 # undef PM_MODEL_FROM_PSF
+# undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
Index: /branches/eam_branch_20070817/psphot/src/pmFootprint.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/pmFootprint.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/pmFootprint.c	(revision 14545)
@@ -29,5 +29,5 @@
 }
 
-bool pmIsSpan(const psPtr ptr)
+bool pmSpanTest(const psPtr ptr)
 {
     return (psMemGetDeallocator(ptr) == (psFreeFunc)spanFree);
@@ -115,5 +115,5 @@
 }
 
-bool pmIsFootprint(const psPtr ptr) {
+bool pmFootprintTest(const psPtr ptr) {
     return (psMemGetDeallocator(ptr) == (psFreeFunc)footprintFree);
 }
@@ -762,5 +762,5 @@
    // Set stop bits from peaks list
    //
-   assert (peaks == NULL || peaks->n == 0 || pmIsPeak(peaks->data[0]));
+   assert (peaks == NULL || peaks->n == 0 || pmPeakTest(peaks->data[0]));
    if (peaks != NULL) {
        for (int i = 0; i < peaks->n; i++) {
@@ -859,5 +859,5 @@
    }
    const pmFootprint *fp = footprints->data[0];
-   assert(pmIsFootprint((const psPtr)fp));
+   assert(pmFootprintTest((const psPtr)fp));
    const int numCols = fp->region.x1 - fp->region.x0 + 1;
    const int numRows = fp->region.y1 - fp->region.y0 + 1;
@@ -884,5 +884,5 @@
 psImage *pmSetFootprintID(const pmFootprint *fp, // the footprint to insert
 			  const int id) {	// the desired ID
-   assert(fp != NULL && pmIsFootprint((const psPtr)fp));
+   assert(fp != NULL && pmFootprintTest((const psPtr)fp));
    const int numCols = fp->region.x1 - fp->region.x0 + 1;
    const int numRows = fp->region.y1 - fp->region.y0 + 1;
@@ -910,5 +910,5 @@
 psArray *pmGrowFootprintArray(const psArray *footprints, // footprints to grow
 			      int r) {	// how much to grow each footprint
-    assert (footprints->n == 0 || pmIsFootprint(footprints->data[0]));
+    assert (footprints->n == 0 || pmFootprintTest(footprints->data[0]));
 
     if (footprints->n == 0) {		// we don't know the size of the footprint's region
@@ -964,6 +964,6 @@
 				const psArray *footprints2, // the other set
 				const int includePeaks) { // which peaks to set? 0x1 => footprints1, 0x2 => 2
-    assert (footprints1->n == 0 || pmIsFootprint(footprints1->data[0]));
-    assert (footprints2->n == 0 || pmIsFootprint(footprints2->data[0]));
+    assert (footprints1->n == 0 || pmFootprintTest(footprints1->data[0]));
+    assert (footprints2->n == 0 || pmFootprintTest(footprints2->data[0]));
 
     if (footprints1->n == 0 || footprints2->n == 0) {		// nothing to do but put copies on merged
@@ -1032,7 +1032,7 @@
 			  const psArray *peaks) { // the pmPeaks
     assert (footprints != NULL);
-    assert (footprints->n == 0 || pmIsFootprint(footprints->data[0]));
+    assert (footprints->n == 0 || pmFootprintTest(footprints->data[0]));
     assert (peaks != NULL);
-    assert (peaks->n == 0 || pmIsPeak(peaks->data[0]));
+    assert (peaks->n == 0 || pmPeakTest(peaks->data[0]));
     
     if (footprints->n == 0) {
@@ -1222,5 +1222,5 @@
 psArray *pmFootprintArrayToPeaks(const psArray *footprints) {
    assert(footprints != NULL);
-   assert(footprints->n == 0 || pmIsFootprint(footprints->data[0]));
+   assert(footprints->n == 0 || pmFootprintTest(footprints->data[0]));
 
    int npeak = 0;
Index: /branches/eam_branch_20070817/psphot/src/pmFootprint.h
===================================================================
--- /branches/eam_branch_20070817/psphot/src/pmFootprint.h	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/pmFootprint.h	(revision 14545)
@@ -11,5 +11,5 @@
 
 pmSpan *pmSpanAlloc(int y, int x1, int x2);
-bool pmIsSpan(const psPtr ptr);
+bool pmSpanTest(const psPtr ptr);
 int pmSpanSortByYX (const void **a, const void **b);
 
@@ -25,5 +25,5 @@
 
 pmFootprint *pmFootprintAlloc(int nspan, const psImage *img);
-bool pmIsFootprint(const psPtr ptr);
+bool pmFootprintTest(const psPtr ptr);
 
 pmFootprint *pmFootprintNormalize(pmFootprint *fp);
Index: /branches/eam_branch_20070817/psphot/src/psphot.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphot.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphot.c	(revision 14545)
@@ -11,5 +11,5 @@
     pmErrorRegister();			// register psModule's error codes/messages
     psphotErrorRegister();              // register our error codes/messages
-    psphotModelGroupInit ();            // load implementation-specific models
+    psphotModelClassInit ();            // load implementation-specific models
 
     // load command-line arguments, options, and system config data
Index: /branches/eam_branch_20070817/psphot/src/psphot.h
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphot.h	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphot.h	(revision 14545)
@@ -51,5 +51,5 @@
 
 // basic support functions
-void            psphotModelGroupInit (void);
+void            psphotModelClassInit (void);
 int             pmPeakSortBySN (const void **a, const void **b);
 int             pmPeakSortByY (const void **a, const void **b);
Index: /branches/eam_branch_20070817/psphot/src/psphotChoosePSF.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotChoosePSF.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotChoosePSF.c	(revision 14545)
@@ -295,5 +295,5 @@
     }
 
-    char *modelName = pmModelGetType (psf->type);
+    char *modelName = pmModelClassGetName (psf->type);
     psLogMsg ("psphot.pspsf", PS_LOG_INFO, "select psf model: %f sec\n", psTimerMark ("psphot"));
     psLogMsg ("psphot.pspsf", PS_LOG_INFO, "psf model %s, ApResid: %f +/- %f\n", modelName, psf->ApResid, psf->dApResid);
@@ -315,26 +315,13 @@
     PS_ASSERT_PTR_NON_NULL(image, false);
 
-    pmModel *modelEXT = pmModelAlloc (psf->type);
-    PS_ASSERT_PTR_NON_NULL(modelEXT, false);
-
-    // make a model with unit central intensity at the image center
-    modelEXT->params->data.F32[PM_PAR_SKY] = 0;
-    modelEXT->params->data.F32[PM_PAR_I0] = 1;
-    modelEXT->params->data.F32[PM_PAR_XPOS] = 0.5*image->numCols;
-    modelEXT->params->data.F32[PM_PAR_YPOS] = 0.5*image->numRows;
-
-    // construct a PSF model at this coordinate
-    pmModel *modelPSF = pmModelFromPSF (modelEXT, psf);
+    // construct a normalized PSF model at this coordinate (Io = 1.0)
+    pmModel *modelPSF = pmModelFromPSFforXY (psf, 0.5*image->numCols, 0.5*image->numRows, 1.0);
     if (modelPSF == NULL) {
         psError(PSPHOT_ERR_PSF, false, "Failed to estimate PSF model at image centre");
-        psFree(modelEXT);
         return false;
     }
 
-    // get the correct model-radius function
-    pmModelRadius modelRadiusFunc = pmModelRadius_GetFunction (psf->type);
-
     // get the model full-width at half-max
-    psF64 FWHM_X = 2*modelRadiusFunc (modelPSF->params, 0.5);
+    psF64 FWHM_X = 2*modelPSF->modelRadius (modelPSF->params, 0.5);
 
     // XXX make sure this is consistent with the re-definition of PM_PAR_SXX
@@ -351,6 +338,4 @@
     psMetadataAddS32 (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", psf->nPSFstars);
     psMetadataAddBool(recipe, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", true);
-
-    psFree (modelEXT);
     psFree (modelPSF);
 
Index: /branches/eam_branch_20070817/psphot/src/psphotCleanup.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotCleanup.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotCleanup.c	(revision 14545)
@@ -7,5 +7,5 @@
     psTimerStop ();
     psMemCheckCorruption (stderr, true);
-    pmModelGroupCleanup ();
+    pmModelClassCleanup ();
     psTimeFinalize ();
     pmConceptsDone ();
Index: /branches/eam_branch_20070817/psphot/src/psphotEvalFLT.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotEvalFLT.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotEvalFLT.c	(revision 14545)
@@ -37,5 +37,5 @@
     } 
 
-    keep = pmModelFitStatus (model);
+    keep = model->modelFitStatus(model);
     if (keep) return true;
 
Index: /branches/eam_branch_20070817/psphot/src/psphotFakeSources.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotFakeSources.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotFakeSources.c	(revision 14545)
@@ -23,5 +23,5 @@
         source->type = PM_SOURCE_TYPE_STAR;
 
-        pmModelType modelType = pmModelSetType ("PS_MODEL_QGAUSS");
+        pmModelType modelType = pmModelClassGetType ("PS_MODEL_QGAUSS");
         source->modelPSF = pmSourceModelGuess (source, modelType);
         sources->data[i] = source;
Index: /branches/eam_branch_20070817/psphot/src/psphotFindPeaks.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotFindPeaks.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotFindPeaks.c	(revision 14545)
@@ -95,5 +95,5 @@
 
     // find the peaks in the smoothed image
-    psArray *peaks = pmFindImagePeaks (smooth_im, threshold);
+    psArray *peaks = pmPeaksInImage (smooth_im, threshold);
     if (peaks == NULL) {
         // XXX this may also be due to a programming or config error
Index: /branches/eam_branch_20070817/psphot/src/psphotGrowthCurve.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotGrowthCurve.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotGrowthCurve.c	(revision 14545)
@@ -14,7 +14,4 @@
     float radius;
 
-    // create template model
-    pmModel *modelRef = pmModelAlloc(psf->type);
-
     // use the center of the center pixel of the image
     xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
@@ -23,13 +20,6 @@
     dy = psf->growth->maxRadius + 1;
 
-    // assign the x and y coords to the image center
-    // create an object with center intensity of 1000
-    modelRef->params->data.F32[PM_PAR_SKY] = 0;
-    modelRef->params->data.F32[PM_PAR_I0] = 1000;
-    modelRef->params->data.F32[PM_PAR_XPOS] = xc;
-    modelRef->params->data.F32[PM_PAR_YPOS] = yc;
-
-    // create modelPSF from this model
-    pmModel *model = pmModelFromPSF (modelRef, psf);
+    // create normalized model object at xc,yc 
+    pmModel *model = pmModelFromPSFforXY (psf, xc, yc, 1.0);
 
     // measure the fitMag for this model
@@ -76,5 +66,4 @@
     psFree (mask);
     psFree (model);
-    psFree (modelRef);
 
     return true;
Index: /branches/eam_branch_20070817/psphot/src/psphotModelGroupInit.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotModelGroupInit.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotModelGroupInit.c	(revision 14545)
@@ -7,18 +7,18 @@
 # include "models/pmModel_STRAIL.c"
 
-static pmModelGroup userModels[] = {
-    {"PS_MODEL_TEST1", 7, pmModelFunc_TEST1,  pmModelFlux_TEST1,  pmModelRadius_TEST1,  pmModelLimits_TEST1,  pmModelGuess_TEST1, pmModelFromPSF_TEST1, pmModelFitStatus_TEST1},
-    {"PS_MODEL_STRAIL", 9, pmModelFunc_STRAIL,  pmModelFlux_STRAIL,  pmModelRadius_STRAIL,  pmModelLimits_STRAIL,  pmModelGuess_STRAIL, pmModelFromPSF_STRAIL, pmModelFitStatus_STRAIL},
+static pmModelClass userModels[] = {
+    {"PS_MODEL_TEST1", 7, pmModelFunc_TEST1,  pmModelFlux_TEST1,  pmModelRadius_TEST1,  pmModelLimits_TEST1,  pmModelGuess_TEST1, pmModelFromPSF_TEST1, pmModelParamsFromPSF_TEST1, pmModelFitStatus_TEST1},
+    {"PS_MODEL_STRAIL", 9, pmModelFunc_STRAIL,  pmModelFlux_STRAIL,  pmModelRadius_STRAIL,  pmModelLimits_STRAIL,  pmModelGuess_STRAIL, pmModelFromPSF_STRAIL, pmModelParamsFromPSF_STRAIL, pmModelFitStatus_STRAIL},
 };
 
-void psphotModelGroupInit (void) 
+void psphotModelClassInit (void) 
 { 
 
-    // if pmModelGroupInit returns false, we have already init'ed
-    if (!pmModelGroupInit ()) return;
+    // if pmModelClassInit returns false, we have already init'ed
+    if (!pmModelClassInit ()) return;
 
-    int Nmodels = sizeof (userModels) / sizeof (pmModelGroup);
+    int Nmodels = sizeof (userModels) / sizeof (pmModelClass);
     for (int i = 0; i < Nmodels; i++) {
-	pmModelGroupAdd (&userModels[i]);
+	pmModelClassAdd (&userModels[i]);
     }
     return;
Index: /branches/eam_branch_20070817/psphot/src/psphotModelTest.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotModelTest.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotModelTest.c	(revision 14545)
@@ -89,5 +89,5 @@
             modelName = item->data.V;
         }
-        modelType = pmModelSetType (modelName);
+        modelType = pmModelClassGetType (modelName);
         if (modelType < 0) psAbort("unknown model %s", modelName);
 	source->type = PM_SOURCE_TYPE_EXTENDED;
@@ -118,5 +118,5 @@
             modelName = item->data.V;
         }
-        modelType = pmModelSetType (modelName);
+        modelType = pmModelClassGetType (modelName);
         if (modelType < 0) psAbort("unknown model %s", modelName);
 	source->type = PM_SOURCE_TYPE_EXTENDED;
@@ -148,5 +148,5 @@
 
     // if any parameters are defined by the user, take those values
-    int nParams = pmModelParameterCount (modelType);
+    int nParams = pmModelClassParameterCount (modelType);
     psF32 *params = model->params->data.F32;
     params[PM_PAR_XPOS] = xObj; // XXX use the user-supplied value, 
Index: /branches/eam_branch_20070817/psphot/src/psphotPSFConvModel.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotPSFConvModel.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotPSFConvModel.c	(revision 14545)
@@ -58,18 +58,8 @@
     psVector *dparams = modelConv->dparams;
 
-    // get the model function for this model
-    pmModelFunc modelFunc = pmModelFunc_GetFunction (modelConv->type);
-    if (!modelFunc)
-	psAbort("invalid model function");
-
-    // get the limits function for this model
-    pmModelLimits checkLimits = pmModelLimits_GetFunction (modelConv->type);
-    if (!checkLimits)
-	psAbort("invalid model limits function");
-
     // create the minimization constraints
     psMinConstraint *constraint = psMinConstraintAlloc();
     constraint->paramMask = psVectorAlloc (params->n, PS_TYPE_U8);
-    constraint->checkLimits = checkLimits;
+    constraint->checkLimits = modelConv->modelLimits;
 
     // set parameter mask based on fitting mode
@@ -81,6 +71,6 @@
     // force the floating parameters to fall within the contraint ranges
     for (int i = 0; i < params->n; i++) {
-	checkLimits (PS_MINIMIZE_PARAM_MIN, i, params->data.F32, NULL);
-	checkLimits (PS_MINIMIZE_PARAM_MAX, i, params->data.F32, NULL);
+	modelConv->modelLimits (PS_MINIMIZE_PARAM_MIN, i, params->data.F32, NULL);
+	modelConv->modelLimits (PS_MINIMIZE_PARAM_MAX, i, params->data.F32, NULL);
     }
 
@@ -90,5 +80,5 @@
     psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
 
-    bool fitStatus = psphotModelWithPSF_LMM (myMin, covar, params, constraint, source, psf, modelFunc);
+    bool fitStatus = psphotModelWithPSF_LMM (myMin, covar, params, constraint, source, psf, modelConv->modelFunc);
     for (int i = 0; i < dparams->n; i++) {
         if (psTraceGetLevel("psphot") >= 4) {
Index: /branches/eam_branch_20070817/psphot/src/psphotPSFResiduals.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotPSFResiduals.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotPSFResiduals.c	(revision 14545)
@@ -12,36 +12,16 @@
     if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
 
-    // XXX if a source is faint, it will not have moments measured.
-    // it must be modelled as a PSF.  In this case, we need to use 
-    // the peak centroid to get the coordinates and get the peak flux 
-    // from the image?
-
-    // use the source moments, etc to guess basic model parameters
-    pmModel *modelEXT = pmSourceModelGuess (source, psf->type);
-    
-    // XXX put this in a function of its own..
-    if (modelEXT == NULL) {
-	psErrorClear (); // XXX need to clear the error from failing the model
-	modelEXT = pmModelAlloc(psf->type);
-	psF32 *PAR = modelEXT->params->data.F32;
-	PAR[PM_PAR_SKY]  = 0;
-	// XXX get this from the image pixels
-	PAR[PM_PAR_I0]   = source->peak->flux;
-	PAR[PM_PAR_XPOS] = source->peak->xf;
-	PAR[PM_PAR_YPOS] = source->peak->yf;
+    if (source->mode & PM_SOURCE_MODE_SATSTAR) {
+	Xo = source->moments->x;
+	Yo = source->moments->y;
+	Io = source->peak->flux;
     } else {
-	// these valuse are set in pmSourceModelGuess, should this rule be in there as well?
-	if (source->mode &  PM_SOURCE_MODE_SATSTAR) {
-	    modelEXT->params->data.F32[PM_PAR_XPOS] = source->moments->x;
-	    modelEXT->params->data.F32[PM_PAR_YPOS] = source->moments->y;
-	} else {
-	    modelEXT->params->data.F32[PM_PAR_XPOS] = source->peak->xf;
-	    modelEXT->params->data.F32[PM_PAR_YPOS] = source->peak->yf;
-	}
+	Xo = source->peak->xf;
+	Yo = source->peak->yf;
+	Io = source->peak->flux;
     }
 
     // set PSF parameters for this model (apply 2D shape model)
-    pmModel *modelPSF = pmModelFromPSF (modelEXT, psf);
-    psFree (modelEXT);
+    pmModel *modelPSF = pmModelFromPSFforXY (psf, Xo, Yo, Io);
 
     // XXX need to define the guess flux?
Index: /branches/eam_branch_20070817/psphot/src/psphotRadiusChecks.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotRadiusChecks.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotRadiusChecks.c	(revision 14545)
@@ -6,5 +6,4 @@
 static float PSF_FIT_RADIUS = 0;	// radius to use in fitting (ignored if <= 0,
 					// and a per-object radius is calculated)
-static pmModelRadius modelRadiusPSF;
 
 bool psphotInitRadiusPSF(const psMetadata *recipe,
@@ -17,6 +16,4 @@
     PSF_FIT_RADIUS =  psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
 
-    // this function specifies the radius at this the model hits the given flux
-    modelRadiusPSF       = pmModelRadius_GetFunction (type);
     return true;
 }
@@ -34,7 +31,7 @@
     if (radiusFit <= 0) {		// use fixed radius
 	if (moments == NULL) {
-	    radiusFit = modelRadiusPSF(model->params, PSF_FIT_NSIGMA*moments->dSky);
+	    radiusFit = model->modelRadius(model->params, PSF_FIT_NSIGMA*moments->dSky);
 	} else {
-	    radiusFit = modelRadiusPSF(model->params, 1.0);
+	    radiusFit = model->modelRadius(model->params, 1.0);
 	}
     }
@@ -62,5 +59,5 @@
 
     // set the fit radius based on the object flux limit and the model
-    model->radiusFit = (RADIUS_TYPE) (modelRadiusPSF (model->params, PSF_FIT_NSIGMA*moments->dSky) + dR + PSF_FIT_PADDING);
+    model->radiusFit = (RADIUS_TYPE) (model->modelRadius (model->params, PSF_FIT_NSIGMA*moments->dSky) + dR + PSF_FIT_PADDING);
     if (isnan(model->radiusFit)) psAbort("error in radius");
 	
@@ -78,5 +75,4 @@
 static float EXT_FIT_NSIGMA;
 static float EXT_FIT_PADDING;
-static pmModelRadius modelRadiusEXT;
 
 bool psphotInitRadiusEXT (psMetadata *recipe, pmModelType type) {
@@ -87,6 +83,4 @@
     EXT_FIT_PADDING  = psMetadataLookupF32 (&status, recipe, "EXT_FIT_PADDING");
 
-    // this function specifies the radius at this the model hits the given flux
-    modelRadiusEXT       = pmModelRadius_GetFunction (type);
     return true;
 }
@@ -101,5 +95,5 @@
 
     // set the fit radius based on the object flux limit and the model
-    model->radiusFit = (RADIUS_TYPE) (modelRadiusEXT (model->params, EXT_FIT_NSIGMA*moments->dSky) + EXT_FIT_PADDING);
+    model->radiusFit = (RADIUS_TYPE) (model->modelRadius (model->params, EXT_FIT_NSIGMA*moments->dSky) + EXT_FIT_PADDING);
     if (isnan(model->radiusFit)) psAbort("error in radius");
 
Index: /branches/eam_branch_20070817/psphot/src/psphotSourceFits.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotSourceFits.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotSourceFits.c	(revision 14545)
@@ -195,5 +195,5 @@
     // extended source model descriptions
     char *modelNameEXT = psMetadataLookupStr (&status, recipe, "EXT_MODEL");
-    modelTypeEXT = pmModelSetType (modelNameEXT);
+    modelTypeEXT = pmModelClassGetType (modelNameEXT);
     psphotInitRadiusEXT (recipe, modelTypeEXT);
 
Index: /branches/eam_branch_20070817/psphot/src/psphotTestSourceOutput.c
===================================================================
--- /branches/eam_branch_20070817/psphot/src/psphotTestSourceOutput.c	(revision 14544)
+++ /branches/eam_branch_20070817/psphot/src/psphotTestSourceOutput.c	(revision 14545)
@@ -21,5 +21,4 @@
     psVector *x = psVectorAlloc(2, PS_TYPE_F32);
     psVector *params = model->params;
-    pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
     psS32 imageCol;
     psS32 imageRow;
@@ -68,5 +67,5 @@
             // set the appropriate pixel value for this coordinate
 	    if (mode & PSPHOT_ADD_MODEL) {
-		pixelValue = modelFunc (NULL, params, x) - skyValue;
+		pixelValue = model->modelFunc (NULL, params, x) - skyValue;
 	    } else {
 		pixelValue = 0.0;
