Index: trunk/psphot/src/psphotFullForceSummaryReadout.c
===================================================================
--- trunk/psphot/src/psphotFullForceSummaryReadout.c	(revision 36664)
+++ trunk/psphot/src/psphotFullForceSummaryReadout.c	(revision 36701)
@@ -4,16 +4,18 @@
 typedef struct {
     int     numTrials;
-    psF32   fRmajorMin;
-    psF32   fRmajorMax;
-    psF32   fRmajorDel;
-    psF32   fRminorMin;
-    psF32   fRminorMax;
-    psF32   fRminorDel;
-    psVector    *rMajor;
-    psVector    *rMinor;
+    psF64   fRMajorMin;
+    psF64   fRMajorMax;
+    psF64   fRMajorDel;
+    psF64   fRMinorMin;
+    psF64   fRMinorMax;
+    psF64   fRMinorDel;
+    psVector    *fRMajor;
+    psVector    *fRMinor;
     psArray *zeroPt;
     psArray *exptime;
     psArray *cffTable;
 } galaxyShapeOptions;
+
+
 
 static pmSource *psphotFullForceSummarizeObject(pmConfig *config, pmPhotObj *obj, psVector *fluxScaleFactor, galaxyShapeOptions *options);
@@ -47,11 +49,8 @@
     psMetadataAddF32(outputCell->concepts, PS_LIST_TAIL, "CELL.EXPOSURE", PS_META_REPLACE, "Exposure time (sec)",
         outputExptime);
-    // don't think this one matters
-//    psMetadataAddF32(output->fpa->concepts, PS_LIST_TAIL, "FPA.EXPOSURE", PS_META_REPLACE, "Exposure time (sec)",
- //       outputExptime);
 
     // Create objects from the various input's sources
     // loop over the available readouts
-//    psArray *readouts = psArrayAlloc(num);
+
     psVector *fluxScaleFactor = psVectorAlloc(num, PS_TYPE_F32);
     galaxyShapeOptions options;
@@ -91,6 +90,4 @@
         psF32 scaleFactor = pow(10, 0.4 * (outputZeroPoint - zero_point)) * outputExptime / exptime;
         fluxScaleFactor->data.F32[index] = scaleFactor;
-
-//        readouts->data[index] = readout;
 
         // find detections
@@ -184,8 +181,9 @@
     psVector *sumInvSig2 = NULL;
     psVector *numerator   = NULL;
-//    psVector *tmp = NULL;
     psF32   totalNPix = 0;
     long    vectorLength = 0;
 
+    // Loop over sources for this object. Start output source for first input that has
+    // good pixel frac
     for (int i=0; i < obj->sources->n; i++) {
         pmSource *source = obj->sources->data[i];
@@ -220,8 +218,12 @@
         }
 
+        // The only parameters that we are summarizing currently are galaxy shapes. 
+        // Continue for inputs that do not have modelEXT which contains the model paramters
+        if (!source->modelEXT) continue;
+
         if (source->galaxyFits && isfinite(source->galaxyFits->nPix) && source->galaxyFits->chisq->n) {
             if (numerator == NULL) {
+                // first source with galaxyFits allocate accumulators
                 vectorLength = source->galaxyFits->chisq->n;
-                // tmp = psVectorAlloc(vectorLength, PS_TYPE_F32);
                 sumWeightedFlux = psVectorAlloc(vectorLength, PS_TYPE_F32);
                 psVectorInit(sumWeightedFlux, 0.0);
@@ -232,4 +234,5 @@
             }
 
+            // Die if the lengths of the vectors is not the same in all sources
             psAssert(vectorLength == options->numTrials, "length of chisq vector %ld does not match options %d",
                 vectorLength, options->numTrials);
@@ -237,6 +240,7 @@
                     source->galaxyFits->chisq->n, vectorLength);
 
-
             psF32 scaleFactor = fluxScaleFactor->data.F32[source->imageID];
