IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jul 17, 2014, 12:30:45 PM (12 years ago)
Author:
eugene
Message:

merge changes (from past YEAR) into trunk

Location:
branches/eam_branches/ipp-ops-20130712/psphot
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-ops-20130712/psphot

    • Property svn:mergeinfo deleted
  • branches/eam_branches/ipp-ops-20130712/psphot/src

    • Property svn:ignore
      •  

        old new  
        2424psphotModelTest
        2525psphotMinimal
         26psphotFullForce
         27psmakecff
         28psphotFullForceSummary
    • Property svn:mergeinfo deleted
  • branches/eam_branches/ipp-ops-20130712/psphot/src/psphotSourceFits.c

    r35769 r37066  
    1919static int NfitIterPCM = 0;
    2020static int NfitPixPCM = 0;
     21
     22bool psphotPCMfitCheckSize (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, float psfSize);
     23bool psphotPCMfitRetry (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, float psfSize);
    2124
    2225bool psphotFitInit (int nThreads) {
     
    559562
    560563# define TIMING 0
     564# define EXTRA_VERBOSE 0
     565
     566bool psphotSersicModelGuessPCM (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, float psfSize);
     567bool psphotFitSersicShapeAndIndex (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
     568bool psphotFitSersicShapeAndIndexGrid (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
     569bool psphotFitSersicShapeAndIndexGridAuto (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
    561570
    562571pmModel *psphotFitPCM (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     
    573582    maskVal |= markVal;
    574583
    575     // allocate the model
     584    // allocate the model (this can only fail on a config error)
    576585    pmModel *model = pmModelAlloc(modelType);
    577     if (!model) {
    578         return NULL;
    579     }
    580 
    581     float t1, t2, t4, t5;
     586    psAssert (model, "invalid extended model name");
     587
     588    float t1, t2, t3, t4, t5;
     589    t1 = t2 = t3 = t4 = t5 = 0.0;
    582590    if (TIMING) { psTimerStart ("psphotFitPCM"); }
     591
     592    // if we are ever (in a given psphot implementation) going to fit a parameter, we must set the options here to include
     593    // that parameter (otherwise pmPCMupdate will fail to allocate the dmodelFlux image)
     594    // thus, if the sersic analysis below uses an index fit, need to use this EXT_AND_SKY mode for init
     595
     596    options.mode = PM_SOURCE_FIT_EXT;
     597    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
     598        options.mode = PM_SOURCE_FIT_EXT_AND_SKY;
     599    }
     600    if (modelType == pmModelClassGetType("PS_MODEL_DEV")) {
     601        options.mode = PM_SOURCE_FIT_SHAPE;
     602        options.mode = PM_SOURCE_FIT_EXT_AND_SKY;
     603    }
     604    if (modelType == pmModelClassGetType("PS_MODEL_EXP")) {
     605        options.mode = PM_SOURCE_FIT_EXT_AND_SKY;
     606    }
    583607
    584608    pmPCMdata *pcm = pmPCMinit (source, &options, model, maskVal, psfSize);
     
    594618    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
    595619        // use the source moments, etc to guess basic model parameters
    596         if (!psphotSersicModelClassGuessPCM (pcm, source)) {
     620        if (!psphotSersicModelGuessPCM (pcm, source, maskVal, psfSize)) {
    597621            psFree (pcm);
    598             model->flags |= PM_MODEL_STATUS_BADARGS;
     622            model->flags |= PM_MODEL_SERSIC_PCM_FAIL_GUESS;
     623            return model;
     624        }
     625        if (TIMING) { t2 = psTimerMark ("psphotFitPCM"); }
     626
     627        // psphotFitSersicShapeAndIndex (pcm, readout, source, fitOptions, maskVal, markVal, psfSize);
     628        options.mode = PM_SOURCE_FIT_NO_INDEX;
     629        if (!psphotFitSersicShapeAndIndexGridAuto (pcm, readout, source, &options, maskVal, markVal, psfSize)) {
     630            psFree (pcm);
     631            model->flags |= PM_MODEL_SERSIC_PCM_FAIL_GRID;
     632            psError(PS_ERR_UNKNOWN, true, "Failed to find a index & shape");
     633            psErrorClear (); // clear the polynomial error
    599634            return model;
    600635        }
     
    603638        if (!pmSourceModelGuessPCM (pcm, source, maskVal, markVal)) {
    604639            psFree (pcm);
    605             model->flags |= PM_MODEL_STATUS_BADARGS;
     640            model->flags |= PM_MODEL_PCM_FAIL_GUESS;
    606641            return model;
    607642        }
    608643    }
    609644
    610     if (TIMING) { t2 = psTimerMark ("psphotFitPCM"); }
    611 
    612     if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
    613         options.mode = PM_SOURCE_FIT_NO_INDEX;
    614     } else {
    615         options.mode = PM_SOURCE_FIT_EXT;
    616     }
    617     // update the pcm elements if we have changed the circumstance (options.mode or source->pixels)
    618     pmPCMupdate(pcm, source, &options, model);
    619     if (TIMING) { t4 = psTimerMark ("psphotFitPCM"); }
     645    if (TIMING) { t3 = psTimerMark ("psphotFitPCM"); }
    620646
    621647    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
     
    623649    NfitIterPCM += pcm->modelConv->nIter;
    624650    NfitPixPCM += pcm->modelConv->nDOF;
     651    if (TIMING) { t4 = psTimerMark ("psphotFitPCM"); }
     652
     653    // XXX we might make this more efficient by setting NITER to be fairly small.  if we hit the iteration
     654    // limit, then we could do a small grid search on the size and try again from the best fit
     655
     656    if (options.isInteractive) psphotPCMfitCheckSize (pcm, source, maskVal, psfSize);
     657    // if (pcm->modelConv->nIter == fitOptions->nIter) {
     658    //  psphotPCMfitRetry (pcm, source, &options, maskVal, markVal, psfSize);
     659    // }
    625660    if (TIMING) { t5 = psTimerMark ("psphotFitPCM"); }
    626661
    627662    if (TIMING) {
    628663        int nPixBig = source->pixels->numCols * source->pixels->numRows;
    629         fprintf (stderr, "psphotFitPCM : nIter: %2d, radius: %6.1f, npix: %5d of %5d, t1: %6.4f, t2: %6.4f, t4: %6.4f, t5: %6.4f\n", model->nIter, model->fitRadius, model->nPix, nPixBig, t1, t2, t4, t5);
    630     }
    631 
    632     // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
     664        fprintf (stderr, "psphotFitPCM : nIter: %2d, radius: %6.1f, npix: %5d of %5d, t1: %6.4f, t2: %6.4f, t3: %6.4f, t4: %6.4f, t5: %6.4f\n", model->nIter, model->fitRadius, model->nPix, nPixBig, t1, t2, t3, t4, t5);
     665    }
     666    if (EXTRA_VERBOSE && !TIMING) {
     667        int nPixBig = source->pixels->numCols * source->pixels->numRows;
     668        float *PAR = model->params->data.F32;
     669        fprintf (stderr, "source %d : %f - %f %f - %f %f %f - %f | nIter: %2d, radius: %6.1f, npix: %5d of %5d, chisq %f\n", source->id, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1], model->nIter, model->fitRadius, model->nPix, nPixBig, model->chisqNorm);
     670    }
     671
    633672    psFree (pcm);
    634673
     
    661700        model->params->data.F32[PM_PAR_7] = 0.5/indexGuess[i];
    662701
    663         if (!model->modelGuess(model, source, maskVal, markVal)) {
     702        if (!model->class->modelGuess(model, source, maskVal, markVal)) {
    664703            model->flags |= PM_MODEL_STATUS_BADARGS;
    665704            return false;
     
    684723    model->flags = PM_MODEL_STATUS_NONE; // do not attempt to handle failures here, let the next iteration deal with it
    685724    model->params->data.F32[PM_PAR_7] = 0.5/indexGuess[iMin];
    686     model->modelGuess(model, source, maskVal, markVal);
     725    model->class->modelGuess(model, source, maskVal, markVal);
    687726
    688727    return true;
     
    713752        model->params->data.F32[PM_PAR_7] = indexGuess[i];
    714753       
    715         if (!model->modelGuess(model, source, maskVal, markVal)) {
     754        if (!model->class->modelGuess(model, source, maskVal, markVal)) {
    716755            model->flags |= PM_MODEL_STATUS_BADARGS;
    717756            return false;
     
    748787    return true;
    749788}
     789
     790// 0.5 / n for (1.0, 1.25, 1.66, 2.0, 3.33, 4.0)
     791// float indexGuessInv[] = {0.5, 0.4, 0.3, 0.25, 0.20, 0.15, 0.125};
     792
     793// 0.5 / n for (0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0)
     794float indexGuessInv[] = {1.00, 0.50, 0.333, 0.25, 0.166, 0.125, 0.10, 0.0833};
     795float indexGuessR1q[] = {1.06, 1.19, 1.335, 1.48, 1.840, 2.290, 2.84, 3.5300};
     796# define N_INDEX_GUESS_INV 8
     797
     798// we are going to guess in fractions about the R1-based guess
     799float reffGuess[] = {0.8, 0.9, 1.0, 1.12, 1.25};
     800# define N_REFF_GUESS 5
     801
     802// A sersic model is very sensitive to the index.  attempt to find the index first by grid search in just the index
     803// for a sersic model, attempt to fit just the index and normalization with a modest number of iterations
     804bool psphotSersicModelGuessPCM (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, float psfSize) {
     805
     806    // we get a reasonable guess from:
     807    // * Reff = Kron R1 / Q(index) -- Q comes from Graham & Driver
     808    // * Rmajor / Rminor & Theta from moments
     809    // * Io from total Kron flux
     810
     811    // the guesses are used to fill in PAR:
     812    psF32 *PAR = pcm->modelConv->params->data.F32;
     813
     814    // convert the moments to Major,Minor,Theta
     815    psEllipseMoments moments;
     816
     817    if (!isfinite(source->moments->Mrf)) return false;
     818    if (!isfinite(source->moments->Mxx)) return false;
     819    if (!isfinite(source->moments->Mxy)) return false;
     820    if (!isfinite(source->moments->Myy)) return false;
     821
     822    moments.x2 = source->moments->Mxx;
     823    moments.y2 = source->moments->Myy;
     824    moments.xy = source->moments->Mxy;
     825   
     826    // limit axis ratio < 20.0
     827    psEllipseAxes momentAxes = psEllipseMomentsToAxes (moments, 20.0);
     828
     829    // set the model position
     830    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     831      return false;
     832    }
     833
     834    // sky is zero (no longer fitted, but not yet deprecated)
     835    PAR[PM_PAR_SKY]  = 0.0;
     836
     837    // for the index loop, use Io = 1.0, use fitted values to determine Io
     838    PAR[PM_PAR_I0] = 1.0;
     839
     840    float xMin = NAN;
     841    float iMin = NAN;
     842    float sMin = NAN;
     843    float rMin = NAN;
     844
     845    // loop over index and Reff, keeping the ARatio and Theta constant?
     846    // loop over index guesses and find the best fit
     847    for (int j = 0; j < N_REFF_GUESS; j++) {
     848        for (int i = 0; i < N_INDEX_GUESS_INV; i++) {
     849            PAR[PM_PAR_7] = indexGuessInv[i];
     850
     851            psEllipseAxes guessAxes;
     852            guessAxes.major = reffGuess[j] * source->moments->Mrf / indexGuessR1q[i];
     853            guessAxes.minor = guessAxes.major * (momentAxes.minor / momentAxes.major);
     854            guessAxes.theta = momentAxes.theta;
     855
     856            if (!isfinite(guessAxes.major)) return false;
     857            if (!isfinite(guessAxes.minor)) return false;
     858            if (!isfinite(guessAxes.theta)) return false;
     859
     860            // convert the major,minor,theta to shape parameters for an Reff-like model
     861            pmModelAxesToParams (&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], guessAxes, true);
     862
     863            // generated the modelFlux
     864            // XXX note that this does not add sky to model
     865            pmPCMMakeModel (source, pcm->modelConv, pcm->nsigma, maskVal, psfSize);
     866       
     867            float YY = 0.0;
     868            float YM = 0.0;
     869            float MM = 0.0;
     870            bool usePoisson = false;
     871
     872            for (int iy = 0; iy < source->pixels->numRows; iy++) {
     873                for (int ix = 0; ix < source->pixels->numCols; ix++) {
     874                    // skip masked points
     875                    if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
     876                        continue;
     877                    }
     878                    // skip zero-variance points
     879                    if (source->variance->data.F32[iy][ix] == 0) {
     880                        continue;
     881                    }
     882                    // skip nan value points
     883                    if (!isfinite(source->pixels->data.F32[iy][ix])) {
     884                        continue;
     885                    }
     886
     887                    float fy = source->pixels->data.F32[iy][ix];
     888                    float fm = source->modelFlux->data.F32[iy][ix];
     889                    float wt = (usePoisson) ? 1.0 / source->variance->data.F32[iy][ix] : 1.0;
     890
     891                    YY += PS_SQR(fy) * wt;
     892                    YM += fm * fy * wt;
     893                    MM += PS_SQR(fm) * wt;
     894                }
     895            }
     896
     897            float Io = YM / MM;
     898            float Chisq = YY - 2 * Io * YM + Io * Io * MM;
     899            if (isnan(xMin) || (Chisq < xMin)) {
     900                xMin = Chisq;
     901                iMin = Io;
     902                sMin = indexGuessInv[i];
     903                rMin = reffGuess[j] / indexGuessR1q[i];
     904            }
     905            if (EXTRA_VERBOSE) {
     906                fprintf (stderr, "%d | %f %f %f %f | %f %f %f %f", i, indexGuessInv[i], reffGuess[j], Io, Chisq, sMin, rMin, iMin, xMin);
     907                fprintf (stderr, "\n");
     908            }
     909        }
     910    }
     911
     912    {
     913        psEllipseAxes guessAxes;
     914        guessAxes.major = rMin * source->moments->Mrf;
     915        guessAxes.minor = guessAxes.major * (momentAxes.minor / momentAxes.major);
     916        guessAxes.theta = momentAxes.theta;
     917
     918        if (!isfinite(guessAxes.major)) return false;
     919        if (!isfinite(guessAxes.minor)) return false;
     920        if (!isfinite(guessAxes.theta)) return false;
     921
     922        // convert the major,minor,theta to shape parameters for an Reff-like model
     923        pmModelAxesToParams (&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], guessAxes, true);
     924    }
     925
     926    PAR[PM_PAR_I0] = iMin;
     927    PAR[PM_PAR_7] = sMin;
     928
     929    return true;
     930}
     931
     932// we have a set of guess parameters, do a small number of iterations fitting only SHAPE then only INDEX
     933bool psphotFitSersicShapeAndIndex (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     934
     935    pmModel *model = pcm->modelConv;
     936
     937    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
     938
     939    pmSourceFitOptions options = *fitOptions;
     940   
     941    for (int i = 0; i < 3; i++) {
     942      // fit EXT (not PSF) model (set/unset the pixel mask)
     943      options.mode = PM_SOURCE_FIT_SHAPE;
     944      options.nIter = 2;
     945
     946      // update the pcm elements if we have changed the circumstance (here, options.mode)
     947      pmPCMupdate(pcm, source, &options, model);
     948     
     949      pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     950      if (EXTRA_VERBOSE) {
     951        float *PAR = model->params->data.F32;
     952        fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     953      }
     954     
     955      // fit EXT (not PSF) model (set/unset the pixel mask)
     956      options.mode = PM_SOURCE_FIT_INDEX;
     957      // options.mode = PM_SOURCE_FIT_EXT_AND_SKY;
     958      options.nIter = 30;
     959     
     960      // update the pcm elements if we have changed the circumstance (here, options.mode)
     961      pmPCMupdate(pcm, source, &options, model);
     962     
     963      pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     964      if (EXTRA_VERBOSE) {
     965        float *PAR = model->params->data.F32;
     966        fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     967      }
     968    }
     969
     970    // update the pcm elements if we have changed the circumstance (here, options.mode)
     971    pmPCMupdate(pcm, source, fitOptions, model);
     972
     973    return true;
     974}
     975
     976// we have a set of guess parameters, do a small number of iterations fitting only SHAPE then only INDEX
     977bool psphotFitSersicShapeAndIndexGridAuto (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     978
     979    pmModel *model = pcm->modelConv;
     980
     981    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
     982
     983    pmSourceFitOptions options = *fitOptions;
     984   
     985    psF32 *PAR = pcm->modelConv->params->data.F32;
     986
     987    options.mode = PM_SOURCE_FIT_SHAPE;
     988    options.nIter = 7;
     989   
     990    // update the pcm elements if we have changed the circumstance (here, options.mode)
     991    pmPCMupdate(pcm, source, &options, model);
     992   
     993    // we have been provided a guess at the index (P[7]) from the list of indexGuessInv
     994
     995    // find the matching indexGuessInv
     996    int nStart = -1;
     997    for (int i = 0; i < N_INDEX_GUESS_INV; i++) {
     998        if (fabs(PAR[PM_PAR_7] - indexGuessInv[i]) < 0.01) {
     999            nStart = i;
     1000            break;
     1001        }
     1002    }
     1003    if (nStart == -1) {
     1004        fprintf (stderr, "WARNING: could not find start guess %f\n", PAR[PM_PAR_7]);
     1005        return false;
     1006    }
     1007
     1008    psVector *chi2 = psVectorAllocEmpty (16, PS_TYPE_F32);
     1009    psVector *Sidx = psVectorAllocEmpty (16, PS_TYPE_F32);
     1010
     1011    float Sm = NAN, Sp = NAN, So = NAN;
     1012    if (nStart == 0) {
     1013        Sm = indexGuessInv[nStart];
     1014        So = 0.5*(indexGuessInv[nStart + 1] + indexGuessInv[nStart]);
     1015        Sp = indexGuessInv[nStart + 1];
     1016    } else if (nStart == N_INDEX_GUESS_INV - 1) {
     1017        Sp = indexGuessInv[nStart];
     1018        So = 0.5*(indexGuessInv[nStart - 1] + indexGuessInv[nStart]);
     1019        Sm = indexGuessInv[nStart - 1];
     1020    } else {
     1021        Sm = 0.5*(indexGuessInv[nStart - 1] + indexGuessInv[nStart]);
     1022        So = indexGuessInv[nStart];
     1023        Sp = 0.5*(indexGuessInv[nStart + 1] + indexGuessInv[nStart]);
     1024    }
     1025   
     1026    PAR[PM_PAR_7] = Sm;
     1027    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1028    if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1029    psVectorAppend (Sidx, 100*PAR[PM_PAR_7]);
     1030    psVectorAppend (chi2, model->chisqNorm);
     1031
     1032    PAR[PM_PAR_7] = So;
     1033    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1034    if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1035    psVectorAppend (Sidx, 100*PAR[PM_PAR_7]);
     1036    psVectorAppend (chi2, model->chisqNorm);
     1037
     1038    PAR[PM_PAR_7] = Sp;
     1039    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1040    if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1041    psVectorAppend (Sidx, 100*PAR[PM_PAR_7]);
     1042    psVectorAppend (chi2, model->chisqNorm);
     1043
     1044    psPolynomial1D *poly = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 2);
     1045    if (!psVectorFitPolynomial1D (poly, NULL, 0, chi2, NULL, Sidx)) {
     1046        psError(PS_ERR_UNKNOWN, true, "Failed to find a good chisq parabola");
     1047        psFree (chi2);
     1048        psFree (Sidx);
     1049        psFree (poly);
     1050        return false;
     1051    }
     1052
     1053    // where is the minimum of this polynomial fit?
     1054    float Smin = -0.5 * poly->coeff[1] / poly->coeff[2] / 100.0;
     1055
     1056    // constrain Smin to be in a valid range: allow the fitted range to go a bit beyond the 3 trial points, but no further
     1057    float Smx = Sm - 0.25*(So - Sm);
     1058    float Spx = Sp + 0.25*(Sp - So);
     1059    Smin = PS_MAX(PS_MIN(Smin, Smx), Spx);
     1060    PAR[PM_PAR_7] = Smin;
     1061
     1062    // XXX I could set the error on PAR_7 here if I knew how to roughly convert these chisq values to true chisq values
     1063
     1064    // return to the original fitting mode (fitOptions)
     1065    pmPCMupdate(pcm, source, fitOptions, model);
     1066
     1067    psFree (chi2);
     1068    psFree (Sidx);
     1069    psFree (poly);
     1070
     1071    return true;
     1072}
     1073
     1074 
     1075// we have a set of guess parameters, do a small number of iterations fitting only SHAPE then only INDEX
     1076bool psphotFitSersicShapeAndIndexGridAutoScaled (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     1077
     1078    pmModel *model = pcm->modelConv;
     1079
     1080    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
     1081
     1082    pmSourceFitOptions options = *fitOptions;
     1083   
     1084    psF32 *PAR = pcm->modelConv->params->data.F32;
     1085
     1086    options.mode = PM_SOURCE_FIT_SHAPE;
     1087    options.nIter = 5;
     1088   
     1089    // update the pcm elements if we have changed the circumstance (here, options.mode)
     1090    pmPCMupdate(pcm, source, &options, model);
     1091   
     1092    float parStart[8];
     1093    for (int i = 0; i < 8; i++) parStart[i] = PAR[i];
     1094
     1095    // we start with a guess at the index (P[7])
     1096
     1097    // get chisq for P[7], P[7]*1.1, P[7]*1.25 (or *0.75 depending on the result of 1.1)
     1098
     1099    psVector *chi2 = psVectorAllocEmpty (16, PS_TYPE_F32);
     1100    psVector *Sidx = psVectorAllocEmpty (16, PS_TYPE_F32);
     1101
     1102    PAR[PM_PAR_7] = parStart[7];
     1103    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1104      if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1105    psVectorAppend (Sidx, 100*PAR[PM_PAR_7]);
     1106    psVectorAppend (chi2, model->chisqNorm);
     1107
     1108    float fI = 1.1;
     1109    PAR[PM_PAR_7] = parStart[7]*fI;
     1110    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1111      if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1112    psVectorAppend (Sidx, 100*PAR[PM_PAR_7]);
     1113    psVectorAppend (chi2, model->chisqNorm);
     1114
     1115    if (chi2->data.F32[1] < chi2->data.F32[0]) {
     1116      fI = 1.3;
     1117    } else {
     1118      fI = 1.0 / 1.3;
     1119    }
     1120   
     1121    PAR[PM_PAR_7] = parStart[7]*fI;
     1122    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1123      if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1124    psVectorAppend (Sidx, 100*PAR[PM_PAR_7]);
     1125    psVectorAppend (chi2, model->chisqNorm);
     1126
     1127    // can we fit the 3 pts with a parabola?
     1128    int nTry = 0;
     1129    psPolynomial1D *poly = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 2);
     1130    while (!psVectorFitPolynomial1D (poly, NULL, 0, chi2, NULL, Sidx)) {
     1131      psErrorClear (); // clear the polynomial error
     1132      if (nTry > 4) {
     1133        psError(PS_ERR_UNKNOWN, true, "Failed to find a good chisq parabola");
     1134        psFree (chi2);
     1135        psFree (Sidx);
     1136        psFree (poly);
     1137        return false;
     1138      }
     1139      fI = (fI < 1.0) ? fI / 1.3 : fI * 1.3;
     1140      PAR[PM_PAR_7] = parStart[7]*fI;
     1141      pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1142      if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1143      psVectorAppend (Sidx, 100*PAR[PM_PAR_7]);
     1144      psVectorAppend (chi2, model->chisqNorm);
     1145      nTry ++;
     1146    }
     1147
     1148    // where is the minimum of this polynomial fit?
     1149    float Smin = -0.5 * poly->coeff[1] / poly->coeff[2] / 100.0;
     1150
     1151    // constrain Smin to be in a valid range (1.0 - 0.1, corresponding to 0.5 (Gauss) to 5.0 (slightly peakier than Dev)
     1152    Smin = PS_MAX(PS_MIN(Smin, 1.0), 0.1);
     1153    PAR[PM_PAR_7] = Smin;
     1154
     1155    // pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1156    // if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1157   
     1158    //// for (int i = 0; i < 8; i++) PAR[i] = parStart[i];
     1159    ////
     1160    //// for (float fI = 0.0; fI < 0.15; fI += 0.01) {
     1161    ////   PAR[PM_PAR_7] = parStart[7] - fI;
     1162    ////
     1163    ////   // fit EXT (not PSF) model (set/unset the pixel mask)
     1164    ////   
     1165    ////   pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1166    ////   if (TIMING) {
     1167    ////        float *PAR = model->params->data.F32;
     1168    ////        fprintf (stderr, "%d %f : %f - %f %f %f - %f\n", model->nIter, model->chisqNorm, PAR[7], PAR[4], PAR[5], PAR[6], PAR[1]);
     1169    ////   }
     1170    //// }
     1171
     1172    // return to the original fitting mode (fitOptions)
     1173    pmPCMupdate(pcm, source, fitOptions, model);
     1174
     1175    psFree (chi2);
     1176    psFree (Sidx);
     1177    psFree (poly);
     1178
     1179    return true;
     1180}
     1181
     1182 
     1183// we have a set of guess parameters, do a small number of iterations fitting only SHAPE then only INDEX
     1184bool psphotFitSersicShapeAndIndexGrid (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     1185
     1186    pmModel *model = pcm->modelConv;
     1187
     1188    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
     1189
     1190    pmSourceFitOptions options = *fitOptions;
     1191   
     1192    psF32 *PAR = pcm->modelConv->params->data.F32;
     1193
     1194    options.mode = PM_SOURCE_FIT_SHAPE;
     1195    options.nIter = 10;
     1196   
     1197    // update the pcm elements if we have changed the circumstance (here, options.mode)
     1198    pmPCMupdate(pcm, source, &options, model);
     1199   
     1200    psVector *chi2 = psVectorAllocEmpty (16, PS_TYPE_F32);
     1201    psVector *Sidx = psVectorAllocEmpty (16, PS_TYPE_F32);
     1202
     1203    float par7[] = {0.100, 0.125, 0.150, 0.175, 0.200, 0.225, 0.250};
     1204    for (int i = 0; i < 7; i++) {
     1205      PAR[PM_PAR_7] = par7[i];
     1206      pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1207      if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1208      psVectorAppend (Sidx, PAR[PM_PAR_7]);
     1209      psVectorAppend (chi2, model->chisqNorm);
     1210    }
     1211
     1212    psPolynomial1D *poly = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 2);
     1213    if (!psVectorFitPolynomial1D (poly, NULL, 0, chi2, NULL, Sidx)) {
     1214      psError(PS_ERR_UNKNOWN, true, "Failed to find a good chisq parabola");
     1215      psFree (chi2);
     1216      psFree (Sidx);
     1217      psFree (poly);
     1218      return false;
     1219    }
     1220
     1221    // where is the minimum of this polynomial fit?
     1222    fprintf (stderr, "fit1d: %f + %f x + %f x^2\n", poly->coeff[0], poly->coeff[1], poly->coeff[2]);
     1223    float Smin = -0.5 * poly->coeff[1] / poly->coeff[2];
     1224
     1225    // constrain Smin to be in a valid range (1.0 - 0.1, corresponding to 0.5 (Gauss) to 5.0 (slightly peakier than Dev)
     1226    Smin = PS_MAX(PS_MIN(Smin, 1.0), 0.1);
     1227    PAR[PM_PAR_7] = Smin;
     1228    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1229    if (EXTRA_VERBOSE) fprintf (stderr, "%d >>> %d %f : %f - %f %f - %f %f %f - %f\n", source->id, model->nIter, model->chisqNorm, PAR[7], PAR[2], PAR[3], PAR[4], PAR[5], PAR[6], PAR[1]);
     1230   
     1231    //// for (int i = 0; i < 8; i++) PAR[i] = parStart[i];
     1232    ////
     1233    //// for (float fI = 0.0; fI < 0.15; fI += 0.01) {
     1234    ////   PAR[PM_PAR_7] = parStart[7] - fI;
     1235    ////
     1236    ////   // fit EXT (not PSF) model (set/unset the pixel mask)
     1237    ////   
     1238    ////   pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
     1239    ////   if (TIMING) {
     1240    ////        float *PAR = model->params->data.F32;
     1241    ////        fprintf (stderr, "%d %f : %f - %f %f %f - %f\n", model->nIter, model->chisqNorm, PAR[7], PAR[4], PAR[5], PAR[6], PAR[1]);
     1242    ////   }
     1243    //// }
     1244
     1245    // return to the original fitting mode (fitOptions)
     1246    pmPCMupdate(pcm, source, fitOptions, model);
     1247
     1248    psFree (chi2);
     1249    psFree (Sidx);
     1250    psFree (poly);
     1251
     1252    return true;
     1253}
     1254
     1255// # define N_REFF_CHECK 11
     1256// float drefCheck[] = {-0.02, -0.04, -0.06, 0.0, 0.85, 0.90, 0.95, 1.00, 1.05, 1.10, 1.15, 1.20, 1.25};
     1257
     1258// we have an initial fit, check to see if the current size is besst
     1259bool psphotPCMfitCheckSize (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, float psfSize) {
     1260
     1261    // PAR is already at my current best guess
     1262    psF32 *PAR = pcm->modelConv->params->data.F32;
     1263
     1264    // store best guess as a shape
     1265    psEllipseAxes centerAxes;
     1266    pmModelParamsToAxes (&centerAxes, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], true);
     1267
     1268    float xMin = NAN;
     1269    float iMin = NAN;
     1270    float rMin = NAN;
     1271
     1272    // loop over Reff, keeping the ARatio and Theta constant
     1273    for (int j = -4; j <= 4; j++) {
     1274
     1275        float dref = j * 0.01;
     1276
     1277        psEllipseAxes guessAxes;
     1278        guessAxes.major = centerAxes.major + dref;
     1279        guessAxes.minor = guessAxes.major * centerAxes.minor / centerAxes.major;
     1280        guessAxes.theta = centerAxes.theta;
     1281
     1282        if (!isfinite(guessAxes.major)) return false;
     1283        if (!isfinite(guessAxes.minor)) return false;
     1284        if (!isfinite(guessAxes.theta)) return false;
     1285
     1286        // convert the major,minor,theta to shape parameters for an Reff-like model
     1287        pmModelAxesToParams (&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], guessAxes, true);
     1288
     1289        // generated the modelFlux
     1290            // XXX note that this does not add sky to model
     1291        pmPCMMakeModel (source, pcm->modelConv, pcm->nsigma, maskVal, psfSize);
     1292       
     1293        float YY = 0.0;
     1294        float YM = 0.0;
     1295        float MM = 0.0;
     1296        bool usePoisson = false;
     1297
     1298        for (int iy = 0; iy < source->pixels->numRows; iy++) {
     1299            for (int ix = 0; ix < source->pixels->numCols; ix++) {
     1300                // skip masked points
     1301                if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
     1302                    continue;
     1303                }
     1304                // skip zero-variance points
     1305                if (source->variance->data.F32[iy][ix] == 0) {
     1306                    continue;
     1307                }
     1308                // skip nan value points
     1309                if (!isfinite(source->pixels->data.F32[iy][ix])) {
     1310                    continue;
     1311                }
     1312
     1313                float fy = source->pixels->data.F32[iy][ix];
     1314                float fm = source->modelFlux->data.F32[iy][ix];
     1315                float wt = (usePoisson) ? 1.0 / source->variance->data.F32[iy][ix] : 1.0;
     1316
     1317                YY += PS_SQR(fy) * wt;
     1318                YM += fm * fy * wt;
     1319                MM += PS_SQR(fm) * wt;
     1320            }
     1321        }
     1322
     1323        float Io = YM / MM;
     1324        float Chisq = YY - 2 * Io * YM + Io * Io * MM;
     1325        if (isnan(xMin) || (Chisq < xMin)) {
     1326            xMin = Chisq;
     1327            iMin = Io;
     1328            rMin = dref;
     1329        }
     1330        // fprintf (stderr, "%d | %f %f %f | %f %f %f\n", j, dref, Io, Chisq, rMin, iMin, xMin);
     1331    }
     1332
     1333    psEllipseAxes guessAxes;
     1334    guessAxes.major = centerAxes.major + rMin;
     1335    guessAxes.minor = guessAxes.major * centerAxes.minor / centerAxes.major;
     1336    guessAxes.theta = centerAxes.theta;
     1337
     1338    if (!isfinite(guessAxes.major)) return false;
     1339    if (!isfinite(guessAxes.minor)) return false;
     1340    if (!isfinite(guessAxes.theta)) return false;
     1341
     1342    // convert the major,minor,theta to shape parameters for an Reff-like model
     1343    pmModelAxesToParams (&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], guessAxes, true);
     1344    PAR[PM_PAR_I0] = iMin;
     1345
     1346    return true;
     1347}
     1348
     1349// we have an initial fit, check to see if the current size is besst
     1350bool psphotPCMfitRetry (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, float psfSize) {
     1351
     1352    // PAR is already at my current best guess
     1353    psF32 *PAR = pcm->modelConv->params->data.F32;
     1354
     1355    // store best guess as a shape
     1356    psEllipseAxes centerAxes;
     1357    pmModelParamsToAxes (&centerAxes, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], true);
     1358
     1359    // retry with axes smaller by 1 pixel
     1360    psEllipseAxes guessAxes;
     1361    guessAxes.major = centerAxes.major - 0.08;
     1362    guessAxes.minor = guessAxes.major * centerAxes.minor / centerAxes.major;
     1363    guessAxes.theta = centerAxes.theta;
     1364
     1365    if (!isfinite(guessAxes.major)) return false;
     1366    if (!isfinite(guessAxes.minor)) return false;
     1367    if (!isfinite(guessAxes.theta)) return false;
     1368
     1369    // convert the major,minor,theta to shape parameters for an Reff-like model
     1370    pmModelAxesToParams (&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], guessAxes, true);
     1371
     1372    // generated the modelFlux
     1373            // XXX note that this does not add sky to model
     1374    pmPCMMakeModel (source, pcm->modelConv, pcm->nsigma, maskVal, psfSize);
     1375       
     1376    float YY = 0.0;
     1377    float YM = 0.0;
     1378    float MM = 0.0;
     1379    bool usePoisson = false;
     1380
     1381    for (int iy = 0; iy < source->pixels->numRows; iy++) {
     1382        for (int ix = 0; ix < source->pixels->numCols; ix++) {
     1383            // skip masked points
     1384            if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
     1385                continue;
     1386            }
     1387            // skip zero-variance points
     1388            if (source->variance->data.F32[iy][ix] == 0) {
     1389                continue;
     1390            }
     1391            // skip nan value points
     1392            if (!isfinite(source->pixels->data.F32[iy][ix])) {
     1393                continue;
     1394            }
     1395
     1396            float fy = source->pixels->data.F32[iy][ix];
     1397            float fm = source->modelFlux->data.F32[iy][ix];
     1398            float wt = (usePoisson) ? 1.0 / source->variance->data.F32[iy][ix] : 1.0;
     1399
     1400            YY += PS_SQR(fy) * wt;
     1401            YM += fm * fy * wt;
     1402            MM += PS_SQR(fm) * wt;
     1403        }
     1404    }
     1405
     1406    float Io = YM / MM;
     1407    PAR[PM_PAR_I0] = Io;
     1408
     1409    pmSourceFitPCM (pcm, source, fitOptions, maskVal, markVal, psfSize);  // NOTE : 1687 allocs in here
     1410
     1411    return true;
     1412}
     1413
     1414
Note: See TracChangeset for help on using the changeset viewer.