+
+            totalNPix += source->galaxyFits->nPix;
 
             for (int k = 0; k < vectorLength; k++) {
@@ -245,27 +249,10 @@
                 psF32 flux  = source->galaxyFits->Flux->data.F32[k]  * scaleFactor;
                 psF32 dFlux = source->galaxyFits->dFlux->data.F32[k] * scaleFactor;
-                // for chisq 
-                // Numerator = sum( nPix[i] * chisq[i] )
-                // denominator will be sum( nPix )
-
-
-//                tmp = (psVector *) psBinaryOp(tmp, 
- //                   source->galaxyFits->chisq, "*", psScalarAlloc(source->galaxyFits->nPix, PS_TYPE_F32));
-//                numerator = (psVector *) psBinaryOp(numerator, numerator, "+", tmp);
 
                 numerator->data.F32[k] += chisq * source->galaxyFits->nPix;
-                totalNPix += source->galaxyFits->nPix;
-
-                // sumInvSig2 = sum( 1 / dFlux**2 )
-//                tmp = (psVector *) psBinaryOp(tmp, source->galaxyFits->dFlux, "*", source->galaxyFits->dFlux);
-//                tmp = (psVector *) psBinaryOp(tmp, psScalarAlloc(1.0, PS_TYPE_F32), "/", tmp);
-//                sumInvSig2 = (psVector *) psBinaryOp(sumInvSig2, sumInvSig2, "+", tmp);
-//
+
                 psF32 invSig2 = 1.0 / (dFlux * dFlux);
                 sumInvSig2->data.F32[k] += invSig2;
 
-                // sumWeightedFlux = sum ( Flux / dFlux**2 )
-//                tmp = (psVector *) psBinaryOp(tmp, source->galaxyFits->Flux, "*", tmp);
-//                sumWeightedFlux = (psVector *) psBinaryOp(sumWeightedFlux, sumWeightedFlux, "+", tmp);
                 sumWeightedFlux->data.F32[k] += flux * invSig2;
             }
@@ -275,24 +262,55 @@
     if (outSrc) {
         if (vectorLength) {
+            // allocate galaxyFits for the output source
             outSrc->galaxyFits = pmSourceGalaxyFitsAlloc();
-            outSrc->galaxyFits->nPix = totalNPix;
-            outSrc->galaxyFits->Flux  = psVectorRecycle(outSrc->galaxyFits->Flux, vectorLength, PS_TYPE_F32);
-            outSrc->galaxyFits->dFlux = psVectorRecycle(outSrc->galaxyFits->dFlux, vectorLength, PS_TYPE_F32);
-            outSrc->galaxyFits->chisq = psVectorRecycle(outSrc->galaxyFits->chisq, vectorLength, PS_TYPE_F32);
+            outSrc->galaxyFits->nPix  = totalNPix;
+            psVector *fluxVec = 
+                outSrc->galaxyFits->Flux  = psVectorRecycle(outSrc->galaxyFits->Flux,  vectorLength, PS_TYPE_F32);
+            psVector *dFluxVec = 
+                outSrc->galaxyFits->dFlux = psVectorRecycle(outSrc->galaxyFits->dFlux, vectorLength, PS_TYPE_F32);
+            psVector *chisqVec = 
+                outSrc->galaxyFits->chisq = psVectorRecycle(outSrc->galaxyFits->chisq, vectorLength, PS_TYPE_F32);
+
+            // Find the nominal radii paramters in the cff table
+            if (outSrc->seq >= options->cffTable->n) {
+                psError(PS_ERR_PROGRAMMING, true, "object sequence number %d is larger than cff table length %ld",
+                    outSrc->seq, options->cffTable->n);
+                return NULL;
+            }
+            psMetadata *cffRow = options->cffTable->data[outSrc->seq];
+            if (!cffRow) {
+                psError (PS_ERR_PROGRAMMING, true, "NO cff data for object %d", outSrc->seq);
+                psFree(outSrc);
+                return NULL;
+            }
+            bool mdok;
+            psF32 R_MAJOR = psMetadataLookupF32(&mdok, cffRow, "R_MAJOR");
+            if (!mdok) {
+                psError (PS_ERR_PROGRAMMING, true, "can't find R_MAJOR for object %d", outSrc->seq);
+                psFree(outSrc);
+                return NULL;
+            }
+            psF32 R_MINOR = psMetadataLookupF32(&mdok, cffRow, "R_MINOR");
+            if (!mdok) {
+                psError (PS_ERR_PROGRAMMING, true, "can't find R_MINOR for object %d", outSrc->seq);
+                psFree(outSrc);
+                return NULL;
+            }
+
+            // fill the summary galaxyFits vectors and find the trial with the minimum value for chisq
+
+            int min_k = -1;
+            psF32 minChisq = NAN;
+
             for (int k = 0; k < vectorLength; k++) {
-                outSrc->galaxyFits->Flux->data.F32[k]  = sumWeightedFlux->data.F32[k] / sumInvSig2->data.F32[k];
-                outSrc->galaxyFits->dFlux->data.F32[k] = 1.0 / sumInvSig2->data.F32[k];
-                outSrc->galaxyFits->chisq->data.F32[k] = numerator->data.F32[k] / totalNPix;
-
-#ifdef nodef
-                outSrc->galaxyFits->Flux = (psVector *) psBinaryOp(outSrc->galaxyFits->Flux,
-                        sumWeightedFlux, "/", sumInvSig2);
-
-                outSrc->galaxyFits->dFlux = (psVector *) psBinaryOp(outSrc->galaxyFits->dFlux,
-                        psScalarAlloc(1.0, PS_TYPE_F32), "/", sumInvSig2);
-
-                outSrc->galaxyFits->chisq = (psVector *) psBinaryOp(outSrc->galaxyFits->chisq,
-                        numerator, "/", psScalarAlloc(totalNPix, PS_TYPE_F32));
-#endif
+                fluxVec->data.F32[k]  = sumWeightedFlux->data.F32[k] / sumInvSig2->data.F32[k];
+                dFluxVec->data.F32[k] = 1.0 / sumInvSig2->data.F32[k];
+
+                psF32 thischisq = chisqVec->data.F32[k] = numerator->data.F32[k] / totalNPix;
+
+                if (isfinite(thischisq)  && (!isfinite(minChisq) || thischisq < minChisq)) {
+                    min_k = k;
+                    minChisq = thischisq;
+                }
             }
 
@@ -300,50 +318,217 @@
             psFree(sumInvSig2);
             psFree(sumWeightedFlux);
-//            psFree(tmp);
-
-            int min_j = -1;
-            psF32 minChisq = NAN;
-            psVector *chisq = outSrc->galaxyFits->chisq;
-            for (int j=0; j < chisq->n; j++) {
-                psF32 thischisq = chisq->data.F32[j];
-                if (isfinite(thischisq)  && (!isfinite(minChisq) || thischisq < minChisq)) {
-                    min_j = j;
-                    minChisq = thischisq;
+
+            if (min_k >= 0 && isfinite(minChisq) && outSrc->modelEXT) {
+                // copy the best fit params to the model
+                // fractional radii with the lowest chisq
+                psEllipseAxes axes = pmPSF_ModelToAxes(outSrc->modelEXT->params->data.F32, outSrc->modelEXT->type);
+
+                // examine the params for the trial with minimum chisq.
+                bool fitMajor = true;
+                bool fitMinor = true;
+                psF64 fRMajorBest = options->fRMajor->data.F32[min_k];
+                if ((fabs(fRMajorBest - options->fRMajorMin) < options->fRMajorDel) || 
+                    (fabs(fRMajorBest - options->fRMajorMax) < options->fRMajorDel)) {
+                    fitMajor = false;
                 }
-            }
-            if (min_j >= 0 && isfinite(minChisq) && outSrc->modelEXT) {
-                // copy the best fit params to the model
-                psEllipseAxes axes = pmPSF_ModelToAxes(outSrc->modelEXT->params->data.F32, outSrc->modelEXT->type);
-                if (outSrc->seq >= options->cffTable->n) {
-                    psError(PS_ERR_PROGRAMMING, true, "object sequence number %d is larger than cff table length %ld",
-                        outSrc->seq, options->cffTable->n);
-                    return NULL;
+                psF64 fRMinorBest = options->fRMinor->data.F32[min_k];
+                if ((fabs(fRMinorBest - options->fRMinorMin) < options->fRMinorDel) || 
+                    (fabs(fRMinorBest - options->fRMinorMax) < options->fRMinorDel)) {
+                    fitMinor = false;
                 }
-                psMetadata *row = options->cffTable->data[outSrc->seq];
-                if (!row) {
-                    psError (PS_ERR_PROGRAMMING, true, "NO cff data for object %d", outSrc->seq);
-                    psFree(outSrc);
-                    return NULL;
+                // If either major or minor is at one of the limits do not fit report the minimum value
+                bool useFit = fitMajor && fitMinor;
+
+                // save the flux and dFlux values from entry with lowest chisq
+                psF64 fluxBest = fluxVec->data.F32[min_k];
+                psF64 dFlux0   = dFluxVec->data.F32[min_k];
+                psF64 flux0    = NAN;
+
+                if (useFit) {
+                    #define NUM_TRIALS_INIT 9     // this isn't used for anything execpt for the initial vector lengths
+                    psVector *major = psVectorAllocEmpty(NUM_TRIALS_INIT, PS_TYPE_F64);
+                    psVector *minor = psVectorAllocEmpty(NUM_TRIALS_INIT, PS_TYPE_F64);
+                    psVector *chisq = psVectorAllocEmpty(NUM_TRIALS_INIT, PS_TYPE_F64);
+                    psVector *flux = psVectorAllocEmpty(NUM_TRIALS_INIT, PS_TYPE_F64);
+                    psVector *dFlux = psVectorAllocEmpty(NUM_TRIALS_INIT, PS_TYPE_F64);
+
+                    // XXX: use a recipe parameter
+                    psF64 maxDeltaMaj = 2.2 * options->fRMajorDel;
+                    psF64 maxDeltaMin = 2.2 * options->fRMinorDel;
+
+                    psF64 majorMin = NAN;
+                    psF64 majorMax = NAN;
+                    psF64 minorMin = NAN;
+                    psF64 minorMax = NAN;
+                    psF64 chisqMin = NAN;
+                    psF64 chisqMax = NAN;
+                    for (int k = 0; k < vectorLength; k++) {
+
+                        if (fabs(options->fRMajor->data.F32[k] - fRMajorBest) < maxDeltaMaj &&
+                            fabs(options->fRMinor->data.F32[k] - fRMinorBest) < maxDeltaMin) {
+
+                            if (isfinite(chisqVec->data.F32[k]) && 
+                                isfinite(fluxVec->data.F32[k])  &&
+                                isfinite(dFluxVec->data.F32[k])) {
+
+                                // compute major and minor radius vectors from nominal and trial fractions
+                                // also find the ranges in the vectors
+                                psF64 thisMajor = R_MAJOR * options->fRMajor->data.F32[k];
+                                if (!isfinite(majorMin) || thisMajor < majorMin) {
+                                    majorMin = thisMajor;
+                                }
+                                if (!isfinite(majorMax) || thisMajor > majorMax) {
+                                    majorMax = thisMajor;
+                                }
+                                psVectorAppend(major, thisMajor);
+
+                                psF64 thisMinor = R_MINOR * options->fRMinor->data.F32[k];
+                                if (!isfinite(minorMin) || thisMinor < minorMin) {
+                                    minorMin = thisMinor;
+                                }
+                                if (!isfinite(minorMax) || thisMinor > minorMax) {
+                                    minorMax = thisMinor;
+                                }
+                                psVectorAppend(minor, thisMinor);
+
+                                psF64 thisChisq = chisqVec->data.F32[k];
+                                if (!isfinite(chisqMin) || thisChisq < chisqMin) {
+                                    chisqMin = thisChisq;
+                                }
+                                if (!isfinite(chisqMax) || thisChisq > chisqMax) {
+                                    chisqMax = thisChisq;
+                                }
+                                psVectorAppend(chisq, thisChisq);
+
+                                psVectorAppend(flux,  fluxVec->data.F32[k]);
+                                psVectorAppend(dFlux, dFluxVec->data.F32[k]);
+                            }
+                        }
+                    }
+
+                    // see if we ever get too few good values (haven't seen this happen)
+                    if (major->n < NUM_TRIALS_INIT) {
+                        fprintf(stderr, "only found %ld good points wanted %d for seq: %d\n",
+                            major->n, NUM_TRIALS_INIT, outSrc->seq); 
+                    }
+
+                    // rescale data - this helps avoid precision errors.
+                    psF64 majorRange = majorMax - majorMin;
+                    if (majorRange == 0) {
+                        majorRange = 1;
+                    }
+                    psF64 minorRange = minorMax - minorMin;
+                    if (minorRange == 0) {
+                        minorRange = 1;
+                    }
+                    psF64 chisqRange = chisqMax - chisqMin;
+                    if (chisqRange == 0) {
+                        chisqRange = 1;
+                    }
+                    for (int k = 0; k < major->n; k++) {
+                        major->data.F64[k] = (major->data.F64[k] - majorMin) / majorRange;
+                        minor->data.F64[k] = (minor->data.F64[k] - minorMin) / minorRange;
+                        chisq->data.F64[k] = (chisq->data.F64[k] - chisqMin) / chisqRange;
+                    }
+
+                    // Fit chisq versus rMajor and rMinor
+                    psPolynomial2D *chisqFit = psPolynomial2DAlloc(PS_POLYNOMIAL_ORD, 2, 2);
+                    psPolynomial2D *fluxFit = psPolynomial2DAlloc(PS_POLYNOMIAL_ORD, 2, 2);
+                    chisqFit->coeffMask[2][2] = PS_POLY_MASK_SET;
+                    chisqFit->coeffMask[2][1] = PS_POLY_MASK_SET;
+                    chisqFit->coeffMask[1][2] = PS_POLY_MASK_SET;
+                    fluxFit->coeffMask[2][2] = PS_POLY_MASK_SET;
+                    fluxFit->coeffMask[2][1] = PS_POLY_MASK_SET;
+                    fluxFit->coeffMask[1][2] = PS_POLY_MASK_SET;
+
+                    bool goodFit = psVectorFitPolynomial2D (chisqFit, NULL, 0xff, chisq, NULL, major, minor);
+
+                    if (goodFit) {
+                        // find the axes for the minimum chisq from the formula
+                        psF64 **coeff = chisqFit->coeff;
+                        psF64 D = 4*coeff[2][0]*coeff[0][2] - coeff[1][1]*coeff[1][1];
+                        psF64 major0 = ((coeff[1][1]*coeff[0][1] - 2*coeff[0][2]*coeff[1][0]) / D) * majorRange + majorMin;
+                        psF64 minor0 = ((coeff[1][1]*coeff[1][0] - 2*coeff[2][0]*coeff[0][1]) / D) * minorRange + minorMin;
+
+                        // estimated chisq at the minimum
+                        psF64 chisq0 = psPolynomial2DEval(chisqFit, major0, minor0) * chisqRange + chisqMin;
+
+                        // now fit the flux ...
+                        bool goodFluxFit = psVectorFitPolynomial2D(fluxFit, NULL, 0xFF, flux, NULL, major, minor);
+
+                        // .. and compute flux at the minimum chisq position
+                        if (goodFluxFit) {
+                            flux0  = psPolynomial2DEval(fluxFit, major0, minor0);
+                        } else {
+                            flux0 = fluxBest;
+                        }
+
+#ifdef PRINTVALS
+                        fprintf (stderr, "%4d %3d %3ld | %6.3f %6.3f %6.3f %4.2f |  %6.3f %6.3f %6.3f %4.2f | %7.4f %7.4f %7.1f %7.1f\n", 
+                            outSrc->seq, min_k, major->n, R_MAJOR, fRMajorBest*R_MAJOR, major0, major0/R_MAJOR, R_MINOR, fRMinorBest*R_MINOR, minor0, minor0/R_MINOR, minChisq, chisq0, fluxBest, flux0);
+#endif 
+
+
+                        axes.major = major0;
+                        axes.minor = minor0;
+                        outSrc->modelEXT->chisq = chisq0;
+#ifdef DUMPVECTORS
+                        char fn[80];
+
+                        sprintf(fn, "vectors/%s.%05d.txt", goodFit ? "g" : "b", outSrc->seq);
+
+                        FILE *f = fopen(fn, "w");
+                        fprintf(f, "#major minor chisq i\n");
+                        for (int k = 0; k < chisq->n; k++) {
+                            fprintf(f, "%10.6f %10.6f %10.6f %5d\n", 
+                                major->data.F64[k]/R_MAJOR, minor->data.F64[k]/R_MINOR, chisq->data.F64[k], k);
+                        }
+                        fclose(f);
+#endif
+                    } else {
+                        outSrc->modelEXT->flags |= PM_MODEL_STATUS_NONCONVERGE;
+
+#ifdef PRINTVALS
+                        fprintf(stderr, "%4d %3d %3ld | %6.3f %6.3f %6.3f %6.3f bad fit\n", 
+                            outSrc->seq, min_k, major->n, R_MAJOR, fRMajorBest, R_MINOR, fRMinorBest);
+#endif
+                        psErrorClear();
+                        // psFree(outSrc->galaxyFits);
+
+                        // XXX drop the model since it is bogus? Perhaps we do this or use the nominal values
+                        // and add a flag
+#ifdef notnow
+                        psFree(outSrc->modelEXT);
+                        outSrc->modelEXT = 0;
+                        psFree(outSrc->modelFits);
+                        outSrc->modelFits = 0;
+#endif
+                    }
+                    psFree(chisqFit);
+                    psFree(major);
+                    psFree(minor);
+                    psFree(chisq);
+                    psFree(flux);
+                    psFree(dFlux);
+                } else {
+                    // No fit
+                    // Set the values based on the trial with the best chisq
+                    axes.major = R_MAJOR * fRMajorBest;
+                    axes.minor = R_MINOR * fRMinorBest;
+                    outSrc->modelEXT->chisq = minChisq; 
+                    flux0 = fluxBest;
+#ifdef PRINTVALS
+                    fprintf(stderr, "%4d %3d %3ld | %6.3f %6.3f %6.3f %6.3f skip fit\n", 
+                            outSrc->seq, min_k, 0L, R_MAJOR, fRMajorBest, R_MINOR, fRMinorBest);
+#endif
                 }
-                bool mdok;
-                psF32 rMajor = psMetadataLookupF32(&mdok, row, "R_MAJOR");
-                if (!mdok) {
-                    psError (PS_ERR_PROGRAMMING, true, "can't find R_MAJOR for object %d", outSrc->seq);
-                    psFree(outSrc);
-                    return NULL;
-                }
-                psF32 rMinor = psMetadataLookupF32(&mdok, row, "R_MINOR");
-                if (!mdok) {
-                    psError (PS_ERR_PROGRAMMING, true, "can't find R_MINOR for object %d", outSrc->seq);
-                    psFree(outSrc);
-                    return NULL;
-                }
-                axes.major = rMajor * options->rMajor->data.F32[min_j];
-                axes.minor = rMinor * options->rMinor->data.F32[min_j];
+                // now save the model parameters in the model structure
+
                 pmPSF_AxesToModel (outSrc->modelEXT->params->data.F32, axes, outSrc->modelEXT->type);
-                outSrc->modelEXT->chisq = minChisq; 
-                outSrc->modelEXT->mag = -2.5 * log10(outSrc->galaxyFits->Flux->data.F32[min_j]);
-                outSrc->modelEXT->magErr = 1.0 / 
-                    (outSrc->galaxyFits->Flux->data.F32[min_j]/outSrc->galaxyFits->dFlux->data.F32[min_j]); // 1 / SN
+
+                outSrc->modelEXT->mag = -2.5 * log10(flux0);
+                outSrc->modelEXT->magErr = dFlux0 / flux0; // 1 / SN
+                // XXX: should there be a different flag if we didn't do a fit of the chisq
+                outSrc->modelEXT->flags |= PM_MODEL_STATUS_FITTED;
             }
         }
@@ -367,24 +552,24 @@
     psMetadata *md = useAnalysis ? readout->analysis : recipe;
 
-    GETVAL(fRmajorMin, "GALAXY_SHAPES_FR_MAJOR_MIN");
-    GETVAL(fRmajorMax, "GALAXY_SHAPES_FR_MAJOR_MAX");
-    GETVAL(fRmajorDel, "GALAXY_SHAPES_FR_MAJOR_DEL");
-    GETVAL(fRminorMin, "GALAXY_SHAPES_FR_MINOR_MIN");
-    GETVAL(fRminorMax, "GALAXY_SHAPES_FR_MINOR_MAX");
-    GETVAL(fRminorDel, "GALAXY_SHAPES_FR_MINOR_DEL");
-
-    opt->numTrials = ceil((opt->fRmajorMax - opt->fRmajorMin + 0.5*opt->fRmajorDel) / opt->fRmajorDel) *
-                         ceil((opt->fRminorMax - opt->fRminorMin + 0.5*opt->fRminorDel) / opt->fRminorDel) ;
+    GETVAL(fRMajorMin, "GALAXY_SHAPES_FR_MAJOR_MIN");
+    GETVAL(fRMajorMax, "GALAXY_SHAPES_FR_MAJOR_MAX");
+    GETVAL(fRMajorDel, "GALAXY_SHAPES_FR_MAJOR_DEL");
+    GETVAL(fRMinorMin, "GALAXY_SHAPES_FR_MINOR_MIN");
+    GETVAL(fRMinorMax, "GALAXY_SHAPES_FR_MINOR_MAX");
+    GETVAL(fRMinorDel, "GALAXY_SHAPES_FR_MINOR_DEL");
+
+    opt->numTrials = ceil((opt->fRMajorMax - opt->fRMajorMin + 0.5*opt->fRMajorDel) / opt->fRMajorDel) *
+                         ceil((opt->fRMinorMax - opt->fRMinorMin + 0.5*opt->fRMinorDel) / opt->fRMinorDel) ;
 
     if (makeVectors) {
-        opt->rMinor = psVectorAlloc(opt->numTrials, PS_TYPE_F32);
-        opt->rMajor = psVectorAlloc(opt->numTrials, PS_TYPE_F32);
+        opt->fRMinor = psVectorAlloc(opt->numTrials, PS_TYPE_F32);
+        opt->fRMajor = psVectorAlloc(opt->numTrials, PS_TYPE_F32);
         int i = 0;
-        for (float fRmajor = opt->fRmajorMin; fRmajor < opt->fRmajorMax + 0.5*opt->fRmajorDel;
-                fRmajor += opt->fRmajorDel) {
-            for (float fRminor = opt->fRminorMin; fRminor < opt->fRminorMax + 0.5*opt->fRminorDel;
-                    fRminor += opt->fRminorDel) {
-                opt->rMinor->data.F32[i] = fRminor;
-                opt->rMajor->data.F32[i] = fRmajor;
+        for (float fRMajor = opt->fRMajorMin; fRMajor < opt->fRMajorMax + 0.5*opt->fRMajorDel;
+                fRMajor += opt->fRMajorDel) {
+            for (float fRMinor = opt->fRMinorMin; fRMinor < opt->fRMinorMax + 0.5*opt->fRMinorDel;
+                    fRMinor += opt->fRMinorDel) {
+                opt->fRMinor->data.F32[i] = fRMinor;
+                opt->fRMajor->data.F32[i] = fRMajor;
                 i++;
             }
@@ -392,6 +577,6 @@
         psAssert(i == opt->numTrials, "Something's wrong with my loop got %d entries expected %d", i, opt->numTrials);
     } else {
-        opt->rMinor = NULL;
-        opt->rMajor = NULL;
+        opt->fRMinor = NULL;
+        opt->fRMajor = NULL;
     }
         
@@ -413,10 +598,10 @@
     }
     CHECKVAL(options, thisReadoutsOptions, numTrials, "mismatched number of trials")
-    CHECKVAL(options, thisReadoutsOptions, fRmajorMin, "mismatched fRmajorMin")
-    CHECKVAL(options, thisReadoutsOptions, fRmajorMax, "mismatched fRmajorMax")
-    CHECKVAL(options, thisReadoutsOptions, fRmajorDel, "mismatched fRmajorDel")
-    CHECKVAL(options, thisReadoutsOptions, fRminorMin, "mismatched fRminorMin")
-    CHECKVAL(options, thisReadoutsOptions, fRminorMax, "mismatched fRminorMax")
-    CHECKVAL(options, thisReadoutsOptions, fRminorDel, "mismatched fRminorDel")
+    CHECKVAL(options, thisReadoutsOptions, fRMajorMin, "mismatched fRMajorMin")
+    CHECKVAL(options, thisReadoutsOptions, fRMajorMax, "mismatched fRMajorMax")
+    CHECKVAL(options, thisReadoutsOptions, fRMajorDel, "mismatched fRMajorDel")
+    CHECKVAL(options, thisReadoutsOptions, fRMinorMin, "mismatched fRMinorMin")
+    CHECKVAL(options, thisReadoutsOptions, fRMinorMax, "mismatched fRMinorMax")
+    CHECKVAL(options, thisReadoutsOptions, fRMinorDel, "mismatched fRMinorDel")
 
     return true;
