IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 5255


Ignore:
Timestamp:
Oct 10, 2005, 9:53:54 AM (21 years ago)
Author:
gusciora
Message:

A fairly large check-in. This incorporates must of Eugene's mods to
the object detection routines.

Location:
trunk/psModules
Files:
12 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/objects/Makefile.am

    r5170 r5255  
    33libpsmoduleobjects_la_CPPFLAGS = $(SRCINC) $(PSMODULE_CFLAGS)
    44libpsmoduleobjects_la_LDFLAGS  = -release $(PACKAGE_VERSION)
    5 libpsmoduleobjects_la_SOURCES  = pmObjects.c
     5libpsmoduleobjects_la_SOURCES  = \
     6    pmObjects.c \
     7    pmPSF.c \
     8    pmPSFtry.c \
     9    pmModelGroup.c \
     10    psModulesUtils.c \
     11    psLibUtils.c \
     12    psEllipse.c
    613
    714psmoduleincludedir = $(includedir)
    815psmoduleinclude_HEADERS = \
    9   pmObjects.h
     16    pmObjects.h \
     17    pmPSF.h \
     18    pmPSFtry.h \
     19    pmModelGroup.h \
     20    psModulesUtils.h \
     21    psLibUtils.h \
     22    psEllipse.h
  • trunk/psModules/src/objects/pmObjects.c

    r5170 r5255  
    66 *  @author EAM, IfA: significant modifications.
    77 *
    8  *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
    9  *  @date $Date: 2005-09-28 20:43:52 $
     8 *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
     9 *  @date $Date: 2005-10-10 19:53:40 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    1313 */
    1414
    15 #include<stdio.h>
    16 #include<math.h>
     15#include <stdio.h>
     16#include <math.h>
     17#include <string.h>
    1718#include "pslib.h"
    18 #include "psConstants.h"
    1919#include "pmObjects.h"
    20 
     20#include "pmModelGroup.h"
    2121/******************************************************************************
    2222pmPeakAlloc(): Allocate the pmPeak data structure and set appropriate members.
     
    2727                    pmPeakType class)
    2828{
     29    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    2930    pmPeak *tmp = (pmPeak *) psAlloc(sizeof(pmPeak));
    3031    tmp->x = x;
     
    3334    tmp->class = class;
    3435
     36    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    3537    return(tmp);
    3638}
     
    4244pmMoments *pmMomentsAlloc()
    4345{
     46    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    4447    pmMoments *tmp = (pmMoments *) psAlloc(sizeof(pmMoments));
    4548    tmp->x = 0.0;
    4649    tmp->y = 0.0;
    4750    tmp->Sx = 0.0;
    48     tmp->Sx = 0.0;
     51    tmp->Sy = 0.0;
    4952    tmp->Sxy = 0.0;
    5053    tmp->Sum = 0.0;
     
    5356    tmp->nPixels = 0;
    5457
     58    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    5559    return(tmp);
    5660}
     
    5862static void modelFree(pmModel *tmp)
    5963{
     64    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    6065    psFree(tmp->params);
    6166    psFree(tmp->dparams);
     67    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    6268}
    6369
     
    6571pmModelAlloc(): Allocate the pmModel structure, along with its parameters,
    6672and initialize the type member.  Initialize the params to 0.0.
    67 XXX EAM: changing params and dparams to psVector
     73XXX EAM: simplifying code with pmModelParameterCount
    6874*****************************************************************************/
    6975pmModel *pmModelAlloc(pmModelType type)
    7076{
     77    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    7178    pmModel *tmp = (pmModel *) psAlloc(sizeof(pmModel));
    7279
    7380    tmp->type = type;
    7481    tmp->chisq = 0.0;
    75     switch (type) {
    76     case PS_MODEL_GAUSS:
    77         tmp->params  = psVectorAlloc(7, PS_TYPE_F32);
    78         tmp->dparams = psVectorAlloc(7, PS_TYPE_F32);
    79         break;
    80     case PS_MODEL_PGAUSS:
    81         tmp->params  = psVectorAlloc(7, PS_TYPE_F32);
    82         tmp->dparams = psVectorAlloc(7, PS_TYPE_F32);
    83         break;
    84     case PS_MODEL_TWIST_GAUSS:
    85         tmp->params  = psVectorAlloc(11, PS_TYPE_F32);
    86         tmp->dparams = psVectorAlloc(11, PS_TYPE_F32);
    87         break;
    88     case PS_MODEL_WAUSS:
    89         tmp->params  = psVectorAlloc(9, PS_TYPE_F32);
    90         tmp->dparams = psVectorAlloc(9, PS_TYPE_F32);
    91         break;
    92     case PS_MODEL_SERSIC:
    93         tmp->params  = psVectorAlloc(8, PS_TYPE_F32);
    94         tmp->dparams = psVectorAlloc(8, PS_TYPE_F32);
    95         break;
    96     case PS_MODEL_SERSIC_CORE:
    97         tmp->params  = psVectorAlloc(12, PS_TYPE_F32);
    98         tmp->dparams = psVectorAlloc(12, PS_TYPE_F32);
    99         break;
    100     default:
     82    tmp->nIter = 0;
     83    psS32 Nparams = pmModelParameterCount(type);
     84    if (Nparams == 0) {
    10185        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
    10286        return(NULL);
    10387    }
     88
     89    tmp->params  = psVectorAlloc(Nparams, PS_TYPE_F32);
     90    tmp->dparams = psVectorAlloc(Nparams, PS_TYPE_F32);
    10491
    10592    for (psS32 i = 0; i < tmp->params->n; i++) {
     
    10996
    11097    psMemSetDeallocator(tmp, (psFreeFunc) modelFree);
     98    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    11199    return(tmp);
    112100}
    113101
    114102/******************************************************************************
    115 XXX: We don't free pixels and mask since that caused a memory error.
    116 We might need to increase the reference counter and decrease it here.
     103XXX EAM : we can now free these pixels - memory ref is incremented now
    117104*****************************************************************************/
    118105static void sourceFree(pmSource *tmp)
    119106{
     107    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    120108    psFree(tmp->peak);
    121     //    psFree(tmp->pixels);
    122     //    psFree(tmp->mask);
     109    psFree(tmp->pixels);
     110    psFree(tmp->weight);
     111    psFree(tmp->mask);
    123112    psFree(tmp->moments);
    124113    psFree(tmp->modelPSF);
    125114    psFree(tmp->modelFLT);
     115    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    126116}
    127117
     
    132122pmSource *pmSourceAlloc()
    133123{
     124    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    134125    pmSource *tmp = (pmSource *) psAlloc(sizeof(pmSource));
    135126    tmp->peak = NULL;
    136127    tmp->pixels = NULL;
     128    tmp->weight = NULL;
    137129    tmp->mask = NULL;
    138130    tmp->moments = NULL;
     
    142134    psMemSetDeallocator(tmp, (psFreeFunc) sourceFree);
    143135
     136    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    144137    return(tmp);
    145138}
     
    159152                            psF32 threshold)
    160153{
     154    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    161155    PS_ASSERT_VECTOR_NON_NULL(vector, NULL);
    162156    PS_ASSERT_VECTOR_NON_EMPTY(vector, NULL);
     
    177171            tmpVector = psVectorAlloc(0, PS_TYPE_U32);
    178172        }
     173        psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    179174        return(tmpVector);
    180175    }
     
    241236    }
    242237
     238    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    243239    return(tmpVector);
    244240}
     
    248244psVector containing the specified row of data from the psImage.
    249245 
    250 XXX: Is there a better way to do this?
     246XXX: Is there a better way to do this? 
     247XXX EAM: does this really need to alloc a new vector???
    251248*****************************************************************************/
    252249static psVector *getRowVectorFromImage(psImage *image,
    253250                                       psU32 row)
    254251{
     252    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    255253    PS_ASSERT_IMAGE_NON_NULL(image, NULL);
    256254    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, NULL);
     
    260258        tmpVector->data.F32[col] = image->data.F32[row][col];
    261259    }
     260    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    262261    return(tmpVector);
    263262}
     
    276275                              pmPeakType type)
    277276{
     277    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    278278    pmPeak *tmpPeak = pmPeakAlloc(col, row, counts, type);
    279279
     
    283283    }
    284284    psArrayAdd(list, 100, tmpPeak);
    285 
     285    psFree (tmpPeak);
     286    // XXX EAM : is this free appropriate?  (does psArrayAdd increment memory counter?)
     287
     288    psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    286289    return(list);
    287290}
     
    308311                          psF32 threshold)
    309312{
     313    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    310314    PS_ASSERT_IMAGE_NON_NULL(image, NULL);
    311315    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, NULL);
    312316    if ((image->numRows == 1) || (image->numCols == 1)) {
    313317        psError(PS_ERR_UNKNOWN, true, "Currently, input image must have at least 2 rows and 2 columns.");
     318        psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    314319        return(NULL);
    315320    }
     
    364369        }
    365370    }
     371    psFree (tmpRow);
     372    psFree (row1);
    366373
    367374    //
     
    369376    //
    370377    if (image->numRows == 1) {
     378        psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    371379        return(list);
    372380    }
     
    442450                }
    443451            } else {
    444                 psError(PS_ERR_UNKNOWN, true, "peak specified valid column range.");
     452                psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");
    445453            }
    446454
    447455        }
     456        psFree (tmpRow);
     457        psFree (row1);
    448458    }
    449459
     
    484494            }
    485495        } else {
    486             psError(PS_ERR_UNKNOWN, true, "peak specified valid colum range.");
    487         }
    488     }
     496            psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");
     497        }
     498    }
     499    psFree (tmpRow);
     500    psFree (row1);
     501    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    489502    return(list);
    490503}
     
    495508                             psS32 y)
    496509{
    497 
     510    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    498511    if ((x >= valid.x0) &&
    499512            (x <= valid.x1) &&
    500513            (y >= valid.y0) &&
    501514            (y <= valid.y1)) {
     515        psTrace(__func__, 4, "---- %s(true) end ----\n", __func__);
    502516        return(true);
    503517    }
    504 
     518    psTrace(__func__, 4, "---- %s(false) end ----\n", __func__);
    505519    return(false);
    506520}
     
    516530 
    517531XXX: changed API to create a NEW output psArray (should change name as well)
     532 
     533XXX: Do we free the psList elements of those culled peaks?
     534 
     535XXX EAM : do we still need pmCullPeaks, or only pmPeaksSubset?
    518536*****************************************************************************/
    519537psList *pmCullPeaks(psList *peaks,
     
    521539                    const psRegion valid)
    522540{
     541    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    523542    PS_ASSERT_PTR_NON_NULL(peaks, NULL);
    524     //    PS_ASSERT_PTR_NON_NULL(valid, NULL);
    525543
    526544    psListElem *tmpListElem = (psListElem *) peaks->head;
     
    539557    }
    540558
     559    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    541560    return(peaks);
    542561}
     
    544563// XXX EAM: I changed this to return a new, subset array
    545564//          rather than alter the existing one
    546 psArray *pmPeaksSubset(psArray *peaks, psF32 maxValue, const psRegion valid)
    547 {
     565// XXX: Fix the *valid pointer.
     566psArray *pmPeaksSubset(
     567    psArray *peaks,
     568    psF32 maxValue,
     569    const psRegion valid)
     570{
     571    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    548572    PS_ASSERT_PTR_NON_NULL(peaks, NULL);
    549573
     
    561585        psArrayAdd (output, 200, tmpPeak);
    562586    }
     587    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    563588    return(output);
    564589}
     
    601626     members.
    602627*****************************************************************************/
    603 pmSource *pmSourceLocalSky(const psImage *image,
    604                            const pmPeak *peak,
    605                            psStatsOptions statsOptions,
    606                            psF32 innerRadius,
    607                            psF32 outerRadius)
    608 {
    609     PS_ASSERT_IMAGE_NON_NULL(image, NULL);
    610     PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, NULL);
    611     PS_ASSERT_PTR_NON_NULL(peak, NULL);
    612     PS_FLOAT_COMPARE(0.0, innerRadius, NULL);
    613     PS_FLOAT_COMPARE(innerRadius, outerRadius, NULL);
    614     psS32 innerRadiusS32 = (psS32) innerRadius;
    615     psS32 outerRadiusS32 = (psS32) outerRadius;
    616 
    617     //
    618     // We define variables for code readability.
    619     //
    620     // XXX: Since the peak->xy coords are in image, not subImage coords,
    621     // these variables should be renamed for clarity (imageCenterRow, etc).
    622     //
    623     // peak->x,y is guaranteed to be on image
    624     psS32 SubImageCenterRow = peak->y;
    625     psS32 SubImageCenterCol = peak->x;
    626 
    627     // XXX EAM : I added this code to stay on the image. So did George
    628     psS32 SubImageStartRow  = PS_MAX(0, SubImageCenterRow - outerRadiusS32);
    629     psS32 SubImageEndRow    = PS_MIN(image->numRows - 1, SubImageCenterRow + outerRadiusS32);
    630     psS32 SubImageStartCol  = PS_MAX(0, SubImageCenterCol - outerRadiusS32);
    631     psS32 SubImageEndCol    = PS_MIN(image->numCols - 1, SubImageCenterCol + outerRadiusS32);
    632     // AnulusWidth == number of pixels width in the annulus.  We add one since
    633     // the pixels at the inner AND outher radius are included.
    634     psS32 AnulusWidth = 1 + (outerRadiusS32 - innerRadiusS32);
    635     // Example: assume an outer/inner radius of 20/10.  Then the subimage
    636     // should have width/length of 40.  An 18-by-18 interior region will
    637     // be masked.
    638     //    printf("pmSourceLocalSky(): innerRadiusS32 is %d\n", innerRadiusS32);
    639     //    printf("pmSourceLocalSky(): outerRadiusS32 is %d\n", outerRadiusS32);
    640     //    printf("pmSourceLocalSky(): AnulusWidth is %d\n", AnulusWidth);
    641 
    642     // XXX EAM : these tests should not be needed: we can never hit this error because of above
    643     # if (1)
    644 
    645         if (SubImageStartRow < 0) {
    646             psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
    647                     SubImageStartRow);
    648             return(NULL);
    649         }
    650     if (SubImageEndRow >= image->numRows) {
    651         psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n",
    652                 SubImageEndRow);
    653         return(NULL);
    654     }
    655     if (SubImageStartCol < 0) {
    656         psError(PS_ERR_UNKNOWN, true, "Sub image startCol is outside image boundaries (%d).\n",
    657                 SubImageStartCol);
    658         return(NULL);
    659     }
    660     if (SubImageEndCol >= image->numCols) {
    661         psError(PS_ERR_UNKNOWN, true, "Sub image endCol is outside image boundaries (%d).\n",
    662                 SubImageEndCol);
    663         return(NULL);
    664     }
    665     # endif
    666 
    667     //
    668     // Grab a subimage of the original image of size (2 * outerRadius).
    669     //
    670     // XXX: Must fix for new psImageSubset
    671     //    psImage *subImage = psImageSubset((psImage *) image,
    672     //                                      SubImageStartCol,
    673     //                                      SubImageStartRow,
    674     //                                      SubImageEndCol,
    675     //                                      SubImageEndRow);
    676     //    printf("pmSourceLocalSky: subimage width/length is (%d, %d)\n", subImage->numCols, subImage->numRows);
    677     psRegion tmpRegion = psRegionSet(SubImageStartCol,
    678                                      SubImageEndCol,
    679                                      SubImageStartRow,
    680                                      SubImageEndRow);
    681     psImage *subImage = psImageSubset((psImage *) image, tmpRegion);
    682 
    683     psImage *subImageMask = psImageAlloc(subImage->numCols,
    684                                          subImage->numRows,
    685                                          PS_TYPE_U8);
    686 
    687     //
    688     // Loop through the subimage mask, initialize mask to 0.
    689     //
    690     for (psS32 row = 0 ; row < subImageMask->numRows; row++) {
    691         for (psS32 col = 0 ; col < subImageMask->numCols; col++) {
    692             subImageMask->data.U8[row][col] = 0;
    693         }
    694     }
    695 
    696     //
    697     // Loop through the subimage, mask off pixels in the inner square.
    698     // XXX this uses a static mask value of 1
    699     //
    700     for (psS32 row = AnulusWidth; row <= (subImageMask->numRows - AnulusWidth) - 1; row++) {
    701         for (psS32 col = AnulusWidth; col <= (subImageMask->numCols - AnulusWidth) - 1; col++) {
    702             subImageMask->data.U8[row][col] = 1;
    703         }
    704     }
    705 
    706 
    707     //    for (psS32 row = 0 ; row < subImage->numRows; row++) {
    708     //        for (psS32 col = 0 ; col < subImage->numCols; col++) {
    709     //            printf("(%d) ", subImageMask->data.U8[row][col]);
    710     //        }
    711     //        printf("\n");
    712     //    }
    713 
    714     //
    715     // Allocate the myStats structure, then call psImageStats(), which will
    716     // calculate the specified statistic.
    717     //
     628
     629
     630
     631
     632
     633
     634
     635
     636
     637bool pmSourceLocalSky(
     638    pmSource *source,
     639    psStatsOptions statsOptions,
     640    psF32 Radius)
     641{
     642    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     643    PS_ASSERT_PTR_NON_NULL(source, false);
     644    PS_ASSERT_IMAGE_NON_NULL(source->pixels, false);
     645    PS_ASSERT_IMAGE_NON_NULL(source->mask, false);
     646    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     647    PS_ASSERT_INT_POSITIVE(Radius, false);
     648    PS_ASSERT_INT_NONNEGATIVE(Radius, false);
     649
     650    psImage *image = source->pixels;
     651    psImage *mask  = source->mask;
     652    pmPeak *peak  = source->peak;
     653    psRegion srcRegion;
     654
     655    srcRegion = psRegionForSquare(peak->x, peak->y, Radius);
     656    srcRegion = psRegionForImage(mask, srcRegion);
     657
     658    psImageMaskRegion(mask, srcRegion, "OR", PSPHOT_MASK_MARKED);
    718659    psStats *myStats = psStatsAlloc(statsOptions);
    719     myStats = psImageStats(myStats, subImage, subImageMask, 1);
    720 
    721     //
    722     // Create the output mySource, and set appropriate members.
    723     //
    724     pmSource *mySource = pmSourceAlloc();
    725     mySource->peak = (pmPeak *) peak;
    726     mySource->moments = pmMomentsAlloc();
     660    myStats = psImageStats(myStats, image, mask, 0xff);
     661    psImageMaskRegion(mask, srcRegion, "AND", ~PSPHOT_MASK_MARKED);
     662
    727663    psF64 tmpF64;
    728664    p_psGetStatValue(myStats, &tmpF64);
    729     mySource->moments->Sky = (psF32) tmpF64;
    730     mySource->pixels = subImage;
    731     mySource->mask = subImageMask;
    732 
    733     //
    734     // Free things.  XXX: This should be static memory.
    735     //
    736665    psFree(myStats);
    737666
    738     return(mySource);
    739 }
    740 
    741 /******************************************************************************
    742 bool checkRadius(*peak, radius, x, y): private function which simply
    743 determines if the (x, y) point is within the radius of the specified peak.
    744  
    745 XXX: macro this for performance.
    746 *****************************************************************************/
    747 static bool checkRadius(pmPeak *peak,
    748                         psF32 radius,
    749                         psS32 x,
    750                         psS32 y)
    751 {
    752     if (PS_SQR(radius) >= (psF32) (PS_SQR(x - peak->x) + PS_SQR(y - peak->y))) {
    753         return(true);
    754     }
    755 
    756     return(false);
     667    if (isnan(tmpF64)) {
     668        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     669        return(false);
     670    }
     671    source->moments = pmMomentsAlloc();
     672    source->moments->Sky = (psF32) tmpF64;
     673    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
     674    return (true);
    757675}
    758676
     
    770688                         psF32 y)
    771689{
     690    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    772691    /// XXX EAM should compare with hypot (x,y) for speed
    773692    if ((PS_SQR(x - xCenter) + PS_SQR(y - yCenter)) < PS_SQR(radius)) {
     
    775694    }
    776695
     696    psTrace(__func__, 4, "---- %s(false) end ----\n", __func__);
    777697    return(false);
    778698}
     
    787707    pmSource->peak
    788708    pmSource->pixels
     709    pmSource->weight
     710    pmSource->mask
    789711 
    790712XXX: The peak calculations are done in image coords, not subImage coords.
    791713 
    792 XXX: mask values?
    793 *****************************************************************************/
    794 pmSource *pmSourceMoments(pmSource *source,
    795                           psF32 radius)
    796 {
    797     PS_ASSERT_PTR_NON_NULL(source, NULL);
    798     PS_ASSERT_PTR_NON_NULL(source->peak, NULL);
    799     PS_ASSERT_PTR_NON_NULL(source->pixels, NULL);
    800     PS_FLOAT_COMPARE(0.0, radius, NULL);
     714XXX EAM : this version clips input pixels on S/N
     715XXX EAM : this version returns false for several reasons
     716*****************************************************************************/
     717# define VALID_RADIUS(X,Y,RAD2) (((RAD2) >= (PS_SQR(X) + PS_SQR(Y))) ? 1 : 0)
     718
     719bool pmSourceMoments(pmSource *source,
     720                     psF32 radius)
     721{
     722    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     723    PS_ASSERT_PTR_NON_NULL(source, false);
     724    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     725    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
     726    PS_ASSERT_PTR_NON_NULL(source->mask, false);
     727    PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);
    801728
    802729    //
     
    816743    // XY  = SUM (x - xc)*(y - yc)*(z - sky)
    817744    //
    818     psF32 Sum = 0.0;
    819745    psF32 peakPixel = -PS_MAX_F32;
    820746    psS32 numPixels = 0;
     747    psF32 Sum = 0.0;
    821748    psF32 X1 = 0.0;
    822749    psF32 Y1 = 0.0;
     
    824751    psF32 Y2 = 0.0;
    825752    psF32 XY = 0.0;
    826     psF32 x = 0;
    827     psF32 y = 0;
    828     //
     753    psF32 x  = 0;
     754    psF32 y  = 0;
     755    psF32 R2 = PS_SQR(radius);
     756
     757    psF32 xPeak = source->peak->x;
     758    psF32 yPeak = source->peak->y;
     759
    829760    // XXX why do I get different results for these two methods of finding Sx?
    830761    // XXX Sx, Sy would be better measured if we clip pixels close to sky
     
    834765    // proceed with the moments calculation.  need to do two loops for a
    835766    // numerically stable result.  first loop: get the sums.
    836     //
     767    // XXX EAM : mask == 0 is valid
     768
    837769    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    838770        for (psS32 col = 0; col < source->pixels->numCols ; col++) {
    839             if ((source->mask != NULL) && (source->mask->data.U8[row][col] != 0)) {
    840                 psS32 imgColCoord = col + source->pixels->col0;
    841                 psS32 imgRowCoord = row + source->pixels->row0;
    842                 if (checkRadius(source->peak,
    843                                 radius,
    844                                 imgColCoord,
    845                                 imgRowCoord)) {
    846                     psF32 xDiff = (psF32) (imgColCoord - source->peak->x);
    847                     psF32 yDiff = (psF32) (imgRowCoord - source->peak->y);
    848                     psF32 pDiff = source->pixels->data.F32[row][col] - sky;
    849 
    850                     Sum+= pDiff;
    851                     X1+= xDiff * pDiff;
    852                     Y1+= yDiff * pDiff;
    853                     XY+= xDiff * yDiff * pDiff;
    854 
    855                     X2+= PS_SQR(xDiff) * pDiff;
    856                     Y2+= PS_SQR(yDiff) * pDiff;
    857 
    858                     if (source->pixels->data.F32[row][col] > peakPixel) {
    859                         peakPixel = source->pixels->data.F32[row][col];
    860                     }
    861                     numPixels++;
    862                 }
    863             }
    864         }
    865     }
     771            if ((source->mask != NULL) && (source->mask->data.U8[row][col]))
     772                continue;
     773
     774            psF32 xDiff = col + source->pixels->col0 - xPeak;
     775            psF32 yDiff = row + source->pixels->row0 - yPeak;
     776
     777            // XXX EAM : calculate xDiff, yDiff up front;
     778            //           radius is just a function of (xDiff, yDiff)
     779            if (!VALID_RADIUS(xDiff, yDiff, R2))
     780                continue;
     781
     782            psF32 pDiff = source->pixels->data.F32[row][col] - sky;
     783
     784            // XXX EAM : check for valid S/N in pixel
     785            // XXX EAM : should this limit be user-defined?
     786            if (pDiff / sqrt(source->weight->data.F32[row][col]) < 1)
     787                continue;
     788
     789            Sum += pDiff;
     790            X1  += xDiff * pDiff;
     791            Y1  += yDiff * pDiff;
     792            XY  += xDiff * yDiff * pDiff;
     793
     794            X2  += PS_SQR(xDiff) * pDiff;
     795            Y2  += PS_SQR(yDiff) * pDiff;
     796
     797            peakPixel = PS_MAX (source->pixels->data.F32[row][col], peakPixel);
     798            numPixels++;
     799        }
     800    }
     801    // XXX EAM - the limit is a bit arbitrary.  make it user defined?
     802    if ((numPixels < 3) || (Sum <= 0)) {
     803        psTrace (".psModules.pmSourceMoments", 5, "no valid pixels for source\n");
     804        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     805        return (false);
     806    }
     807
     808    psTrace (".psModules.pmSourceMoments", 5,
     809             "sky: %f  Sum: %f  X1: %f  Y1: %f  X2: %f  Y2: %f  XY: %f  Npix: %d\n",
     810             sky, Sum, X1, Y1, X2, Y2, XY, numPixels);
    866811
    867812    //
     
    872817    x = X1/Sum;
    873818    y = Y1/Sum;
    874     source->moments->x = x + ((psF32) source->peak->x);
    875     source->moments->y = y + ((psF32) source->peak->y);
    876 
    877     source->moments->Sxy = XY/Sum;
     819    if ((fabs(x) > radius) || (fabs(y) > radius)) {
     820        psTrace (".psModules.pmSourceMoments", 5,
     821                 "large centroid swing; invalid peak %d, %d\n",
     822                 source->peak->x, source->peak->y);
     823        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     824        return (false);
     825    }
     826
     827    source->moments->x = x + xPeak;
     828    source->moments->y = y + yPeak;
     829
     830    // XXX EAM : Sxy needs to have x*y subtracted
     831    source->moments->Sxy = XY/Sum - x*y;
    878832    source->moments->Sum = Sum;
    879833    source->moments->Peak = peakPixel;
     
    883837    source->moments->Sx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0));
    884838    source->moments->Sy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0));
    885     return(source);
    886 
    887     // XXX EAM : the following code should be the same as above, but it is not very stable: ignore it
    888     # if (0)
    889         //
    890         // second loop: get the difference sums
    891         //
    892         X2 = Y2 = 0;
    893     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
    894         for (psS32 col = 0; col < source->pixels->numCols ; col++) {
    895             if ((source->mask != NULL) && (source->mask->data.U8[row][col] != 0)) {
    896                 psS32 imgColCoord = col + source->pixels->col0;
    897                 psS32 imgRowCoord = row + source->pixels->row0;
    898                 if (checkRadius(source->peak,
    899                                 radius,
    900                                 imgColCoord,
    901                                 imgRowCoord)) {
    902                     psF32 xDiff = (psF32) (imgColCoord - source->peak->x);
    903                     psF32 yDiff = (psF32) (imgRowCoord - source->peak->y);
    904                     psF32 pDiff = source->pixels->data.F32[row][col] - sky;
    905 
    906                     Sum+= pDiff;
    907                     X2+= PS_SQR(xDiff - x) * pDiff;
    908                     Y2+= PS_SQR(yDiff - y) * pDiff;
    909                 }
    910             }
    911         }
    912     }
    913 
    914     //
    915     // second moment X = sqrt (X2/Sum)
    916     //
    917     source->moments->Sx = (X2/Sum);
    918     source->moments->Sy = (Y2/Sum);
    919     return(source);
    920     # endif
     839
     840    psTrace (".psModules.pmSourceMoments", 4,
     841             "sky: %f  Sum: %f  x: %f  y: %f  Sx: %f  Sy: %f  Sxy: %f\n",
     842             sky, Sum, source->moments->x, source->moments->y,
     843             source->moments->Sx, source->moments->Sy, source->moments->Sxy);
     844
     845    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
     846    return(true);
    921847}
    922848
     
    924850int pmComparePeakAscend (const void **a, const void **b)
    925851{
     852    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    926853    pmPeak *A = *(pmPeak **)a;
    927854    pmPeak *B = *(pmPeak **)b;
     
    930857
    931858    diff = A->counts - B->counts;
    932     if (diff < FLT_EPSILON)
     859    if (diff < FLT_EPSILON) {
     860        psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__);
    933861        return (-1);
    934     if (diff > FLT_EPSILON)
     862    } else if (diff > FLT_EPSILON) {
     863        psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__);
    935864        return (+1);
     865    }
     866    psTrace(__func__, 3, "---- %s(0) end ----\n", __func__);
    936867    return (0);
    937868}
     
    939870int pmComparePeakDescend (const void **a, const void **b)
    940871{
     872    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    941873    pmPeak *A = *(pmPeak **)a;
    942874    pmPeak *B = *(pmPeak **)b;
     
    945877
    946878    diff = A->counts - B->counts;
    947     if (diff < FLT_EPSILON)
     879    if (diff < FLT_EPSILON) {
     880        psTrace(__func__, 3, "---- %s(+1) end ----\n", __func__);
    948881        return (+1);
    949     if (diff > FLT_EPSILON)
     882    } else if (diff > FLT_EPSILON) {
     883        psTrace(__func__, 3, "---- %s(-1) end ----\n", __func__);
    950884        return (-1);
     885    }
     886    psTrace(__func__, 3, "---- %s(0) end ----\n", __func__);
    951887    return (0);
    952888}
    953889
    954890/******************************************************************************
    955 pmSourceRoughClass(source, metadata): make a guess at the source
    956 classification.
    957  
    958 XXX: This is not useable code, as of the release date.  There remains a fair
    959 bit of coding to be completed.
    960  
    961 XXX: The sigX and sigY stuff in the SDRS is unclear.
    962  
    963 XXX: How can this function ever return FALSE?
    964 *****************************************************************************/
    965 
    966 # define NPIX 10
    967 # define SCALE 0.1
    968 
    969 // XXX I am ignore memory freeing issues (EAM)
    970 bool pmSourceRoughClass(psArray *sources, psMetadata *metadata)
    971 {
    972     PS_ASSERT_PTR_NON_NULL(sources, false);
    973     PS_ASSERT_PTR_NON_NULL(metadata, false);
    974     psBool rc = true;
     891pmSourcePSFClump(source, metadata): Find the likely PSF clump in the
     892sigma-x, sigma-y plane. return 0,0 clump in case of error.
     893*****************************************************************************/
     894
     895// XXX EAM include a S/N cutoff in selecting the sources?
     896pmPSFClump pmSourcePSFClump(psArray *sources, psMetadata *metadata)
     897{
     898    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     899
     900    # define NPIX 10
     901    # define SCALE 0.1
     902
    975903    psArray *peaks  = NULL;
    976     psF32 clumpX = 0.0;
    977     psF32 clumpDX = 0.0;
    978     psF32 clumpY = 0.0;
    979     psF32 clumpDY = 0.0;
     904    pmPSFClump emptyClump = {0.0, 0.0, 0.0, 0.0};
     905    pmPSFClump psfClump = emptyClump;
     906
     907    PS_ASSERT_PTR_NON_NULL(sources, emptyClump);
     908    PS_ASSERT_PTR_NON_NULL(metadata, emptyClump);
    980909
    981910    // find the sigmaX, sigmaY clump
     
    986915
    987916        // construct a sigma-plane image
     917        // psImageAlloc does zero the data
    988918        splane = psImageAlloc (NPIX/SCALE, NPIX/SCALE, PS_TYPE_F32);
     919        for (int i = 0; i < splane->numRows; i++)
     920        {
     921            memset (splane->data.F32[i], 0, splane->numCols*sizeof(PS_TYPE_F32));
     922        }
    989923
    990924        // place the sources in the sigma-plane image (ignore 0,0 values?)
     
    992926        {
    993927            pmSource *tmpSrc = (pmSource *) sources->data[i];
    994             PS_ASSERT_PTR_NON_NULL(tmpSrc, false); // just skip this one?
    995             PS_ASSERT_PTR_NON_NULL(tmpSrc->moments, false); // just skip this one?
     928            if (tmpSrc == NULL) {
     929                continue;
     930            }
     931            if (tmpSrc->moments == NULL) {
     932                continue;
     933            }
    996934
    997935            // Sx,Sy are limited at 0.  a peak at 0,0 is artificial
     
    1022960        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump threshold is %f\n", stats[0].max/2);
    1023961
    1024     }
     962        psFree (splane);
     963        psFree (stats);
     964
     965    }
     966    // XXX EAM : possible errors:
     967    //           1) no peak in splane
     968    //           2) no significant peak in splane
    1025969
    1026970    // measure statistics on Sx, Sy if Sx, Sy within range of clump
     
    1036980        psArraySort (peaks, pmComparePeakDescend);
    1037981        clump = peaks->data[0];
    1038         psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d\n", clump->x, clump->y);
     982        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->counts);
    1039983
    1040984        // define section window for clump
     
    10771021
    10781022        stats = psVectorStats (stats, tmpSx, NULL, NULL, 0);
    1079         clumpX  = stats->clippedMean;
    1080         clumpDX = stats->clippedStdev;
     1023        psfClump.X  = stats->clippedMean;
     1024        psfClump.dX = stats->clippedStdev;
    10811025
    10821026        stats = psVectorStats (stats, tmpSy, NULL, NULL, 0);
    1083         clumpY  = stats->clippedMean;
    1084         clumpDY = stats->clippedStdev;
    1085 
    1086         psTrace (".pmObjects.pmSourceRoughClass", 2, "clump  X,  Y: %f, %f\n", clumpX, clumpY);
    1087         psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", clumpDX, clumpDY);
     1027        psfClump.Y  = stats->clippedMean;
     1028        psfClump.dY = stats->clippedStdev;
     1029
     1030        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump  X,  Y: %f, %f\n", psfClump.X, psfClump.Y);
     1031        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY);
    10881032        // these values should be pushed on the metadata somewhere
    1089     }
    1090 
    1091     int Nsat   = 0;
    1092     int Ngal   = 0;
    1093     int Nfaint = 0;
    1094     int Nstar  = 0;
    1095     int Npsf   = 0;
    1096     int Ncr    = 0;
     1033
     1034        psFree (stats);
     1035        psFree (peaks);
     1036        psFree (tmpSx);
     1037        psFree (tmpSy);
     1038    }
     1039
     1040    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1041    return (psfClump);
     1042}
     1043
     1044/******************************************************************************
     1045pmSourceRoughClass(source, metadata): make a guess at the source
     1046classification.
     1047 
     1048XXX: push the clump info into the metadata?
     1049 
     1050XXX: How can this function ever return FALSE?
     1051 
     1052XXX EAM : add the saturated mask value to metadata
     1053*****************************************************************************/
     1054
     1055bool pmSourceRoughClass(psArray *sources, psMetadata *metadata, pmPSFClump clump)
     1056{
     1057    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1058
     1059    psBool rc = true;
     1060
     1061    int Nsat     = 0;
     1062    int Ngal     = 0;
     1063    int Nstar    = 0;
     1064    int Npsf     = 0;
     1065    int Ncr      = 0;
     1066    int Nsatstar = 0;
     1067
    10971068    psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32);
    10981069    starsn->n = 0;
     1070
     1071    // check return status value (do these exist?)
     1072    bool status;
     1073    psF32 RDNOISE    = psMetadataLookupF32 (&status, metadata, "RDNOISE");
     1074    psF32 GAIN       = psMetadataLookupF32 (&status, metadata, "GAIN");
     1075    psF32 PSF_SN_LIM = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM");
     1076    // psF32 SATURATE = psMetadataLookupF32 (&status, metadata, "SATURATE");
    10991077
    11001078    // XXX allow clump size to be scaled relative to sigmas?
     
    11091087        psF32 sigY = tmpSrc->moments->Sy;
    11101088
    1111         // check return status value (do these exist?)
    1112         bool status;
    1113         psF32 RDNOISE  = psMetadataLookupF32 (&status, metadata, "RDNOISE");
    1114         psF32 GAIN     = psMetadataLookupF32 (&status, metadata, "GAIN");
    1115         psF32 SATURATE = psMetadataLookupF32 (&status, metadata, "SATURATE");
    1116 
    1117         psF32 PSF_SN_LIM   = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM");
    1118         psF32 FAINT_SN_LIM = psMetadataLookupF32 (&status, metadata, "FAINT_SN_LIM");
    1119 
    1120         // saturated object (star or single pixel not distinguished)
    1121         if (tmpSrc->moments->Peak > SATURATE) {
    1122             tmpSrc->type |= PS_SOURCE_SATURATED;
     1089        // calculate and save signal-to-noise estimates
     1090        psF32 S  = tmpSrc->moments->Sum;
     1091        psF32 A  = 4 * M_PI * sigX * sigY;
     1092        psF32 B  = tmpSrc->moments->Sky;
     1093        psF32 RT = sqrt(S + (A * B) + (A * PS_SQR(RDNOISE) / sqrt(GAIN)));
     1094        psF32 SN = (S * sqrt(GAIN) / RT);
     1095        tmpSrc->moments->SN = SN;
     1096
     1097        // XXX EAM : can we use the value of SATURATE if mask is NULL?
     1098        //
     1099        // XXX: Must verify this region (the region argument was added to psImageCountPixelMask()
     1100        // after EAM wrote this code.
     1101        //
     1102        psRegion tmpRegion = psRegionSet(0, tmpSrc->mask->numCols, 0, tmpSrc->mask->numRows);
     1103        int Nsatpix = psImageCountPixelMask(tmpSrc->mask, tmpRegion, PSPHOT_MASK_SATURATED);
     1104
     1105        // saturated star (size consistent with PSF or larger)
     1106        // Nsigma should be user-configured parameter
     1107        bool big = (sigX > (clump.X - clump.dX)) && (sigY > (clump.Y - clump.dY));
     1108        if ((Nsatpix > 1) && big) {
     1109            tmpSrc->type |= PM_SOURCE_SATSTAR;
     1110            Nsatstar ++;
     1111            continue;
     1112        }
     1113
     1114        // saturated object (not a star, eg bleed trails, hot pixels)
     1115        if (Nsatpix > 1) {
     1116            tmpSrc->type |= PM_SOURCE_SATURATED;
    11231117            Nsat ++;
    11241118            continue;
    11251119        }
    11261120
    1127         // too small to be stellar
    1128         if ((sigX < (clumpX - clumpDX)) || (sigY < (clumpY - clumpDY))) {
    1129             tmpSrc->type |= PS_SOURCE_DEFECT;
     1121        // likely defect (too small to be stellar) (push out to 3 sigma)
     1122        // low S/N objects which are small are probably stellar
     1123        // only set candidate defects if
     1124        if ((sigX < 0.05) || (sigY < 0.05)) {
     1125            tmpSrc->type |= PM_SOURCE_DEFECT;
    11301126            Ncr ++;
    11311127            continue;
    11321128        }
    11331129
    1134         // possible galaxy
    1135         if ((sigX > (clumpX + clumpDX)) || (sigY > (clumpY + clumpDY))) {
    1136             tmpSrc->type |= PS_SOURCE_GALAXY;
     1130        // likely unsaturated galaxy (too large to be stellar)
     1131        if ((sigX > (clump.X + 3*clump.dX)) || (sigY > (clump.Y + 3*clump.dY))) {
     1132            tmpSrc->type |= PM_SOURCE_GALAXY;
    11371133            Ngal ++;
    11381134            continue;
     
    11401136
    11411137        // the rest are probable stellar objects
    1142         psF32 S  = tmpSrc->moments->Sum;
    1143         psF32 A  = M_PI * sigX * sigY;
    1144         psF32 B  = tmpSrc->moments->Sky;
    1145         psF32 RT = sqrtf(S + (A * B) + (A * PS_SQR(RDNOISE) / sqrtf(GAIN)));
    1146         psF32 SN = (S * sqrtf(GAIN) / RT);
    1147 
    11481138        starsn->data.F32[starsn->n] = SN;
    11491139        starsn->n ++;
    11501140        Nstar ++;
    11511141
    1152         // faint star
    1153         if (SN < FAINT_SN_LIM) {
    1154             tmpSrc->type |= PS_SOURCE_FAINTSTAR;
    1155             Nfaint ++;
    1156             continue;
    1157         }
    1158 
    1159         // PSF star
    1160         if (SN > PSF_SN_LIM) {
    1161             tmpSrc->type |= PS_SOURCE_PSFSTAR;
     1142        // PSF star (within 1.5 sigma of clump center
     1143        psF32 radius = hypot ((sigX-clump.X)/clump.dX, (sigY-clump.Y)/clump.dY);
     1144        if ((SN > PSF_SN_LIM) && (radius < 1.5)) {
     1145            tmpSrc->type |= PM_SOURCE_PSFSTAR;
    11621146            Npsf ++;
    11631147            continue;
     
    11651149
    11661150        // random type of star
    1167         tmpSrc->type |= PS_SOURCE_OTHER;
     1151        tmpSrc->type |= PM_SOURCE_OTHER;
    11681152    }
    11691153
     
    11731157        stats = psVectorStats (stats, starsn, NULL, NULL, 0);
    11741158        psLogMsg ("pmObjects", 3, "SN range: %f - %f\n", stats[0].min, stats[0].max);
    1175     }
    1176 
    1177     psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar:  %3d\n", Nstar);
    1178     psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf:   %3d\n", Npsf);
    1179     psTrace (".pmObjects.pmSourceRoughClass", 2, "Nfaint: %3d\n", Nfaint);
    1180     psTrace (".pmObjects.pmSourceRoughClass", 2, "Ngal:   %3d\n", Ngal);
    1181     psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat:   %3d\n", Nsat);
    1182     psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr:    %3d\n", Ncr);
    1183 
     1159        psFree (stats);
     1160        psFree (starsn);
     1161    }
     1162
     1163    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar:    %3d\n", Nstar);
     1164    psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf:     %3d\n", Npsf);
     1165    psTrace (".pmObjects.pmSourceRoughClass", 2, "Ngal:     %3d\n", Ngal);
     1166    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsatstar: %3d\n", Nsatstar);
     1167    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat:     %3d\n", Nsat);
     1168    psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr:      %3d\n", Ncr);
     1169
     1170    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
    11841171    return(rc);
    11851172}
    11861173
     1174/** pmSourceDefinePixels()
     1175 *
     1176 * Define psImage subarrays for the source located at coordinates x,y on the
     1177 * image set defined by readout. The pixels defined by this operation consist of
     1178 * a square window (of full width 2Radius+1) centered on the pixel which contains
     1179 * the given coordinate, in the frame of the readout. The window is defined to
     1180 * have limits which are valid within the boundary of the readout image, thus if
     1181 * the radius would fall outside the image pixels, the subimage is truncated to
     1182 * only consist of valid pixels. If readout->mask or readout->weight are not
     1183 * NULL, matching subimages are defined for those images as well. This function
     1184 * fails if no valid pixels can be defined (x or y less than Radius, for
     1185 * example). This function should be used to define a region of interest around a
     1186 * source, including both source and sky pixels.
     1187 *
     1188 * XXX: must code this.
     1189 *
     1190 */
     1191bool pmSourceDefinePixels(
     1192    pmSource *mySource,                 ///< Add comment.
     1193    pmReadout *readout,                 ///< Add comment.
     1194    psF32 x,                            ///< Add comment.
     1195    psF32 y,                            ///< Add comment.
     1196    psF32 Radius)                       ///< Add comment.
     1197{
     1198    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1199    psLogMsg(__func__, PS_LOG_WARN, "WARNING: pmSourceDefinePixels() has not been implemented.  Returning FALSE.\n");
     1200    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1201    return(false);
     1202}
     1203
    11871204/******************************************************************************
    11881205pmSourceSetPixelsCircle(source, image, radius)
    11891206 
    1190 XXX: Why boolean output?
    1191  
    1192 XXX: Why are we checking source->moments for NULL?  Should the circle be
    1193      centered on the centroid or the peak?
    1194  
    1195 XXX: The circle will have a diameter of (1+radius).  This is different from
    1196      the pmSourceSetLocal() function.
     1207XXX: This was replaced by DefinePixels in SDRS.  Remove it.
    11971208*****************************************************************************/
    11981209bool pmSourceSetPixelsCircle(pmSource *source,
     
    12001211                             psF32 radius)
    12011212{
     1213    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    12021214    PS_ASSERT_IMAGE_NON_NULL(image, false);
    12031215    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
    12041216    PS_ASSERT_PTR_NON_NULL(source, false);
    12051217    PS_ASSERT_PTR_NON_NULL(source->moments, false);
    1206     // PS_ASSERT_PTR_NON_NULL(source->peak, false);
     1218    PS_ASSERT_PTR_NON_NULL(source->peak, false);
    12071219    PS_FLOAT_COMPARE(0.0, radius, false);
    12081220
     
    12171229    psS32 SubImageCenterCol = source->peak->x;
    12181230    // XXX EAM : for the circle to stay on the image
     1231    // XXX EAM : EndRow is *exclusive* of pixel region (ie, last pixel + 1)
    12191232    psS32 SubImageStartRow  = PS_MAX (0, SubImageCenterRow - radiusS32);
    1220     psS32 SubImageEndRow    = PS_MIN (image->numRows - 1, SubImageCenterRow + radiusS32);
     1233    psS32 SubImageEndRow    = PS_MIN (image->numRows, SubImageCenterRow + radiusS32 + 1);
    12211234    psS32 SubImageStartCol  = PS_MAX (0, SubImageCenterCol - radiusS32);
    1222     psS32 SubImageEndCol    = PS_MIN (image->numCols - 1, SubImageCenterCol + radiusS32);
    1223 
    1224     // XXX EAM : this should not be needed: we can never hit this error
    1225     # if (1)
    1226 
    1227         if (SubImageStartRow < 0) {
    1228             psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
    1229                     SubImageStartRow);
    1230             return(false);
    1231         }
    1232     if (SubImageEndRow >= image->numRows) {
    1233         psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n",
    1234                 SubImageEndRow);
    1235         return(false);
    1236     }
    1237     if (SubImageStartCol < 0) {
    1238         psError(PS_ERR_UNKNOWN, true, "Sub image startCol is outside image boundaries (%d).\n",
    1239                 SubImageStartCol);
    1240         return(false);
    1241     }
    1242     if (SubImageEndCol >= image->numCols) {
    1243         psError(PS_ERR_UNKNOWN, true, "Sub image endCol is outside image boundaries (%d).\n",
    1244                 SubImageEndCol);
    1245         return(false);
    1246     }
    1247     # endif
     1235    psS32 SubImageEndCol    = PS_MIN (image->numCols, SubImageCenterCol + radiusS32 + 1);
    12481236
    12491237    // XXX: Must recycle image.
     
    12551243        psFree(source->pixels);
    12561244    }
    1257     // XXX: Must fix this.  psImageSubset() has different parameters in latest CVS.
    1258     //    source->pixels = psImageSubset((psImage *) image,
    1259     //                                   SubImageStartCol,
    1260     //                                   SubImageStartRow,
    1261     //                                   SubImageEndCol,
    1262     //                                   SubImageEndRow);
     1245    source->pixels = psImageSubset((psImage *) image, psRegionSet(SubImageStartCol,
     1246                                   SubImageStartRow,
     1247                                   SubImageEndCol,
     1248                                   SubImageEndRow));
    12631249
    12641250    // XXX: Must recycle image.
     
    12681254    source->mask = psImageAlloc(source->pixels->numCols,
    12691255                                source->pixels->numRows,
    1270                                 PS_TYPE_F32);
     1256                                PS_TYPE_U8); // XXX EAM : type was F32
    12711257
    12721258    //
     
    12871273        }
    12881274    }
     1275    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
    12891276    return(true);
    12901277}
    12911278
    12921279/******************************************************************************
    1293 pmSourceModelGuess(source, image, model): This function allocates a new
    1294 pmModel structure and stores it in the pmSource data structure specified in
    1295 the argument list.  The model type is specified in the argument list.  The
    1296 params array in that pmModel structure are allocated, and then set to the
    1297 appropriate values.  This function returns true if everything was successful.
    1298  
    1299 XXX: Many of the initial parameters are set to 0.0 since I don't know what
    1300 the appropiate initial guesses are.
    1301  
    1302 XXX: The image argument is redundant.
     1280pmSourceModelGuess(source, model): This function allocates a new
     1281pmModel structure based on the given modelType specified in the argument list. 
     1282The corresponding pmModelGuess function is returned, and used to
     1283supply the values of the params array in the pmModel structure. 
    13031284 
    13041285XXX: Many parameters are based on the src->moments structure, which is in
    13051286image, not subImage coords.  Therefore, the calls to the model evaluation
    13061287functions will be in image, not subImage coords.  Remember this.
    1307  
    1308 XXX: The source->models member used to be allocated here.  Now I assume
    1309 ->modelPSF should be allocated
    1310 *****************************************************************************/
    1311 bool pmSourceModelGuess(pmSource *source,
    1312                         const psImage *image,
    1313                         pmModelType model)
    1314 {
    1315     PS_ASSERT_PTR_NON_NULL(source, false);
     1288*****************************************************************************/
     1289pmModel *pmSourceModelGuess(pmSource *source,
     1290                            pmModelType modelType)
     1291{
     1292    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    13161293    PS_ASSERT_PTR_NON_NULL(source->moments, false);
    13171294    PS_ASSERT_PTR_NON_NULL(source->peak, false);
    1318     PS_ASSERT_IMAGE_NON_NULL(image, false);
    1319     PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
    1320     if (source->modelPSF != NULL) {
    1321         psLogMsg(__func__, PS_LOG_WARN, "WARNING: source->modelPSF was non-NULL; calling psFree(source->modelPSF).\n");
    1322         psFree(source->modelPSF);
    1323     }
    1324     if (!((model == PS_MODEL_GAUSS) ||
    1325             (model == PS_MODEL_PGAUSS) ||
    1326             (model == PS_MODEL_WAUSS) ||
    1327             (model == PS_MODEL_TWIST_GAUSS) ||
    1328             (model == PS_MODEL_SERSIC) ||
    1329             (model == PS_MODEL_SERSIC_CORE))) {
    1330         psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
    1331         return(false);
    1332     }
    1333 
    1334     source->modelPSF = pmModelAlloc(model);
    1335 
    1336     psVector *params = source->modelPSF->params;
    1337 
    1338     switch (model) {
    1339     case PS_MODEL_GAUSS:
    1340         params->data.F32[0] = source->moments->Sky;
    1341         params->data.F32[1] = source->peak->counts - source->moments->Sky;
    1342         params->data.F32[2] = source->moments->x;
    1343         params->data.F32[3] = source->moments->y;
    1344         params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
    1345         params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
    1346         params->data.F32[6] = source->moments->Sxy;
    1347         return(true);
    1348 
    1349     case PS_MODEL_PGAUSS:
    1350         params->data.F32[0] = source->moments->Sky;
    1351         params->data.F32[1] = source->peak->counts - source->moments->Sky;
    1352         params->data.F32[2] = source->moments->x;
    1353         params->data.F32[3] = source->moments->y;
    1354         params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
    1355         params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
    1356         params->data.F32[6] = source->moments->Sxy;
    1357         return(true);
    1358 
    1359     case PS_MODEL_WAUSS:
    1360         params->data.F32[0] = source->moments->Sky;
    1361         params->data.F32[1] = source->peak->counts - source->moments->Sky;
    1362         params->data.F32[2] = source->moments->x;
    1363         params->data.F32[3] = source->moments->y;
    1364         params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
    1365         params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
    1366         params->data.F32[6] = source->moments->Sxy;
    1367         // XXX: What are these?
    1368         // source->modelPSF->params[7] = B2;
    1369         // source->modelPSF->params[8] = B3;
    1370         return(true);
    1371 
    1372         // XXX EAM : I might drop this model (or rather, replace it)
    1373     case PS_MODEL_TWIST_GAUSS:
    1374         params->data.F32[0] = source->moments->Sky;
    1375         params->data.F32[1] = source->peak->counts - source->moments->Sky;
    1376         params->data.F32[2] = source->moments->x;
    1377         params->data.F32[3] = source->moments->y;
    1378         // XXX: What are these?
    1379         // params->data.F32[4] = SxInner;
    1380         // params->data.F32[5] = SyInner;
    1381         // params->data.F32[6] = SxyInner;
    1382         // params->data.F32[7] = SxOuter;
    1383         // params->data.F32[8] = SyOuter;
    1384         // params->data.F32[9] = SxyOuter;
    1385         // params->data.F32[10] = N;
    1386         return(true);
    1387 
    1388     case PS_MODEL_SERSIC:
    1389         params->data.F32[0] = source->moments->Sky;
    1390         params->data.F32[1] = source->peak->counts - source->moments->Sky;
    1391         params->data.F32[2] = source->moments->x;
    1392         params->data.F32[3] = source->moments->y;
    1393         params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
    1394         params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
    1395         params->data.F32[6] = source->moments->Sxy;
    1396         // XXX: What are these?
    1397         //params->data.F32[7] = Nexp;
    1398         return(true);
    1399 
    1400     case PS_MODEL_SERSIC_CORE:
    1401         params->data.F32[0] = source->moments->Sky;
    1402         params->data.F32[1] = source->peak->counts - source->moments->Sky;
    1403         params->data.F32[2] = source->moments->x;
    1404         params->data.F32[3] = source->moments->y;
    1405         // XXX: What are these?
    1406         // params->data.F32[4] SxInner;
    1407         // params->data.F32[5] SyInner;
    1408         // params->data.F32[6] SxyInner;
    1409         // params->data.F32[7] Zd;
    1410         // params->data.F32[8] SxOuter;
    1411         // params->data.F32[9] SyOuter;
    1412         // params->data.F32[10] = SxyOuter;
    1413         // params->data.F32[11] = Nexp;
    1414         return(true);
    1415 
    1416     default:
    1417         psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
    1418         return(false);
    1419     }
     1295
     1296    pmModel *model = pmModelAlloc(modelType);
     1297
     1298    pmModelGuessFunc modelGuessFunc = pmModelGuessFunc_GetFunction(modelType);
     1299    modelGuessFunc(model, source);
     1300    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
     1301    return(model);
    14201302}
    14211303
     
    14411323testing.  Try to reproduce that and debug.
    14421324*****************************************************************************/
    1443 static psF32 evalModel(pmSource *src,
    1444                        psU32 row,
    1445                        psU32 col)
    1446 {
    1447     PS_ASSERT_PTR_NON_NULL(src, false);
    1448     PS_ASSERT_PTR_NON_NULL(src->modelPSF, false);
    1449     PS_ASSERT_PTR_NON_NULL(src->modelPSF->params, false);
    1450 
    1451     // XXX: The following step will not be necessary if the modelPSF->params
    1452     // member is a psVector.  Suggest to IfA.
    1453 
    1454     // XXX EAM: done: modelPSF->params is now a vector
    1455     psVector *params = src->modelPSF->params;
    1456 
    1457     //
     1325
     1326// XXX EAM : I have made this a public function
     1327// XXX EAM : this now uses a pmModel as the input
     1328// XXX EAM : it was using src->type to find the model, not model->type
     1329psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row)
     1330{
     1331    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1332    PS_ASSERT_PTR_NON_NULL(image, false);
     1333    PS_ASSERT_PTR_NON_NULL(model, false);
     1334    PS_ASSERT_PTR_NON_NULL(model->params, false);
     1335
    14581336    // Allocate the x coordinate structure and convert row/col to image space.
    14591337    //
    14601338    psVector *x = psVectorAlloc(2, PS_TYPE_F32);
    1461     x->data.F32[0] = (psF32) (col + src->pixels->col0);
    1462     x->data.F32[1] = (psF32) (row + src->pixels->row0);
     1339    x->data.F32[0] = (psF32) (col + image->col0);
     1340    x->data.F32[1] = (psF32) (row + image->row0);
    14631341    psF32 tmpF;
    1464 
    1465     switch (src->modelPSF->type) {
    1466     case PS_MODEL_GAUSS:
    1467         tmpF = pmMinLM_Gauss2D(NULL, params, x);
    1468         break;
    1469     case PS_MODEL_PGAUSS:
    1470         tmpF = pmMinLM_PsuedoGauss2D(NULL, params, x);
    1471         break;
    1472     case PS_MODEL_TWIST_GAUSS:
    1473         tmpF = pmMinLM_TwistGauss2D(NULL, params, x);
    1474         break;
    1475     case PS_MODEL_WAUSS:
    1476         tmpF = pmMinLM_Wauss2D(NULL, params, x);
    1477         break;
    1478     case PS_MODEL_SERSIC:
    1479         tmpF = pmMinLM_Sersic(NULL, params, x);
    1480         break;
    1481     case PS_MODEL_SERSIC_CORE:
    1482         tmpF = pmMinLM_SersicCore(NULL, params, x);
    1483         break;
    1484     default:
    1485         psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
    1486         return(NAN);
    1487     }
     1342    pmModelFunc modelFunc;
     1343
     1344    modelFunc = pmModelFunc_GetFunction (model->type);
     1345    tmpF = modelFunc (NULL, model->params, x);
    14881346    psFree(x);
     1347    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    14891348    return(tmpF);
    14901349}
     
    15081367                       psU32 dir)
    15091368{
     1369    psTrace(__func__, 4, "---- %s() begin ----\n", __func__);
    15101370    //
    15111371    // Convert coords to subImage space.
     
    15171377    if (!((0 <= subCol) && (subCol < source->pixels->numCols))) {
    15181378        psError(PS_ERR_UNKNOWN, true, "Starting column outside subImage range");
     1379        psTrace(__func__, 4, "---- %s(NAN) end ----\n", __func__);
    15191380        return(NAN);
    15201381    }
    15211382    if (!((0 <= subRow) && (subRow < source->pixels->numRows))) {
     1383        psTrace(__func__, 4, "---- %s(NAN) end ----\n", __func__);
    15221384        psError(PS_ERR_UNKNOWN, true, "Starting row outside subImage range");
    15231385        return(NAN);
    15241386    }
    15251387
    1526     psF32 oldValue = evalModel(source, subRow, subCol);
     1388    // XXX EAM : i changed this to match pmModelEval above, but see
     1389    // XXX EAM   the note below in pmSourceContour
     1390    psF32 oldValue = pmModelEval(source->modelFLT, source->pixels, subCol, subRow);
    15271391    if (oldValue == level) {
     1392        psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    15281393        return(((psF32) (subCol + source->pixels->col0)));
    15291394    }
     
    15451410
    15461411    while (subCol != lastColumn) {
    1547         psF32 newValue = evalModel(source, subRow, subCol);
     1412        psF32 newValue = pmModelEval(source->modelFLT, source->pixels, subCol, subRow);
    15481413        if (oldValue == level) {
     1414            psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    15491415            return((psF32) (subCol + source->pixels->col0));
    15501416        }
     
    15521418        if ((newValue <= level) && (level <= oldValue)) {
    15531419            // This is simple linear interpolation.
     1420            psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    15541421            return( ((psF32) (subCol + source->pixels->col0)) + ((psF32) incr) * ((level - newValue) / (oldValue - newValue)) );
    15551422        }
     
    15571424        if ((oldValue <= level) && (level <= newValue)) {
    15581425            // This is simple linear interpolation.
     1426            psTrace(__func__, 4, "---- %s() end ----\n", __func__);
    15591427            return( ((psF32) (subCol + source->pixels->col0)) + ((psF32) incr) * ((level - oldValue) / (newValue - oldValue)) );
    15601428        }
     
    15631431    }
    15641432
     1433    psTrace(__func__, 4, "---- %s(NAN) end ----\n", __func__);
    15651434    return(NAN);
    15661435}
     
    15761445XXX: What is mode?
    15771446XXX: The top, bottom of the contour is not correctly determined.
     1447XXX EAM : this functions is using the model for the contour, but it should
     1448          be using only the image counts
    15781449*****************************************************************************/
    15791450psArray *pmSourceContour(pmSource *source,
     
    15821453                         pmContourType mode)
    15831454{
     1455    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    15841456    PS_ASSERT_PTR_NON_NULL(source, false);
    15851457    PS_ASSERT_PTR_NON_NULL(image, false);
     
    15871459    PS_ASSERT_PTR_NON_NULL(source->peak, false);
    15881460    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
    1589     PS_ASSERT_PTR_NON_NULL(source->modelPSF, false);
     1461    PS_ASSERT_PTR_NON_NULL(source->modelFLT, false);
     1462    // XXX EAM : what is the purpose of modelPSF/modelFLT?
    15901463
    15911464    //
     
    16101483            psFree(xVec);
    16111484            psFree(yVec);
     1485            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    16121486            return(NULL);
    16131487            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
     
    16221496            psFree(xVec);
    16231497            psFree(yVec);
     1498            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    16241499            return(NULL);
    16251500            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
    16261501        }
    1627         //printf("The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept);
     1502        psTrace(__func__, 4, "The intercepts are (%.2f, %.2f)\n", leftIntercept, rightIntercept);
    16281503        xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept;
    16291504
     
    16461521            psFree(xVec);
    16471522            psFree(yVec);
     1523            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    16481524            return(NULL);
    16491525            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
     
    16571533            psFree(xVec);
    16581534            psFree(yVec);
     1535            psTrace(__func__, 3, "---- %s(NULL) end ----\n", __func__);
    16591536            return(NULL);
    16601537            //psLogMsg(__func__, PS_LOG_WARN, "WARNING: Could not find contour edge (NAN)\n");
     
    16721549    tmpArray->data[0] = (psPtr *) yVec;
    16731550    tmpArray->data[1] = (psPtr *) xVec;
     1551    psTrace(__func__, 3, "---- %s() end ----\n", __func__);
    16741552    return(tmpArray);
    16751553}
    16761554
    1677 #if 0
    1678 static psVector *minLM_Gauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1679 static psVector *minLM_PsuedoGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1680 static psVector *minLM_Wauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1681 static psVector *minLM_TwistGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1682 static psVector *minLM_Sersic_Vec(psImage *deriv, psVector *params, psArray *x);
    1683 static psVector *minLM_SersicCore_Vec(psImage *deriv, psVector *params, psArray *x);
    1684 #endif
    1685 
    16861555// XXX EAM : these are better starting values, but should be available from metadata?
    1687 #define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 20
     1556#define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 15
    16881557#define PM_SOURCE_FIT_MODEL_TOLERANCE 0.1
    16891558/******************************************************************************
    1690 pmSourceFitModel(source, image): must create the appropiate arguments to the
     1559pmSourceFitModel(source, model): must create the appropiate arguments to the
    16911560LM minimization routines for the various p_pmMinLM_XXXXXX_Vec() functions.
    16921561 
    16931562XXX: should there be a mask value?
    1694 XXX: Probably should remove the "image" argument.
    1695 *****************************************************************************/
    1696 bool pmSourceFitModel(pmSource *source,
    1697                       const psImage *image)
    1698 {
     1563XXX EAM : fit the specified model (not necessarily the one in source)
     1564*****************************************************************************/
     1565bool pmSourceFitModel_v5(pmSource *source,
     1566                         pmModel *model,
     1567                         const bool PSF)
     1568{
     1569    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
    16991570    PS_ASSERT_PTR_NON_NULL(source, false);
    17001571    PS_ASSERT_PTR_NON_NULL(source->moments, false);
    17011572    PS_ASSERT_PTR_NON_NULL(source->peak, false);
    17021573    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
    1703     PS_ASSERT_PTR_NON_NULL(source->modelPSF, false);
    1704     PS_ASSERT_IMAGE_NON_NULL(image, false);
    1705     PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
    1706     psBool rc;
     1574    PS_ASSERT_PTR_NON_NULL(source->mask, false);
     1575    PS_ASSERT_PTR_NON_NULL(source->weight, false);
     1576    psBool fitStatus = true;
     1577    psBool onPic     = true;
     1578    psBool rc        = true;
     1579
     1580    // XXX EAM : is it necessary for the mask & weight to exist?  the
     1581    //           tests below could be conditions (!NULL)
     1582
     1583    psVector *params = model->params;
     1584    psVector *dparams = model->dparams;
     1585    psVector *paramMask = NULL;
     1586
     1587    pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
     1588
     1589    int nParams = PSF ? params->n - 4 : params->n;
    17071590
    17081591    // find the number of valid pixels
     
    17161599            }
    17171600        }
     1601    }
     1602    if (count <  nParams + 1) {
     1603        psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n");
     1604        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     1605        return(false);
    17181606    }
    17191607
     
    17331621                x->data[tmpCnt] = (psPtr *) coord;
    17341622                y->data.F32[tmpCnt] = source->pixels->data.F32[i][j];
    1735 
    1736                 // XXX EAM : this is approximate: need to apply the gain and rdnoise
    1737                 yErr->data.F32[tmpCnt] = sqrt(PS_MAX(1, source->pixels->data.F32[i][j]));
     1623                yErr->data.F32[tmpCnt] = sqrt (source->weight->data.F32[i][j]);
     1624                // XXX EAM : note the wasted effort: we carry dY^2, take sqrt(), then
     1625                //           the minimization function calculates sq()
    17381626                tmpCnt++;
    17391627            }
     
    17441632                            PM_SOURCE_FIT_MODEL_TOLERANCE);
    17451633
    1746     psVector *params = source->modelPSF->params;
    1747 
    1748     switch (source->modelPSF->type) {
    1749     case PS_MODEL_GAUSS:
    1750         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Gauss2D);
    1751         break;
    1752     case PS_MODEL_PGAUSS:
    1753         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_PsuedoGauss2D);
    1754         break;
    1755     case PS_MODEL_TWIST_GAUSS:
    1756         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Wauss2D);
    1757         break;
    1758     case PS_MODEL_WAUSS:
    1759         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_TwistGauss2D);
    1760         break;
    1761     case PS_MODEL_SERSIC:
    1762         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Sersic);
    1763         break;
    1764     case PS_MODEL_SERSIC_CORE:
    1765         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_SersicCore);
    1766         break;
    1767     default:
    1768         psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
    1769         rc = false;
    1770     }
     1634    // PSF model only fits first 4 parameters, FLT model fits all
     1635    if (PSF) {
     1636        paramMask = psVectorAlloc (params->n, PS_TYPE_U8);
     1637        for (int i = 0; i < 4; i++) {
     1638            paramMask->data.U8[i] = 0;
     1639        }
     1640        for (int i = 4; i < paramMask->n; i++) {
     1641            paramMask->data.U8[i] = 1;
     1642        }
     1643    }
     1644
     1645    // XXX EAM : covar must be F64?
     1646    psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F64);
     1647
     1648    psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n");
     1649    fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc);
     1650    for (int i = 0; i < dparams->n; i++) {
     1651        if ((paramMask != NULL) && paramMask->data.U8[i])
     1652            continue;
     1653        dparams->data.F32[i] = sqrt(covar->data.F64[i][i]);
     1654    }
     1655
    17711656    // XXX EAM: we need to do something (give an error?) if rc is false
     1657    // XXX EAM: psMinimizeLMChi2 does not check convergence
     1658
     1659    // XXX models can go insane: reject these
     1660    onPic &= (params->data.F32[2] >= source->pixels->col0);
     1661    onPic &= (params->data.F32[2] <  source->pixels->col0 + source->pixels->numCols);
     1662    onPic &= (params->data.F32[3] >= source->pixels->row0);
     1663    onPic &= (params->data.F32[3] <  source->pixels->row0 + source->pixels->numRows);
     1664
    17721665    // XXX EAM: save the resulting chisq, nDOF, nIter
    1773     source->modelPSF->chisq = myMin->value;
    1774     source->modelPSF->nDOF  = y->n - params->n;
    1775     source->modelPSF->nIter = myMin->iter;
    1776 
     1666    model->chisq = myMin->value;
     1667    model->nIter = myMin->iter;
     1668    model->nDOF  = y->n - nParams;
     1669
     1670    // XXX EAM get the Gauss-Newton distance for fixed model parameters
     1671    if (paramMask != NULL) {
     1672        psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64);
     1673        psMinimizeGaussNewtonDelta (delta, params, NULL, x, y, yErr, modelFunc);
     1674        for (int i = 0; i < dparams->n; i++) {
     1675            if (!paramMask->data.U8[i])
     1676                continue;
     1677            dparams->data.F32[i] = delta->data.F64[i];
     1678        }
     1679        psFree (delta);
     1680    }
     1681
     1682    psFree(x);
     1683    psFree(y);
     1684    psFree(yErr);
     1685    psFree(myMin);
     1686    psFree(covar);
     1687    psFree(paramMask);
     1688
     1689    rc = (onPic && fitStatus);
     1690    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
     1691    return(rc);
     1692}
     1693
     1694// XXX EAM : new version with parameter range limits and weight enhancement
     1695bool pmSourceFitModel (pmSource *source,
     1696                       pmModel *model,
     1697                       const bool PSF)
     1698{
     1699    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1700    PS_ASSERT_PTR_NON_NULL(source, false);
     1701    PS_ASSERT_PTR_NON_NULL(source->moments, false);
     1702    PS_ASSERT_PTR_NON_NULL(source->peak, false);
     1703    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
     1704    PS_ASSERT_PTR_NON_NULL(source->mask, false);
     1705    PS_ASSERT_PTR_NON_NULL(source->weight, false);
     1706
     1707    // XXX EAM : is it necessary for the mask & weight to exist?  the
     1708    //           tests below could be conditions (!NULL)
     1709
     1710    psBool fitStatus = true;
     1711    psBool onPic     = true;
     1712    psBool rc        = true;
     1713    psF32  Ro, ymodel;
     1714
     1715    psVector *params = model->params;
     1716    psVector *dparams = model->dparams;
     1717    psVector *paramMask = NULL;
     1718
     1719    pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
     1720
     1721    // XXX EAM : I need to use the sky value to constrain the weight model
     1722    int nParams = PSF ? params->n - 4 : params->n;
     1723    psF32 So = params->data.F32[0];
     1724
     1725    // find the number of valid pixels
     1726    // XXX EAM : this loop and the loop below could just be one pass
     1727    //           using the psArrayAdd and psVectorExtend functions
     1728    psS32 count = 0;
     1729    for (psS32 i = 0; i < source->pixels->numRows; i++) {
     1730        for (psS32 j = 0; j < source->pixels->numCols; j++) {
     1731            if (source->mask->data.U8[i][j] == 0) {
     1732                count++;
     1733            }
     1734        }
     1735    }
     1736    if (count <  nParams + 1) {
     1737        psTrace (".pmObjects.pmSourceFitModel", 4, "insufficient valid pixels\n");
     1738        psTrace(__func__, 3, "---- %s(false) end ----\n", __func__);
     1739        return(false);
     1740    }
     1741
     1742    // construct the coordinate and value entries
     1743    psArray *x = psArrayAlloc(count);
     1744    psVector *y = psVectorAlloc(count, PS_TYPE_F32);
     1745    psVector *yErr = psVectorAlloc(count, PS_TYPE_F32);
     1746    psS32 tmpCnt = 0;
     1747    for (psS32 i = 0; i < source->pixels->numRows; i++) {
     1748        for (psS32 j = 0; j < source->pixels->numCols; j++) {
     1749            if (source->mask->data.U8[i][j] == 0) {
     1750                psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
     1751                // XXX: Convert i/j to image space:
     1752                // XXX EAM: coord order is (x,y) == (col,row)
     1753                coord->data.F32[0] = (psF32) (j + source->pixels->col0);
     1754                coord->data.F32[1] = (psF32) (i + source->pixels->row0);
     1755                x->data[tmpCnt] = (psPtr *) coord;
     1756                y->data.F32[tmpCnt] = source->pixels->data.F32[i][j];
     1757
     1758                // compare observed flux to model flux to adjust weight
     1759                ymodel = modelFunc (NULL, model->params, coord);
     1760
     1761                // this test enhances the weight based on deviation from the model flux
     1762                Ro = 1.0 + fabs (y->data.F32[tmpCnt] - ymodel) / sqrt(PS_SQR(ymodel - So) + PS_SQR(So));
     1763
     1764                // psMinimizeLMChi2_EAM takes wt = 1/dY^2
     1765                if (source->weight->data.F32[i][j] == 0) {
     1766                    yErr->data.F32[tmpCnt] = 0.0;
     1767                } else {
     1768                    yErr->data.F32[tmpCnt] = 1.0 / (source->weight->data.F32[i][j] * Ro);
     1769                }
     1770                tmpCnt++;
     1771            }
     1772        }
     1773    }
     1774
     1775    psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS,
     1776                            PM_SOURCE_FIT_MODEL_TOLERANCE);
     1777
     1778    // PSF model only fits first 4 parameters, FLT model fits all
     1779    if (PSF) {
     1780        paramMask = psVectorAlloc (params->n, PS_TYPE_U8);
     1781        for (int i = 0; i < 4; i++) {
     1782            paramMask->data.U8[i] = 0;
     1783        }
     1784        for (int i = 4; i < paramMask->n; i++) {
     1785            paramMask->data.U8[i] = 1;
     1786        }
     1787    }
     1788
     1789    // XXX EAM : I've added three types of parameter range checks
     1790    // XXX EAM : this requires my new psMinimization functions
     1791    pmModelLimits modelLimits = pmModelLimits_GetFunction (model->type);
     1792    psVector *beta_lim = NULL;
     1793    psVector *params_min = NULL;
     1794    psVector *params_max = NULL;
     1795
     1796    // XXX EAM : in this implementation, I pass in the limits with the covar matrix.
     1797    //           in the SDRS, I define a new psMinimization which will take these in
     1798    psImage *covar = psImageAlloc (params->n, 3, PS_TYPE_F64);
     1799    modelLimits (&beta_lim, &params_min, &params_max);
     1800    for (int i = 0; i < params->n; i++) {
     1801        covar->data.F64[0][i] = beta_lim->data.F32[i];
     1802        covar->data.F64[1][i] = params_min->data.F32[i];
     1803        covar->data.F64[2][i] = params_max->data.F32[i];
     1804    }
     1805
     1806    psTrace (".pmObjects.pmSourceFitModel", 5, "fitting function\n");
     1807    fitStatus = psMinimizeLMChi2(myMin, covar, params, paramMask, x, y, yErr, modelFunc);
     1808    for (int i = 0; i < dparams->n; i++) {
     1809        if ((paramMask != NULL) && paramMask->data.U8[i])
     1810            continue;
     1811        dparams->data.F32[i] = sqrt(covar->data.F64[i][i]);
     1812    }
     1813
     1814    // XXX EAM: we need to do something (give an error?) if rc is false
     1815    // XXX EAM: psMinimizeLMChi2 does not check convergence
     1816
     1817    // XXX models can go insane: reject these
     1818    onPic &= (params->data.F32[2] >= source->pixels->col0);
     1819    onPic &= (params->data.F32[2] <  source->pixels->col0 + source->pixels->numCols);
     1820    onPic &= (params->data.F32[3] >= source->pixels->row0);
     1821    onPic &= (params->data.F32[3] <  source->pixels->row0 + source->pixels->numRows);
     1822
     1823    // XXX EAM: save the resulting chisq, nDOF, nIter
     1824    model->chisq = myMin->value;
     1825    model->nIter = myMin->iter;
     1826    model->nDOF  = y->n - nParams;
     1827
     1828    // XXX EAM get the Gauss-Newton distance for fixed model parameters
     1829    if (paramMask != NULL) {
     1830        psVector *delta = psVectorAlloc (params->n, PS_TYPE_F64);
     1831        psMinimizeGaussNewtonDelta(delta, params, NULL, x, y, yErr, modelFunc);
     1832        for (int i = 0; i < dparams->n; i++) {
     1833            if (!paramMask->data.U8[i])
     1834                continue;
     1835            dparams->data.F32[i] = delta->data.F64[i];
     1836        }
     1837    }
     1838
     1839    psFree(paramMask);
    17771840    psFree(x);
    17781841    psFree(y);
    17791842    psFree(myMin);
     1843
     1844    rc = (onPic && fitStatus);
     1845    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
    17801846    return(rc);
    17811847}
    17821848
    1783 static bool sourceAddOrSubModel(psImage *image,
    1784                                 pmSource *src,
    1785                                 bool center,
    1786                                 psS32 flag)
    1787 {
    1788     PS_ASSERT_PTR_NON_NULL(src, false);
    1789     PS_ASSERT_PTR_NON_NULL(src->moments, false);
    1790     PS_ASSERT_PTR_NON_NULL(src->peak, false);
    1791     PS_ASSERT_PTR_NON_NULL(src->pixels, false);
    1792     PS_ASSERT_PTR_NON_NULL(src->modelPSF, false);
     1849bool p_pmSourceAddOrSubModel(psImage *image,
     1850                             psImage *mask,
     1851                             pmModel *model,
     1852                             bool center,
     1853                             psS32 flag)
     1854{
     1855    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1856
     1857    PS_ASSERT_PTR_NON_NULL(model, false);
    17931858    PS_ASSERT_IMAGE_NON_NULL(image, false);
    17941859    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
    17951860
    17961861    psVector *x = psVectorAlloc(2, PS_TYPE_F32);
    1797     psVector *params = src->modelPSF->params;
    1798 
    1799     for (psS32 i = 0; i < src->pixels->numRows; i++) {
    1800         for (psS32 j = 0; j < src->pixels->numCols; j++) {
     1862    psVector *params = model->params;
     1863    pmModelFunc modelFunc = pmModelFunc_GetFunction (model->type);
     1864    psS32 imageCol;
     1865    psS32 imageRow;
     1866
     1867    for (psS32 i = 0; i < image->numRows; i++) {
     1868        for (psS32 j = 0; j < image->numCols; j++) {
     1869            if ((mask != NULL) && mask->data.U8[i][j])
     1870                continue;
    18011871            psF32 pixelValue;
    18021872            // XXX: Should you be adding the pixels for the entire subImage,
     
    18051875            // Convert i/j to imace coord space:
    18061876            // XXX: Make sure you have col/row order correct.
    1807             psS32 imageRow = i + src->pixels->row0;
    1808             psS32 imageCol = j + src->pixels->col0;
     1877            // XXX EAM : 'center' option changes this
     1878            // XXX EAM : i == numCols/2 -> x = model->params->data.F32[2]
     1879            if (center) {
     1880                imageCol = j - 0.5*image->numCols + model->params->data.F32[2];
     1881                imageRow = i - 0.5*image->numRows + model->params->data.F32[3];
     1882            } else {
     1883                imageCol = j + image->col0;
     1884                imageRow = i + image->row0;
     1885            }
    18091886
    18101887            x->data.F32[0] = (float) imageCol;
    18111888            x->data.F32[1] = (float) imageRow;
    1812             switch (src->modelPSF->type) {
    1813             case PS_MODEL_GAUSS:
    1814                 pixelValue = pmMinLM_Gauss2D(NULL, params, x);
    1815                 break;
    1816             case PS_MODEL_PGAUSS:
    1817                 pixelValue = pmMinLM_PsuedoGauss2D(NULL, params, x);
    1818                 break;
    1819             case PS_MODEL_TWIST_GAUSS:
    1820                 pixelValue = pmMinLM_TwistGauss2D(NULL, params, x);
    1821                 break;
    1822             case PS_MODEL_WAUSS:
    1823                 pixelValue = pmMinLM_Wauss2D(NULL, params, x);
    1824                 break;
    1825             case PS_MODEL_SERSIC:
    1826                 pixelValue = pmMinLM_Sersic(NULL, params, x);
    1827                 break;
    1828             case PS_MODEL_SERSIC_CORE:
    1829                 pixelValue = pmMinLM_SersicCore(NULL, params, x);
    1830                 break;
    1831             default:
    1832                 psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
    1833                 psFree(x);
    1834                 return(false);
    1835             }
     1889            pixelValue = modelFunc (NULL, params, x);
     1890            // fprintf (stderr, "%f %f  %d %d  %f\n", x->data.F32[0], x->data.F32[1], i, j, pixelValue);
     1891
    18361892            if (flag == 1) {
    18371893                pixelValue = -pixelValue;
     
    18411897            // how to use the boolean "center" flag.
    18421898
    1843             image->data.F32[imageRow][imageCol]+= pixelValue;
     1899            image->data.F32[i][j]+= pixelValue;
    18441900        }
    18451901    }
    18461902    psFree(x);
     1903    psTrace(__func__, 3, "---- %s(true) end ----\n", __func__);
    18471904    return(true);
    18481905}
     
    18531910 *****************************************************************************/
    18541911bool pmSourceAddModel(psImage *image,
    1855                       pmSource *src,
     1912                      psImage *mask,
     1913                      pmModel *model,
    18561914                      bool center)
    18571915{
    1858     return(sourceAddOrSubModel(image, src, center, 0));
     1916    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1917    psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, 0);
     1918    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
     1919    return(rc);
    18591920}
    18601921
     
    18621923 *****************************************************************************/
    18631924bool pmSourceSubModel(psImage *image,
    1864                       pmSource *src,
     1925                      psImage *mask,
     1926                      pmModel *model,
    18651927                      bool center)
    18661928{
    1867     return(sourceAddOrSubModel(image, src, center, 1));
    1868 }
    1869 
    1870 
    1871 // XXX: Put this is psConstants.h
    1872 #define PS_VECTOR_CHECK_SIZE(VEC1, N, RVAL) \
    1873 if (VEC1->n != N) { \
    1874     psError(PS_ERR_BAD_PARAMETER_SIZE, true, \
    1875             "psVector %s has size %d, should be %d.", \
    1876             #VEC1, VEC1->n, N); \
    1877     return(RVAL); \
    1878 }
    1879 
    1880 
    1881 /**
    1882    all of these object representation functions have the same form : func(*deriv, *params, *x)
    1883  
    1884    the argument "x" contains a single "x,y" coordinate pair.  The function computes the object
    1885    model, based on the parameters in "params" at the x,y point specified by *x, and returns the value.
    1886    The derivatives are also caculated and returned in the "deriv" argument.  parameter error checking is
    1887    skipped because speed is most important.
    1888 **/
    1889 
    1890 /******************************************************************************
    1891     params->data.F32[0] = So;
    1892     params->data.F32[1] = Zo;
    1893     params->data.F32[2] = Xo;
    1894     params->data.F32[3] = Yo;
    1895     params->data.F32[4] = sqrt(2.0) / SigmaX;
    1896     params->data.F32[5] = sqrt(2.0) / SigmaY;
    1897     params->data.F32[6] = Sxy;
    1898 *****************************************************************************/
    1899 float pmMinLM_Gauss2D(
    1900     psVector *deriv,
    1901     const psVector *params,
    1902     const psVector *x)
    1903 {
    1904     PS_ASSERT_VECTOR_NON_NULL(params, NAN);
    1905     PS_ASSERT_VECTOR_NON_NULL(x, NAN);
    1906     psF32 X  = x->data.F32[0] - params->data.F32[2];
    1907     psF32 Y  = x->data.F32[1] - params->data.F32[3];
    1908     psF32 px = params->data.F32[4]*X;
    1909     psF32 py = params->data.F32[5]*Y;
    1910     psF32 z  = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
    1911     psF32 r  = exp(-z);
    1912     psF32 q  = params->data.F32[1]*r;
    1913     psF32 f  = q + params->data.F32[0];
    1914 
    1915     if (deriv != NULL) {
    1916         deriv->data.F32[0] = +1.0;
    1917         deriv->data.F32[1] = +r;
    1918         deriv->data.F32[2] = q*(2*px*params->data.F32[4] + params->data.F32[6]*Y);
    1919         deriv->data.F32[3] = q*(2*py*params->data.F32[5] + params->data.F32[6]*X);
    1920         deriv->data.F32[4] = -2.0*q*px*X;
    1921         deriv->data.F32[5] = -2.0*q*py*Y;
    1922         deriv->data.F32[6] = -q*X*Y;
    1923     }
    1924     return(f);
    1925 }
    1926 
    1927 /******************************************************************************
    1928     params->data.F32[0] = So;
    1929     params->data.F32[1] = Zo;
    1930     params->data.F32[2] = Xo;
    1931     params->data.F32[3] = Yo;
    1932     params->data.F32[4] = sqrt(2) / SigmaX;
    1933     params->data.F32[5] = sqrt(2) / SigmaY;
    1934     params->data.F32[6] = Sxy;
    1935 *****************************************************************************/
    1936 float pmMinLM_PsuedoGauss2D(
    1937     psVector *deriv,
    1938     const psVector *params,
    1939     const psVector *x)
    1940 {
    1941     PS_ASSERT_VECTOR_NON_NULL(params, NAN);
    1942     PS_ASSERT_VECTOR_NON_NULL(x, NAN);
    1943     psF32 X  = x->data.F32[0] - params->data.F32[2];
    1944     psF32 Y  = x->data.F32[1] - params->data.F32[3];
    1945     psF32 px = params->data.F32[4]*X;
    1946     psF32 py = params->data.F32[5]*Y;
    1947     psF32 z  = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
    1948     psF32 t  = 1 + z + 0.5*z*z;
    1949     psF32 r  = 1.0 / (t*(1 + z/3)); /* exp (-Z) */
    1950     psF32 f  = params->data.F32[1]*r + params->data.F32[0];
    1951 
    1952     if (deriv != NULL) {
    1953         // note difference from a pure gaussian: q = params->data.F32[1]*r
    1954         psF32 q = params->data.F32[1]*r*r*t;
    1955         deriv->data.F32[0] = +1.0;
    1956         deriv->data.F32[1] = +r;
    1957         deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
    1958         deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X);
    1959         deriv->data.F32[4] = -2.0*q*px*X;
    1960         deriv->data.F32[5] = -2.0*q*py*Y;
    1961         deriv->data.F32[6] = -q*X*Y;
    1962     }
    1963     return(f);
    1964 }
    1965 
    1966 /******************************************************************************
    1967     params->data.F32[0] = So;
    1968     params->data.F32[1] = Zo;
    1969     params->data.F32[2] = Xo;
    1970     params->data.F32[3] = Yo;
    1971     params->data.F32[4] = Sx;
    1972     params->data.F32[5] = Sy;
    1973     params->data.F32[6] = Sxy;
    1974     params->data.F32[7] = B2;
    1975     params->data.F32[8] = B3;
    1976 *****************************************************************************/
    1977 float pmMinLM_Wauss2D(
    1978     psVector *deriv,
    1979     const psVector *params,
    1980     const psVector *x)
    1981 {
    1982     PS_ASSERT_VECTOR_NON_NULL(params, NAN);
    1983     PS_ASSERT_VECTOR_NON_NULL(x, NAN);
    1984     psF32 X = x->data.F32[0] - params->data.F32[2];
    1985     psF32 Y = x->data.F32[1] - params->data.F32[2];
    1986     psF32 px = params->data.F32[4]*X;
    1987     psF32 py = params->data.F32[5]*Y;
    1988     psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
    1989     psF32 t = 0.5*z*z*(1.0 + params->data.F32[8]*z/3.0);
    1990     psF32 r = 1.0 / (1.0 + z + params->data.F32[7]*t); /* exp (-Z) */
    1991     psF32 f = params->data.F32[1]*r + params->data.F32[0];
    1992 
    1993     if (deriv != NULL) {
    1994         // note difference from gaussian: q = params->data.F32[1]*r
    1995         psF32 q = params->data.F32[1]*r*r*(1.0 + params->data.F32[7]*z*(1.0 + params->data.F32[8]*z/2.0));
    1996         deriv->data.F32[0] = +1.0;
    1997         deriv->data.F32[1] = +r;
    1998         deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
    1999         deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X);
    2000         deriv->data.F32[4] = -2.0*q*px*X;
    2001         deriv->data.F32[5] = -2.0*q*py*Y;
    2002         deriv->data.F32[6] = -q*X*Y;
    2003         deriv->data.F32[7] = -100.0*params->data.F32[1]*r*r*t;
    2004         deriv->data.F32[8] = -100.0*params->data.F32[1]*r*r*params->data.F32[7]*(z*z*z)/6.0;
    2005         // The values of 100 dampen the swing of params->data.F32[7,8] */
    2006     }
    2007     return(f);
    2008 }
    2009 
    2010 // XXX: What should these be?
    2011 #define FFACTOR 1.0
    2012 #define FSCALE 1.0
    2013 /******************************************************************************
    2014     params->data.F32[0] = So;
    2015     params->data.F32[1] = Zo;
    2016     params->data.F32[2] = Xo;
    2017     params->data.F32[3] = Yo;
    2018     params->data.F32[4] = SxInner;
    2019     params->data.F32[5] = SyInner;
    2020     params->data.F32[6] = SxyInner;
    2021     params->data.F32[7] = SxOuter;
    2022     params->data.F32[8] = SyOuter;
    2023     params->data.F32[9] = SxyOuter;
    2024     params->data.F32[10] = N;
    2025 *****************************************************************************/
    2026 float pmMinLM_TwistGauss2D(
    2027     psVector *deriv,
    2028     const psVector *params,
    2029     const psVector *x)
    2030 {
    2031     PS_ASSERT_VECTOR_NON_NULL(params, NAN);
    2032     PS_ASSERT_VECTOR_NON_NULL(x, NAN);
    2033     psF32 X = x->data.F32[0] - params->data.F32[2];
    2034     psF32 Y = x->data.F32[1] - params->data.F32[3];
    2035     psF32 px1 = params->data.F32[4]*X;
    2036     psF32 py1 = params->data.F32[5]*Y;
    2037     psF32 px2 = params->data.F32[7]*X;
    2038     psF32 py2 = params->data.F32[8]*Y;
    2039     psF32 z1 = 0.5*PS_SQR(px1) + 0.5*PS_SQR(py1) + params->data.F32[4]*X*Y;
    2040     psF32 z2 = 0.5*PS_SQR(px2) + 0.5*PS_SQR(py2) + params->data.F32[9]*X*Y;
    2041     psF32 r = 1.0 / (1.0 + z1 + pow(z2,params->data.F32[10]));
    2042 
    2043     psF32 f = params->data.F32[5]*r + params->data.F32[6];
    2044 
    2045     if (deriv != NULL) {
    2046         psF32 q1 = params->data.F32[5]*PS_SQR(r);
    2047         psF32 q2 = params->data.F32[5]*PS_SQR(r)*params->data.F32[10]*pow(z2,(params->data.F32[10]-1.0));
    2048         deriv->data.F32[0] = +1.0;
    2049         deriv->data.F32[1] = +r;
    2050         deriv->data.F32[2] = q1*(2.0*px1*params->data.F32[4] + params->data.F32[6]*Y) + q2*(2*px2*params->data.F32[7] + params->data.F32[9]*Y);
    2051         deriv->data.F32[3] = q1*(2.0*py1*params->data.F32[5] + params->data.F32[6]*X) + q2*(2*py2*params->data.F32[8] + params->data.F32[9]*X);
    2052 
    2053         // These fudge factors impede the growth of params->data.F32[4] beyond
    2054         // params->data.F32[7].
    2055         psF32 f1 = fabs(params->data.F32[7]) / fabs(params->data.F32[4]);
    2056         psF32 f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
    2057         deriv->data.F32[4] = -2.0*q1*px1*X*f2;
    2058 
    2059         // These fudge factors impede the growth of params->data.F32[5] beyond
    2060         // params->data.F32[8].
    2061         f1 = fabs(params->data.F32[8]) / fabs(params->data.F32[5]);
    2062         f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
    2063         deriv->data.F32[5] = -2.0*q1*py1*Y*f2;
    2064         deriv->data.F32[6] = -q1*X*Y;
    2065         deriv->data.F32[7] = -2.0*q2*px2*X;
    2066         deriv->data.F32[8] = -2.0*q2*py2*Y;
    2067         deriv->data.F32[9] = -q2*X*Y;
    2068         deriv->data.F32[10] = -q1*log(z2);
    2069     }
    2070 
    2071     return(f);
    2072 }
    2073 
    2074 /******************************************************************************
    2075     float Sersic()
    2076     params->data.F32[0] = So;
    2077     params->data.F32[1] = Zo;
    2078     params->data.F32[2] = Xo;
    2079     params->data.F32[3] = Yo;
    2080     params->data.F32[4] = Sx;
    2081     params->data.F32[5] = Sy;
    2082     params->data.F32[6] = Sxy;
    2083     params->data.F32[7] = Nexp;
    2084 *****************************************************************************/
    2085 float pmMinLM_Sersic(
    2086     psVector *deriv,
    2087     const psVector *params,
    2088     const psVector *x)
    2089 {
    2090     PS_ASSERT_VECTOR_NON_NULL(params, NAN);
    2091     PS_ASSERT_VECTOR_NON_NULL(x, NAN);
    2092     psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
    2093     return(0.0);
    2094 }
    2095 
    2096 /******************************************************************************
    2097     float SersicBulge()
    2098     params->data.F32[0] So;
    2099     params->data.F32[1] Zo;
    2100     params->data.F32[2] Xo;
    2101     params->data.F32[3] Yo;
    2102     params->data.F32[4] SxInner;
    2103     params->data.F32[5] SyInner;
    2104     params->data.F32[6] SxyInner;
    2105     params->data.F32[7] Zd;
    2106     params->data.F32[8] SxOuter;
    2107     params->data.F32[9] SyOuter;
    2108     params->data.F32[10] = SxyOuter;
    2109     params->data.F32[11] = Nexp;
    2110 *****************************************************************************/
    2111 float pmMinLM_SersicCore(
    2112     psVector *deriv,
    2113     const psVector *params,
    2114     const psVector *x)
    2115 {
    2116     PS_ASSERT_VECTOR_NON_NULL(params, NAN);
    2117     PS_ASSERT_VECTOR_NON_NULL(x, NAN);
    2118     psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
    2119     return(0.0);
    2120 }
     1929    psTrace(__func__, 3, "---- %s() begin ----\n", __func__);
     1930    psBool rc = p_pmSourceAddOrSubModel(image, mask, model, center, 1);
     1931    psTrace(__func__, 3, "---- %s(%d) end ----\n", __func__, rc);
     1932    return(rc);
     1933}
     1934
     1935
  • trunk/psModules/src/objects/pmObjects.h

    r5170 r5255  
    11/** @file  pmObjects.h
    22 *
    3  *  This file will ...
     3 * The process of finding, measuring, and classifying astronomical sources on
     4 * images is one of the critical tasks of the IPP or any astronomical software
     5 * system. This file will define structures and functions related to the task
     6 * of source detection and measurement. The elements defined in this section
     7 * are generally low-level components which can be connected together to
     8 * construct a complete object measurement suite.
    49 *
    510 *  @author GLG, MHPCC
    611 *
    7  *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
    8  *  @date $Date: 2005-09-28 20:43:52 $
     12 *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
     13 *  @date $Date: 2005-10-10 19:53:40 $
    914 *
    1015 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    1924#endif
    2025
    21 #include<stdio.h>
    22 #include<math.h>
     26#include <stdio.h>
     27#include <math.h>
    2328#include "pslib.h"
     29#include "pmAstrometry.h"
     30/**
     31 * In the object analysis process, we will use specific mask values to mark the
     32 * image pixels. The following structure defines the relevant mask values.
     33 *
     34 * XXX: This is probably a bad solution: we will want to set mask values
     35 * outside of the PSPHOT code.  Perhaps we can set up a registered set of mask
     36 * values with specific meanings that other functions can add to or define?
     37 */
     38enum {
     39    PSPHOT_MASK_CLEAR     = 0x00,
     40    PSPHOT_MASK_INVALID   = 0x01,
     41    PSPHOT_MASK_SATURATED = 0x02,
     42    PSPHOT_MASK_MARKED    = 0x08,
     43} psphotMaskValues;
     44
    2445
    2546/** pmPeakType
     
    4061} pmPeakType;
    4162
     63
    4264/** pmPeak data structure
     65 * 
     66 *  A source has the capacity for several types of measurements. The
     67 *  simplest measurement of a source is the location and flux of the peak pixel
     68 *  associated with the source:
    4369 * 
    4470 */
     
    5278pmPeak;
    5379
     80
    5481/** pmMoments data structure
     82 * 
     83 * One of the simplest measurements which can be made quickly for an object
     84 * are the object moments. We specify a structure to carry the moment information
     85 * for a specific source:
    5586 * 
    5687 */
    5788typedef struct
    5889{
    59     float x;                            ///< X-coord of centroid.
    60     float y;                            ///< Y-coord of centroid.
    61     float Sx;                           ///< x-second moment.
    62     float Sy;                           ///< y-second moment.
    63     float Sxy;                          ///< xy cross moment.
    64     float Sum;                          ///< Pixel sum above sky (background).
    65     float Peak;                         ///< Peak counts above sky.
    66     float Sky;                          ///< Sky level (background).
    67     int nPixels;                        ///< Number of pixels used.
     90    float x;    ///< X-coord of centroid.
     91    float y;    ///< Y-coord of centroid.
     92    float Sx;    ///< x-second moment.
     93    float Sy;    ///< y-second moment.
     94    float Sxy;    ///< xy cross moment.
     95    float Sum;    ///< Pixel sum above sky (background).
     96    float Peak;    ///< Peak counts above sky.
     97    float Sky;    ///< Sky level (background).
     98    float SN;    ///< approx signal-to-noise
     99    int nPixels;   ///< Number of pixels used.
    68100}
    69101pmMoments;
    70102
    71 /** pmModelType enumeration
    72  * 
    73  */
    74 typedef enum {
    75     PS_MODEL_GAUSS,                     ///< Regular 2-D Gaussian
    76     PS_MODEL_PGAUSS,                    ///< Psuedo 2-D Gaussian
    77     PS_MODEL_TWIST_GAUSS,               ///< 2-D Twisted Gaussian
    78     PS_MODEL_WAUSS,                     ///< 2-D Waussian
    79     PS_MODEL_SERSIC,                    ///< Sersic
    80     PS_MODEL_SERSIC_CORE,               ///< Sersic Core
    81     PS_MODEL_UNDEFINED                  ///< Undefined
    82 } pmModelType;
    83 
    84 /** pmModel data structure
    85  * 
    86  */
    87 // XXX: The SDRS has the "type" member of type psS32.
     103
     104/** pmPSFClump data structure
     105 *
     106 * A collection of object moment measurements can be used to determine
     107 * approximate object classes. The key to this analysis is the location and
     108 * statistics (in the second-moment plane,
     109 * 
     110 */
    88111typedef struct
    89112{
    90     pmModelType type;                   ///< Model to be used.
    91     psVector *params;                   ///< Paramater values.
    92     psVector *dparams;                  ///< Parameter errors.
    93     float chisq;                        ///< Fit chi-squared.
    94     int nDOF;                           ///< number of degrees of freedom
    95     int nIter;                          ///< number of iterations to reach min
     113    float X;
     114    float dX;
     115    float Y;
     116    float dY;
     117}
     118pmPSFClump;
     119
     120typedef int pmModelType;
     121#define PS_MODEL_GAUSS 0
     122#define PS_MODEL_PGAUSS 1
     123#define PS_MODEL_QGAUSS 2
     124#define PS_MODEL_SGAUSS 3
     125
     126
     127/** pmModel data structure
     128 *
     129 * Every source may have two types of models: a PSF model and a FLT (floating)
     130 * model. The PSF model represents the best fit of the image PSF to the specific
     131 * object. In this case, the PSF-dependent parameters are specified for the
     132 * object by the PSF, not by the fit. The FLT model represents the best fit of
     133 * the given model to the object, with all parameters floating in the fit.
     134 * 
     135 */
     136typedef struct
     137{
     138    pmModelType type;   ///< Model to be used.
     139    psVector *params;   ///< Paramater values.
     140    psVector *dparams;   ///< Parameter errors.
     141    float chisq;   ///< Fit chi-squared.
     142    int nDOF;    ///< number of degrees of freedom
     143    int nIter;    ///< number of iterations to reach min
     144    float radius;   ///< fit radius actually used
    96145}
    97146pmModel;
    98147
    99148/** pmSourceType enumeration
    100  * 
    101  * 
    102  * 
     149 *
     150 * A given source may be identified as most-likely to be one of several source
     151 * types. The pmSource entry pmSourceType defines the current best-guess for this
     152 * source.
     153 *
     154 * XXX: The values given below are currently illustrative and will require
     155 * some modification as the source classification code is developed. (TBD)
     156 *
    103157 */
    104158typedef enum {
    105     PS_SOURCE_PSFSTAR,
    106     PS_SOURCE_GALAXY,
    107     PS_SOURCE_DEFECT,
    108     PS_SOURCE_SATURATED,
    109     PS_SOURCE_SATSTAR,
    110     PS_SOURCE_FAINTSTAR,
    111     PS_SOURCE_BRIGHTSTAR,
    112     PS_SOURCE_OTHER
     159    PM_SOURCE_DEFECT,                   ///< a cosmic-ray
     160    PM_SOURCE_SATURATED,                ///< random saturated pixels
     161
     162    PM_SOURCE_SATSTAR,                  ///< a saturated star
     163    PM_SOURCE_PSFSTAR,                  ///< a PSF star
     164    PM_SOURCE_GOODSTAR,                 ///< a good-quality star
     165
     166    PM_SOURCE_POOR_FIT_PSF,             ///< poor quality PSF fit
     167    PM_SOURCE_FAIL_FIT_PSF,             ///< failed to get a good PSF fit
     168    PM_SOURCE_FAINTSTAR,                ///< below S/N cutoff
     169
     170    PM_SOURCE_GALAXY,                   ///< an extended object (galaxy)
     171    PM_SOURCE_FAINT_GALAXY,             ///< a galaxy below S/N cutoff
     172    PM_SOURCE_DROP_GALAXY,              ///< ?
     173    PM_SOURCE_FAIL_FIT_GAL,             ///< failed on the galaxy fit
     174    PM_SOURCE_POOR_FIT_GAL,             ///< poor quality galaxy fit
     175
     176    PM_SOURCE_OTHER,                    ///< unidentified
    113177} pmSourceType;
    114178
     
    122186typedef struct
    123187{
    124     pmPeak *peak;                       ///< Description of peak pixel.
    125     psImage *pixels;                    ///< Rectangular region including object pixels.
    126     psImage *mask;                      ///< Mask which marks pixels associated with objects.
    127     pmMoments *moments;                 ///< Basic moments measure for the object.
    128     pmModel *modelPSF;                  ///< PSF model parameters and type
    129     pmModel *modelFLT;                  ///< FLT model parameters and type
    130     pmSourceType type;                  ///< Best identification of object.
     188    pmPeak *peak;   ///< Description of peak pixel.
     189    psImage *pixels;   ///< Rectangular region including object pixels.
     190    psImage *weight;   ///< Image variance.
     191    psImage *mask;   ///< Mask which marks pixels associated with objects.
     192    pmMoments *moments;   ///< Basic moments measure for the object.
     193    pmModel *modelPSF;   ///< PSF Model fit (parameters and type)
     194    pmModel *modelFLT;   ///< FLT (floating) Model fit (parameters and type).
     195    pmSourceType type;   ///< Best identification of object.
    131196}
    132197pmSource;
    133198
    134 /** pmPeak data structure
    135  * 
    136  * 
    137  * 
    138  */
    139 typedef struct
    140 {
    141     psS32 type;                         ///< PSF Model in use
    142     psArray *params;                    ///< Model parameters (psPolynomial2D)
    143     psF32 chisq;                        ///< PSF goodness statistic
    144     psS32 nPSFstars;                    ///< number of stars used to measure PSF
    145 }
    146 pmPSF;
    147 
    148 
    149 
     199
     200/** pmPeakAlloc()
     201 *
     202 *  @return pmPeak*    newly allocated pmPeak with all internal pointers set to NULL
     203 */
    150204pmPeak *pmPeakAlloc(
    151     int x,                              ///< Row-coordinate in image space
    152     int y,                              ///< Col-coordinate in image space
    153     float counts,                       ///< The value of the peak pixel
    154     pmPeakType class                    ///< The type of peak pixel
    155 );
    156 
     205    int x,    ///< Row-coordinate in image space
     206    int y,    ///< Col-coordinate in image space
     207    float counts,   ///< The value of the peak pixel
     208    pmPeakType class   ///< The type of peak pixel
     209);
     210
     211
     212/** pmMomentsAlloc()
     213 *
     214 */
    157215pmMoments *pmMomentsAlloc();
     216
     217
     218/** pmModelAlloc()
     219 *
     220 */
    158221pmModel *pmModelAlloc(pmModelType type);
    159 pmSource *pmSourceAlloc();
    160 
    161 /******************************************************************************
    162 pmFindVectorPeaks(vector, threshold): Find all local peaks in the given vector
    163 above the given threshold.  Returns a vector of type PS_TYPE_U32 containing
    164 the location (x value) of all peaks.
    165  *****************************************************************************/
     222
     223
     224/** pmSourceAlloc()
     225 *
     226 */
     227pmSource  *pmSourceAlloc();
     228
     229
     230/** pmFindVectorPeaks()
     231 *
     232 * Find all local peaks in the given vector above the given threshold. A peak
     233 * is defined as any element with a value greater than its two neighbors and with
     234 * a value above the threshold. Two types of special cases must be addressed.
     235 * Equal value elements: If an element has the same value as the following
     236 * element, it is not considered a peak. If an element has the same value as the
     237 * preceding element (but not the following), then it is considered a peak. Note
     238 * that this rule (arbitrarily) identifies flat regions by their trailing edge.
     239 * Edge cases: At start of the vector, the element must be higher than its
     240 * neighbor. At the end of the vector, the element must be higher or equal to its
     241 * neighbor. These two rules again places the peak associated with a flat region
     242 * which touches the image edge at the image edge. The result of this function is
     243 * a vector containing the coordinates (element number) of the detected peaks
     244 * (type psU32).
     245 *
     246 */
    166247psVector *pmFindVectorPeaks(
    167     const psVector *vector,             ///< The input vector (float)
    168     float threshold                     ///< Threshold above which to find a peak
    169 );
    170 
    171 /******************************************************************************
    172 pmFindImagePeaks(image, threshold): Find all local peaks in the given psImage
    173 above the given threshold.  Returns a psList containing the location (x/y
    174 value) of all peaks.
    175  *****************************************************************************/
     248    const psVector *vector,  ///< The input vector (float)
     249    float threshold   ///< Threshold above which to find a peak
     250);
     251
     252
     253/** pmFindImagePeaks()
     254 *
     255 * Find all local peaks in the given image above the given threshold. This
     256 * function should find all row peaks using pmFindVectorPeaks, then test each row
     257 * peak and exclude peaks which are not local peaks. A peak is a local peak if it
     258 * has a higher value than all 8 neighbors. If the peak has the same value as its
     259 * +y neighbor or +x neighbor, it is NOT a local peak. If any other neighbors
     260 * have an equal value, the peak is considered a valid peak. Note two points:
     261 * first, the +x neighbor condition is already enforced by pmFindVectorPeaks.
     262 * Second, these rules have the effect of making flat-topped regions have single
     263 * peaks at the (+x,+y) corner. When selecting the peaks, their type must also be
     264 * set. The result of this function is an array of pmPeak entries.
     265 *
     266 */
    176267psArray *pmFindImagePeaks(
    177     const psImage *image,               ///< The input image where peaks will be found (float)
    178     float threshold                     ///< Threshold above which to find a peak
    179 );
    180 
    181 /******************************************************************************
    182 psCullPeaks(peaks, maxValue, valid): eliminate peaks from the psList that have
    183 a peak value above the given maximum, or fall outside the valid region.
    184  *****************************************************************************/
     268    const psImage *image,  ///< The input image where peaks will be found (float)
     269    float threshold   ///< Threshold above which to find a peak
     270);
     271
     272
     273/** pmCullPeaks()
     274 *
     275 * Eliminate peaks from the psList that have a peak value above the given
     276 * maximum, or fall outside the valid region.
     277 *
     278 */
    185279psList *pmCullPeaks(
    186     psList *peaks,                      ///< The psList of peaks to be culled
    187     float maxValue,                     ///< Cull peaks above this value
    188     const psRegion valid               ///< Cull peaks otside this psRegion
    189 );
    190 
    191 /******************************************************************************
    192 pmSource *pmSourceLocalSky(image, peak, innerRadius, outerRadius):
    193  
    194  *****************************************************************************/
    195 pmSource *pmSourceLocalSky(
    196     const psImage *image,               ///< The input image (float)
    197     const pmPeak *peak,                 ///< The peak for which the psSource struct is created.
    198     psStatsOptions statsOptions,        ///< The statistic used in calculating the background sky
    199     float innerRadius,                  ///< The inner radius of the suqare annulus for calculating sky
    200     float outerRadius                   ///< The outer radius of the suqare annulus for calculating sky
    201 );
    202 
    203 /******************************************************************************
    204  *****************************************************************************/
    205 pmSource *pmSourceMoments(
    206     pmSource *source,                   ///< The input pmSource for which moments will be computed
    207     float radius                        ///< Use a circle of pixels around the peak
    208 );
    209 
    210 /******************************************************************************
    211 pmSourceRoughClass(pmArray *source, psMetaDeta *metadata): make a guess at the
    212 source classification.
    213  *****************************************************************************/
     280    psList *peaks,   ///< The psList of peaks to be culled
     281    float maxValue,   ///< Cull peaks above this value
     282    const psRegion valid                ///< Cull peaks otside this psRegion
     283);
     284
     285
     286/** pmPeaksSubset()
     287 *
     288 * Create a new peaks array, removing certain types of peaks from the input
     289 * array of peaks based on the given criteria. Peaks should be eliminated if they
     290 * have a peak value above the given maximum value limit or if the fall outside
     291 * the valid region.  The result of the function is a new array with a reduced
     292 * number of peaks.
     293 *
     294 */
     295psArray *pmPeaksSubset(
     296    psArray *peaks,                     ///< Add comment.
     297    float maxvalue,                     ///< Add comment.
     298    const psRegion valid                ///< Add comment.
     299);
     300
     301
     302/** pmSourceDefinePixels()
     303 *
     304 * Define psImage subarrays for the source located at coordinates x,y on the
     305 * image set defined by readout. The pixels defined by this operation consist of
     306 * a square window (of full width 2Radius+1) centered on the pixel which contains
     307 * the given coordinate, in the frame of the readout. The window is defined to
     308 * have limits which are valid within the boundary of the readout image, thus if
     309 * the radius would fall outside the image pixels, the subimage is truncated to
     310 * only consist of valid pixels. If readout->mask or readout->weight are not
     311 * NULL, matching subimages are defined for those images as well. This function
     312 * fails if no valid pixels can be defined (x or y less than Radius, for
     313 * example). This function should be used to define a region of interest around a
     314 * source, including both source and sky pixels.
     315 *
     316 * XXX: must code this.
     317 *
     318 */
     319// XXX: Uncommenting the pmReadout causes compile errors.
     320bool pmSourceDefinePixels(
     321    pmSource *mySource,                 ///< Add comment.
     322    pmReadout *readout,                 ///< Add comment.
     323    psF32 x,                            ///< Add comment.
     324    psF32 y,                            ///< Add comment.
     325    psF32 Radius                        ///< Add comment.
     326);
     327
     328
     329/** pmSourceLocalSky()
     330 *
     331 * Measure the local sky in the vicinity of the given source. The Radius
     332 * defines the square aperture in which the moments will be measured. This
     333 * function assumes the source pixels have been defined, and that the value of
     334 * Radius here is smaller than the value of Radius used to define the pixels. The
     335 * annular region not contained within the radius defined here is used to measure
     336 * the local background in the vicinity of the source. The local background
     337 * measurement uses the specified statistic passed in via the statsOptions entry.
     338 * This function allocates the pmMoments structure. The resulting sky is used to
     339 * set the value of the pmMoments.sky element of the provided pmSource structure.
     340 *
     341 */
     342bool pmSourceLocalSky(
     343    pmSource *source,   ///< The input image (float)
     344    psStatsOptions statsOptions, ///< The statistic used in calculating the background sky
     345    float Radius   ///< The inner radius of the square annulus to exclude
     346);
     347
     348
     349/** pmSourceMoments()
     350 *
     351 * Measure source moments for the given source, using the value of
     352 * source.moments.sky provided as the local background value and the peak
     353 * coordinates as the initial source location. The resulting moment values are
     354 * applied to the source.moments entry, and the source is returned. The moments
     355 * are measured within the given circular radius of the source.peak coordinates.
     356 * The return value indicates the success (TRUE) of the operation.
     357 *
     358 */
     359bool pmSourceMoments(
     360    pmSource *source,   ///< The input pmSource for which moments will be computed
     361    float radius   ///< Use a circle of pixels around the peak
     362);
     363
     364
     365/** pmSourcePSFClump()
     366 *
     367 * We use the source moments to make an initial, approximate source
     368 * classification, and as part of the information needed to build a PSF model for
     369 * the image. As long as the PSF shape does not vary excessively across the
     370 * image, the sources which are represented by a PSF (the start) will have very
     371 * similar second moments. The function pmSourcePSFClump searches a collection of
     372 * sources with measured moments for a group with moments which are all very
     373 * similar. The function returns a pmPSFClump structure, representing the
     374 * centroid and size of the clump in the sigma_x, sigma_y second-moment plane.
     375 *
     376 * The goal is to identify and characterize the stellar clump within the
     377 * sigma_x, sigma_y second-moment plane.  To do this, an image is constructed to
     378 * represent this plane.  The units of sigma_x and sigma_y are in image pixels. A
     379 * pixel in this analysis image represents 0.1 pixels in the input image. The
     380 * dimensions of the image need only be 10 pixels. The peak pixel in this image
     381 * (above a threshold of half of the image maximum) is found. The coordinates of
     382 * this peak pixel represent the 2D mode of the sigma_x, sigma_y distribution.
     383 * The sources with sigma_x, sigma_y within 0.2 pixels of this value are then
     384 *  * used to calculate the median and standard deviation of the sigma_x, sigma_y
     385 * values. These resulting values are returned via the pmPSFClump structure.
     386 *
     387 * The return value indicates the success (TRUE) of the operation.
     388 *
     389 * XXX: Limit the S/N of the candidate sources (part of Metadata)? (TBD).
     390 * XXX: Save the clump parameters on the Metadata (TBD)
     391 *
     392 */
     393pmPSFClump pmSourcePSFClump(
     394    psArray *source,   ///< The input pmSource
     395    psMetadata *metadata  ///< Contains classification parameters
     396);
     397
     398
     399/** pmSourceRoughClass()
     400 *
     401 * Based on the specified data values, make a guess at the source
     402 * classification. The sources are provides as a psArray of pmSource entries.
     403 * Definable parameters needed to make the classification are provided to the
     404 * routine with the psMetadata structure. The rules (in SDRS) refer to values which
     405 * can be extracted from the metadata using the given keywords. Except as noted,
     406 * the data type for these parameters are psF32.
     407 *
     408 */
    214409bool pmSourceRoughClass(
    215     psArray *source,                    ///< The input pmSource
    216     psMetadata *metadata                ///< Contains classification parameters
    217 );
    218 /******************************************************************************
    219 pmSourceSetPixelCircle(source, image, radius)
    220  *****************************************************************************/
    221 bool pmSourceSetPixelsCircle(
    222     pmSource *source,                   ///< The input pmSource
    223     const psImage *image,               ///< The input image (float)
    224     float radius                        ///< The radius of the circle
    225 );
    226 
    227 /******************************************************************************
    228  *****************************************************************************/
    229 bool pmSourceModelGuess(
    230     pmSource *source,                   ///< The input pmSource
    231     const psImage *image,               ///< The input image (float)
    232     pmModelType model                   ///< The type of model to be created.
    233 );
    234 
    235 /******************************************************************************
    236  *****************************************************************************/
     410    psArray *source,   ///< The input pmSource
     411    psMetadata *metadata,  ///< Contains classification parameters
     412    pmPSFClump clump   ///< Statistics about the PSF clump
     413);
     414
     415
     416/** pmSourceModelGuess()
     417 *
     418 * Convert available data to an initial guess for the given model. This
     419 * function allocates a pmModel entry for the pmSource structure based on the
     420 * provided model selection. The method of defining the model parameter guesses
     421 * are specified for each model below. The guess values are placed in the model
     422 * parameters. The function returns TRUE on success or FALSE on failure.
     423 *
     424 */
     425pmModel *pmSourceModelGuess(
     426    pmSource *source,   ///< The input pmSource
     427    pmModelType model   ///< The type of model to be created.
     428);
     429
     430
     431/** pmContourType
     432 *
     433 * Only one type is defined at present.
     434 *
     435 */
    237436typedef enum {
    238437    PS_CONTOUR_CRUDE,
     438    PS_CONTOUR_UNKNOWN01,
     439    PS_CONTOUR_UNKNOWN02
    239440} pmContourType;
    240441
     442
     443/** pmSourceContour()
     444 *
     445 * Find points in a contour for the given source at the given level. If type
     446 * is PM_CONTOUR_CRUDE, the contour is found by starting at the source peak,
     447 * running along each pixel row until the level is crossed, then interpolating to
     448 * the level coordinate for that row. This is done for each row, with the
     449 * starting point determined by the midpoint of the previous row, until the
     450 * starting point has a value below the contour level. The returned contour
     451 * consists of two vectors giving the x and y coordinates of the contour levels.
     452 * This function may be used as part of the model guess inputs.  Other contour
     453 * types may be specified in the future for more refined contours (TBD)
     454 *
     455 */
    241456psArray *pmSourceContour(
    242     pmSource *source,                   ///< The input pmSource
    243     const psImage *image,               ///< The input image (float) (this arg should be removed)
    244     float level,                        ///< The level of the contour
    245     pmContourType mode                  ///< Currently this must be PS_CONTOUR_CRUDE
    246 );
    247 
    248 /******************************************************************************
    249  *****************************************************************************/
     457    pmSource *source,   ///< The input pmSource
     458    const psImage *image,  ///< The input image (float) (this arg should be removed)
     459    float level,   ///< The level of the contour
     460    pmContourType mode   ///< Currently this must be PS_CONTOUR_CRUDE
     461);
     462
     463
     464/** pmSourceFitModel()
     465 *
     466 * Fit the requested model to the specified source. The starting guess for the
     467 * model is given by the input source.model parameter values. The pixels of
     468 * interest are specified by the source.pixelsand source.maskentries. This
     469 * function calls psMinimizeLMChi2() on the image data. The function returns TRUE
     470 * on success or FALSE on failure.
     471 *
     472 */
    250473bool pmSourceFitModel(
    251     pmSource *source,                   ///< The input pmSource
    252     const psImage *image                ///< The input image (float)
    253 );
    254 
    255 /******************************************************************************
    256  *****************************************************************************/
     474    pmSource *source,   ///< The input pmSource
     475    pmModel *model,   ///< model to be fitted
     476    const bool PSF   ///< Treat model as PSF or FLT?
     477);
     478
     479
     480/** pmModelFitStatus()
     481 *
     482 * This function wraps the call to the model-specific function returned by
     483 * pmModelFitStatusFunc_GetFunction.  The model-specific function examines the
     484 * model parameters, parameter errors, Chisq, S/N, and other parameters available
     485 * from model to decide if the particular fit was successful or not.
     486 *
     487 * XXX: Must code this.
     488 *
     489 */
     490bool pmModelFitStatus(
     491    pmModel *model                      ///< Add comment.
     492);
     493
     494
     495/** pmSourceAddModel()
     496 *
     497 * Add the given source model flux to/from the provided image. The boolean
     498 * option center selects if the source is re-centered to the image center or if
     499 * it is placed at its centroid location. The boolean option sky selects if the
     500 * background sky is applied (TRUE) or not. The pixel range in the target image
     501 * is at most the pixel range specified by the source.pixels image. The success
     502 * status is returned.
     503 *
     504 */
    257505bool pmSourceAddModel(
    258     psImage *image,                     ///< The opuut image (float)
    259     pmSource *source,                   ///< The input pmSource
    260     bool center                         ///< A boolean flag that determines whether pixels are centered
    261 );
    262 
    263 /******************************************************************************
    264  *****************************************************************************/
     506    psImage *image,   ///< The output image (float)
     507    psImage *mask,   ///< The image pixel mask (valid == 0)
     508    pmModel *model,   ///< The input pmModel
     509    bool center    ///< A boolean flag that determines whether pixels are centered
     510);
     511
     512
     513/** pmSourceSubModel()
     514 *
     515 * Subtract the given source model flux to/from the provided image. The
     516 * boolean option center selects if the source is re-centered to the image center
     517 * or if it is placed at its centroid location. The boolean option sky selects if
     518 * the background sky is applied (TRUE) or not. The pixel range in the target
     519 * image is at most the pixel range specified by the source.pixels image. The
     520 * success status is returned.
     521 *
     522 */
    265523bool pmSourceSubModel(
    266     psImage *image,                     ///< The output image (float)
    267     pmSource *source,                   ///< The input pmSource
    268     bool center                         ///< A boolean flag that determines whether pixels are centered
    269 );
    270 
    271 /******************************************************************************
    272 XXX: Why only *x argument?
    273 XXX EAM: psMinimizeLMChi2Func returns psF64, not float
    274  *****************************************************************************/
    275 float pmMinLM_Gauss2D(
    276     psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    277     const psVector *params,             ///< A psVector which holds the parameters of this function
    278     const psVector *x                   ///< A psVector which holds the row/col coordinate
    279 );
    280 
    281 /******************************************************************************
    282  *****************************************************************************/
    283 float pmMinLM_PsuedoGauss2D(
    284     psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    285     const psVector *params,             ///< A psVector which holds the parameters of this function
    286     const psVector *x                   ///< A psVector which holds the row/col coordinate
    287 );
    288 
    289 /******************************************************************************
    290  *****************************************************************************/
    291 float pmMinLM_Wauss2D(
    292     psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    293     const psVector *params,             ///< A psVector which holds the parameters of this function
    294     const psVector *x                   ///< A psVector which holds the row/col coordinate
    295 );
    296 
    297 /******************************************************************************
    298  *****************************************************************************/
    299 float pmMinLM_TwistGauss2D(
    300     psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    301     const psVector *params,             ///< A psVector which holds the parameters of this function
    302     const psVector *x                   ///< A psVector which holds the row/col coordinate
    303 );
    304 
    305 /******************************************************************************
    306  *****************************************************************************/
    307 float pmMinLM_Sersic(
    308     psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    309     const psVector *params,             ///< A psVector which holds the parameters of this function
    310     const psVector *x                   ///< A psVector which holds the row/col coordinate
    311 );
    312 
    313 /******************************************************************************
    314  *****************************************************************************/
    315 float pmMinLM_SersicCore(
    316     psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    317     const psVector *params,             ///< A psVector which holds the parameters of this function
    318     const psVector *x                   ///< A psVector which holds the row/col coordinate
    319 );
    320 
    321 /******************************************************************************
    322  *****************************************************************************/
    323 float pmMinLM_PsuedoSersic(
    324     psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    325     const psVector *params,             ///< A psVector which holds the parameters of this function
    326     const psVector *x                   ///< A psVector which holds the row/col coordinate
     524    psImage *image,   ///< The output image (float)
     525    psImage *mask,   ///< The image pixel mask (valid == 0)
     526    pmModel *model,   ///< The input pmModel
     527    bool center    ///< A boolean flag that determines whether pixels are centered
    327528);
    328529
     
    330531/**
    331532 *
    332  *  The object model functions are defined to allow for the flexible addition
    333  *  of new object models. Every object model, with parameters represented by
    334  *  pmModel, has an associated set of functions which provide necessary support
    335  *  operations. A set of abstract functions allow the programmer to select the
    336  *  approriate function or property for a specific named object model.
    337  *
    338  */
     533 * The function returns both the magnitude of the fit, defined as -2.5log(flux),
     534 * where the flux is integrated under the model, theoretically from a radius of 0
     535 * to infinity. In practice, we integrate the model beyond 50sigma.  The aperture magnitude is
     536 * defined as -2.5log(flux) , where the flux is summed for all pixels which are
     537 * not excluded by the aperture mask. The model flux is calculated by calling the
     538 * model-specific function provided by pmModelFlux_GetFunction.
     539 *
     540 * XXX: must code this.
     541 *
     542 */
     543bool pmSourcePhotometry(
     544    float *fitMag,                      ///< integrated fit magnitude
     545    float *obsMag,   ///< aperture flux magnitude
     546    pmModel *model,                     ///< model used for photometry
     547    psImage *image,                     ///< image pixels to be used
     548    psImage *mask                       ///< mask of pixels to ignore
     549);
     550
    339551
    340552/**
    341553 *
    342  *  This function is the model chi-square minimization function for this model.
    343  *
    344  */
    345 typedef psMinimizeLMChi2Func pmModelFunc;
    346 
    347 
    348 /**
    349  *
    350  * This function returns the integrated flux for the given model parameters.
    351  */
    352 typedef psF64 (*pmModelFlux)(const psVector *params);
    353 
    354 
    355 /**
    356  *
    357  *  This function provides the model guess parameters based on the details of
    358  *   the given source.
    359  *
    360  */
    361 typedef bool (*pmModelGuessFunc)(pmModel *model, pmSource *source);
    362 
    363 
    364 /**
    365  *
    366  *  This function constructs the PSF model for the given source based on the
    367  *  supplied psf and the FLT model for the object.
    368  *
    369  */
    370 typedef bool (*pmModelFromPSFFunc)(pmModel *modelPSF, pmModel *modelFLT, pmPSF *psf);
    371 
    372 
    373 /**
    374  *
    375  *  This function returns the radius at which the given model and parameters
    376  *  achieves the given flux.
    377  *
    378  */
    379 typedef psF64 (*pmModelRadius)(const psVector *params, double flux);
    380 
    381 
    382 /**
    383  *
    384  *  Each of the function types above has a corresponding function which returns
    385  *  the function given the model type:
    386  *
    387  */
    388 pmModelFunc pmModelFunc_GetFunction (pmModelType type);
    389 pmModelFlux pmModelFlux_GetFunction (pmModelType type);
    390 pmModelGuessFunc pmModelGuessFunc_GetFunction (pmModelType type);
    391 pmModelFromPSFFunc pmModelFromPSFFunc_GetFunction (pmModelType type);
    392 pmModelRadius pmModelRadius_GetFunction (pmModelType type);
    393 psS32 pmModelParameterCount(pmModelType type);
    394 psS32 pmModelSetType(char *name);
    395 char *pmModelGetType(pmModelType type);
     554 * This function converts the source classification into the closest available
     555 * approximation to the Dophot classification scheme:
     556 *
     557 * PM_SOURCE_DEFECT: 8
     558 * PM_SOURCE_SATURATED: 8
     559 * PM_SOURCE_SATSTAR: 10
     560 * PM_SOURCE_PSFSTAR: 1
     561 * PM_SOURCE_GOODSTAR: 1
     562 * PM_SOURCE_POOR_FIT_PSF: 7
     563 * PM_SOURCE_FAIL_FIT_PSF: 4
     564 * PM_SOURCE_FAINTSTAR: 4
     565 * PM_SOURCE_GALAXY: 2
     566 * PM_SOURCE_FAINT_GALAXY: 2
     567 * PM_SOURCE_DROP_GALAXY: 2
     568 * PM_SOURCE_FAIL_FIT_GAL: 2
     569 * PM_SOURCE_POOR_FIT_GAL: 2
     570 * PM_SOURCE_OTHER: ?
     571 *
     572 */
     573int pmSourceDophotType(
     574    pmSource *source                    ///< Add comment.
     575);
     576
     577
     578/** pmSourceSextractType()
     579 *
     580 * This function converts the source classification into the closest available
     581 * approximation to the Sextractor classification scheme. the correspondence is
     582 * not yet defined (TBD) .
     583 *
     584 * XXX: Must code this.
     585 *
     586 */
     587int pmSourceSextractType(
     588    pmSource *source                    ///< Add comment.
     589);
     590
     591/** pmSourceFitModel_v5()
     592 *
     593 * Fit the requested model to the specified source. The starting guess for the
     594 * model is given by the input source.model parameter values. The pixels of
     595 * interest are specified by the source.pixelsand source.maskentries. This
     596 * function calls psMinimizeLMChi2() on the image data. The function returns TRUE
     597 * on success or FALSE on failure.
     598 *
     599 */
     600bool pmSourceFitModel_v5(
     601    pmSource *source,   ///< The input pmSource
     602    pmModel *model,   ///< model to be fitted
     603    const bool PSF   ///< Treat model as PSF or FLT?
     604);
     605
     606
     607/** pmSourceFitModel_v7()
     608 *
     609 * Fit the requested model to the specified source. The starting guess for the
     610 * model is given by the input source.model parameter values. The pixels of
     611 * interest are specified by the source.pixelsand source.maskentries. This
     612 * function calls psMinimizeLMChi2() on the image data. The function returns TRUE
     613 * on success or FALSE on failure.
     614 *
     615 */
     616bool pmSourceFitModel_v7(
     617    pmSource *source,   ///< The input pmSource
     618    pmModel *model,   ///< model to be fitted
     619    const bool PSF   ///< Treat model as PSF or FLT?
     620);
    396621
    397622#endif
  • trunk/psModules/test/objects/tst_pmObjects01.c

    r5169 r5255  
    1717 *
    1818 * XXX: Memory leaks are not being caught.  If I allocated a psVector in these functions
    19  * abd never deallocate, no error is generated.
     19 * and never deallocate, no error is generated.
     20Fully Tested:
     21    pmPeakAlloc()
     22    pmMomentsAlloc()
     23Weakly Tested:
     24    pmSourceMoments()
     25 
    2026 *
    21  *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
    22  *  @date $Date: 2005-09-28 20:42:52 $
     27 *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
     28 *  @date $Date: 2005-10-10 19:53:54 $
    2329 *
    2430 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    2733#include "pslib.h"
    2834#include "pmObjects.h"
     35#include "pmModelGroup.h"
     36
    2937#define NUM_ROWS 10
    3038#define NUM_COLS 10
     
    3745static int test04(void);
    3846static int test05(void);
    39 static int test06(void);
     47//static int test06(void);
    4048static int test07(void);
     49/*
    4150static int test08(void);
    4251static int test09(void);
     
    4453static int test16(void);
    4554static int test20(void);
     55*/
    4656testDescription tests[] = {
    4757                              {test00, 000, "pmObjects: structure allocators and deallocators", true, false},
     
    5060                              {test03, 001, "pmObjects: pmCullPeaks()", true, false},
    5161                              {test04, 001, "pmObjects: pmSourceLocalSky()", true, false},
    52                               {test06, 001, "pmObjects: pmSourceSetPixelsCircle()", true, false},
    5362                              {test05, 001, "pmObjects: pmSourceMoments()", true, false},
     63                              //                              {test06, 001, "pmObjects: pmSourceSetPixelsCircle()", true, false},
    5464                              {test07, 001, "pmObjects: pmMin()", true, false},
    55                               {test08, 001, "pmObjects: pmSourceModelGuess()", true, false},
    56                               {test09, 001, "pmObjects: pmSourceContour()", true, false},
    57                               {test15, 001, "pmObjects: pmSourceAddModel()", true, false},
    58                               {test16, 001, "pmObjects: pmSourceSubModel()", true, false},
    59                               {test20, 001, "pmObjects: pmSourceSubModel()", true, false},
     65                              /*
     66                                                            {test08, 001, "pmObjects: pmSourceModelGuess()", true, false},
     67                                                            {test09, 001, "pmObjects: pmSourceContour()", true, false},
     68                                                            {test15, 001, "pmObjects: pmSourceAddModel()", true, false},
     69                                                            {test16, 001, "pmObjects: pmSourceSubModel()", true, false},
     70                                                            {test20, 001, "pmObjects: pmSourceSubModel()", true, false},
     71                              */
    6072                              {NULL}
    6173                          };
     
    6476{
    6577    psLogSetFormat("HLNM");
     78    //
     79    // We include the function names here in psTraceSetLevel() commands for
     80    // debugging convenience.  There is no guarantee that this list of functions
     81    // is complete.
     82    //
     83    psTraceSetLevel(".", 0);
     84    psTraceSetLevel("pmPeakAlloc", 0);
     85    psTraceSetLevel("pmMomentsAlloc", 0);
     86    psTraceSetLevel("modelFree", 0);
     87    psTraceSetLevel("pmModelAlloc", 0);
     88    psTraceSetLevel("sourceFree", 0);
     89    psTraceSetLevel("pmSourceAlloc", 0);
     90    psTraceSetLevel("pmFindVectorPeaks", 0);
     91    psTraceSetLevel("getRowVectorFromImage", 0);
     92    psTraceSetLevel("myListAddPeak", 0);
     93    psTraceSetLevel("pmFindImagePeaks", 0);
     94    psTraceSetLevel("isItInThisRegion", 0);
     95    psTraceSetLevel("pmCullPeaks", 0);
     96    psTraceSetLevel("pmPeaksSubset", 0);
     97    psTraceSetLevel("pmSourceLocalSky", 0);
     98    psTraceSetLevel("checkRadius2", 0);
     99    psTraceSetLevel("pmSourceMoments", 0);
     100    psTraceSetLevel("pmComparePeakAscend", 0);
     101    psTraceSetLevel("pmComparePeakDescend", 0);
     102    psTraceSetLevel("pmSourcePSFClump", 0);
     103    psTraceSetLevel("pmSourceRoughClass", 0);
     104    psTraceSetLevel("pmSourceDefinePixels", 0);
     105    psTraceSetLevel("pmSourceModelGuess", 0);
     106    psTraceSetLevel("pmModelEval", 0);
     107    psTraceSetLevel("findValue", 0);
     108    psTraceSetLevel("pmSourceContour", 0);
     109    psTraceSetLevel("pmSourceFitModel_v5", 0);
     110    psTraceSetLevel("pmSourceFitModel", 0);
     111    psTraceSetLevel("p_pmSourceAddOrSubModel", 0);
     112    psTraceSetLevel("pmSourceAddModel", 0);
     113    psTraceSetLevel("pmSourceSubModel", 0);
     114
    66115    return !runTestSuite(stderr, "Test Point Driver", tests, argc, argv);
    67116}
     
    116165                (tmpMoments->nPixels != 0)) {
    117166            printf("TEST ERROR: pmMomentsAlloc() did not properly initialize the pmMoments structure.\n");
     167            printf("    tmpMoments->x is %f\n", tmpMoments->x);
     168            printf("    tmpMoments->y is %f\n", tmpMoments->y);
     169            printf("    tmpMoments->Sx is %f\n", tmpMoments->Sx);
     170            printf("    tmpMoments->Sy is %f\n", tmpMoments->Sy);
     171            printf("    tmpMoments->Sxy is %f\n", tmpMoments->Sxy);
     172            printf("    tmpMoments->Sum is %f\n", tmpMoments->Sum);
     173            printf("    tmpMoments->Peak is %f\n", tmpMoments->Peak);
     174            printf("    tmpMoments->Sky is %f\n", tmpMoments->Sky);
     175            printf("    tmp    Moments->nPixels is %d\n", tmpMoments->nPixels);
    118176            testStatus = false;
    119177        }
     
    121179    psFree(tmpMoments);
    122180
    123     printf("Testing pmModelAlloc(PS_MODEL_GAUSS)...\n");
    124     pmModel *tmpModel = pmModelAlloc(PS_MODEL_GAUSS);
    125     if (tmpModel == NULL) {
    126         printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) returned a NULL pmModel\n");
    127         testStatus = false;
    128     } else {
    129         if ((tmpModel->params->n != 7) || (tmpModel->dparams->n != 7)) {
    130             printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) allocated an incorrect number of params (%ld, %ld)\n",
    131                    tmpModel->params->n, tmpModel->dparams->n);
     181
     182    //
     183    // Loop through each type of model
     184    //
     185    psS32 i = 0;
     186    while (0 != pmModelParameterCount(i)) {
     187        printf("Testing pmModelAlloc(%s)...\n", pmModelGetType(0));
     188        pmModel *tmpModel = pmModelAlloc(i);
     189        if (tmpModel == NULL) {
     190            printf("TEST ERROR: pmModelAlloc(%s) returned a NULL pmModel\n", pmModelGetType(0));
    132191            testStatus = false;
    133192        } else {
    134             for (psS32 i = 0 ; i < 7 ; i++) {
    135                 if ((tmpModel->params->data.F32[i] != 0.0) ||
    136                         (tmpModel->dparams->data.F32[i] != 0.0)) {
    137                     printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) did not ininitialize the params/dparams array to 0.0.\n");
    138                     testStatus = false;
    139                 }
    140             }
    141         }
    142     }
    143     psFree(tmpModel);
    144 
    145     printf("Testing pmModelAlloc(PS_MODEL_PGAUSS)...\n");
    146     tmpModel = pmModelAlloc(PS_MODEL_PGAUSS);
    147     if (tmpModel == NULL) {
    148         printf("TEST ERROR: pmModelAlloc(PS_MODEL_PGAUSS) returned a NULL pmModel\n");
    149         testStatus = false;
    150     } else {
    151         if ((tmpModel->params->n != 7) || (tmpModel->dparams->n != 7)) {
    152             printf("TEST ERROR: pmModelAlloc(PS_MODEL_PGAUSS) allocated an incorrect number of params (%ld, %ld)\n",
    153                    tmpModel->params->n, tmpModel->dparams->n);
    154             testStatus = false;
    155         } else {
    156             for (psS32 i = 0 ; i < 7 ; i++) {
    157                 if ((tmpModel->params->data.F32[i] != 0.0) ||
    158                         (tmpModel->dparams->data.F32[i] != 0.0)) {
    159                     printf("TEST ERROR: pmModelAlloc(PS_MODEL_PGAUSS) did not ininitialize the params/dparams array to 0.0.\n");
    160                     testStatus = false;
    161                 }
    162             }
    163         }
    164     }
    165     psFree(tmpModel);
    166 
    167     printf("Testing pmModelAlloc(PS_MODEL_TWIST_GAUSS)...\n");
    168     tmpModel = pmModelAlloc(PS_MODEL_TWIST_GAUSS);
    169     if (tmpModel == NULL) {
    170         printf("TEST ERROR: pmModelAlloc(PS_MODEL_TWIST_GAUSS) returned a NULL pmModel\n");
    171         testStatus = false;
    172     } else {
    173         if ((tmpModel->params->n != 11) || (tmpModel->dparams->n != 11)) {
    174             printf("TEST ERROR: pmModelAlloc(PS_MODEL_TWIST_GAUSS) allocated an incorrect number of params (%ld, %ld)\n",
    175                    tmpModel->params->n, tmpModel->dparams->n);
    176             testStatus = false;
    177         } else {
    178             for (psS32 i = 0 ; i < 11 ; i++) {
    179                 if ((tmpModel->params->data.F32[i] != 0.0) ||
    180                         (tmpModel->dparams->data.F32[i] != 0.0)) {
    181                     printf("TEST ERROR: pmModelAlloc(PS_MODEL_TWIST_GAUSS) did not ininitialize the params/dparams array to 0.0.\n");
    182                     testStatus = false;
    183                 }
    184             }
    185         }
    186     }
    187     psFree(tmpModel);
    188 
    189     printf("Testing pmModelAlloc(PS_MODEL_WAUSS)...\n");
    190     tmpModel = pmModelAlloc(PS_MODEL_WAUSS);
    191     if (tmpModel == NULL) {
    192         printf("TEST ERROR: pmModelAlloc(PS_MODEL_WAUSS) returned a NULL pmModel\n");
    193         testStatus = false;
    194     } else {
    195         if ((tmpModel->params->n != 9) || (tmpModel->dparams->n != 9)) {
    196             printf("TEST ERROR: pmModelAlloc(PS_MODEL_WAUSS) allocated an incorrect number of params (%ld, %ld)\n",
    197                    tmpModel->params->n, tmpModel->dparams->n);
    198             testStatus = false;
    199         } else {
    200             for (psS32 i = 0 ; i < 9 ; i++) {
    201                 if ((tmpModel->params->data.F32[i] != 0.0) ||
    202                         (tmpModel->dparams->data.F32[i] != 0.0)) {
    203                     printf("TEST ERROR: pmModelAlloc(PS_MODEL_WAUSS) did not ininitialize the params/dparams array to 0.0.\n");
    204                     testStatus = false;
    205                 }
    206             }
    207         }
    208     }
    209     psFree(tmpModel);
    210 
    211     printf("Testing pmModelAlloc(PS_MODEL_SERSIC)...\n");
    212     tmpModel = pmModelAlloc(PS_MODEL_SERSIC);
    213     if (tmpModel == NULL) {
    214         printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC) returned a NULL pmModel\n");
    215         testStatus = false;
    216     } else {
    217         if ((tmpModel->params->n != 8) || (tmpModel->dparams->n != 8)) {
    218             printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC) allocated an incorrect number of params (%ld, %ld)\n",
    219                    tmpModel->params->n, tmpModel->dparams->n);
    220             testStatus = false;
    221         } else {
    222             for (psS32 i = 0 ; i < 8 ; i++) {
    223                 if ((tmpModel->params->data.F32[i] != 0.0) ||
    224                         (tmpModel->dparams->data.F32[i] != 0.0)) {
    225                     printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC) did not ininitialize the params/dparams array to 0.0.\n");
    226                     testStatus = false;
    227                 }
    228             }
    229         }
    230     }
    231     psFree(tmpModel);
    232 
    233     printf("Testing pmModelAlloc(PS_MODEL_SERSIC_CORE)...\n");
    234     tmpModel = pmModelAlloc(PS_MODEL_SERSIC_CORE);
    235     if (tmpModel == NULL) {
    236         printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC_CORE) returned a NULL pmModel\n");
    237         testStatus = false;
    238     } else {
    239         if ((tmpModel->params->n != 12) || (tmpModel->dparams->n != 12)) {
    240             printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC_CORE) allocated an incorrect number of params (%ld, %ld)\n",
    241                    tmpModel->params->n, tmpModel->dparams->n);
    242             testStatus = false;
    243         } else {
    244             for (psS32 i = 0 ; i < 12 ; i++) {
    245                 if ((tmpModel->params->data.F32[i] != 0.0) ||
    246                         (tmpModel->dparams->data.F32[i] != 0.0)) {
    247                     printf("TEST ERROR: pmModelAlloc(PS_MODEL_SERSIC_CORE) did not ininitialize the params/dparams array to 0.0.\n");
    248                     testStatus = false;
    249                 }
    250             }
    251         }
    252     }
    253     psFree(tmpModel);
     193
     194            /* XXX: Should we test that the members were set correctly?
     195                        if ((tmpModel->params->n != 7) || (tmpModel->dparams->n != 7)) {
     196                            printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) allocated an incorrect number of params (%ld, %ld)\n",
     197                                   tmpModel->params->n, tmpModel->dparams->n);
     198                            testStatus = false;
     199                        } else {
     200                            for (psS32 i = 0 ; i < 7 ; i++) {
     201                                if ((tmpModel->params->data.F32[i] != 0.0) ||
     202                                        (tmpModel->dparams->data.F32[i] != 0.0)) {
     203                                    printf("TEST ERROR: pmModelAlloc(PS_MODEL_GAUSS) did not ininitialize the params/dparams array to 0.0.\n");
     204                                    testStatus = false;
     205                                }
     206                            }
     207                        }
     208            */
     209        }
     210        psFree(tmpModel);
     211        i++;
     212    }
     213
    254214
    255215    pmSource *tmpSource = pmSourceAlloc();
     
    775735}
    776736
     737
     738
     739
     740
     741
     742
     743
     744
     745
     746
     747
     748
     749
     750
     751
     752
     753
     754
     755
     756
     757
     758
     759
     760
     761
     762
     763
     764
     765
     766
     767
     768
     769
     770
     771
     772
     773
     774
     775
     776
     777
     778
     779
     780
     781
     782
     783
     784
     785
     786
     787
     788
     789
     790
     791
     792
     793
     794
     795
     796
     797
     798
     799
     800
     801
     802
    777803#define TST04_NUM_ROWS 100
    778804#define TST04_NUM_COLS 100
     
    792818    bool testStatus = true;
    793819    psImage *imgData = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_F32);
    794     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    795         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    796             imgData->data.F32[i][j] = TST04_SKY;
    797         }
    798     }
     820    psImageInit(imgData, TST04_SKY);
     821    psImage *imgMask = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_U8);
     822    psImageInit(imgMask, 0);
     823    //    psImage *imgMaskS8 = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_S8);
     824    //    psImageInit(imgMaskS8, 0);
    799825    psImage *imgDataF64 = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_F64);
    800     for (psS32 i = 0 ; i < imgDataF64->numRows; i++) {
    801         for (psS32 j = 0 ; j < imgDataF64->numCols; j++) {
    802             imgDataF64->data.F64[i][j] = 0.0;
    803         }
    804     }
    805     pmSource *rc = NULL;
     826    psImageInit(imgDataF64, 0.0);
    806827    pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST04_NUM_ROWS / 2),
    807828                                  (psF32) (TST04_NUM_COLS / 2),
    808829                                  200.0,
    809830                                  PM_PEAK_LONE);
    810 
    811     printf("----------------------------------------------------------------------------------\n");
    812     printf("Calling pmSourceLocalSky with NULL psImage.  Should generate error and return NULL.\n");
    813     rc = pmSourceLocalSky(NULL, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0);
    814     if (rc != NULL) {
    815         printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    816         psFree(rc);
    817         testStatus = false;
    818     }
    819 
    820     printf("----------------------------------------------------------------------------------\n");
    821     printf("Calling pmSourceLocalSky with wrong-type psImage.  Should generate error and return NULL.\n");
    822     rc = pmSourceLocalSky(imgDataF64, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0);
    823     if (rc != NULL) {
    824         printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    825         psFree(rc);
    826         testStatus = false;
    827     }
    828 
    829     printf("----------------------------------------------------------------------------------\n");
    830     printf("Calling pmSourceLocalSky with NULL pmPeak.  Should generate error and return NULL.\n");
    831     rc = pmSourceLocalSky(imgData, NULL, PS_STAT_SAMPLE_MEAN, 10.0, 20.0);
    832     if (rc != NULL) {
    833         printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    834         psFree(rc);
    835         testStatus = false;
    836     }
    837 
    838     printf("----------------------------------------------------------------------------------\n");
    839     printf("Calling pmSourceLocalSky with innerRadius<0.0.  Should generate error and return NULL.\n");
    840     rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, -10.0, 20.0);
    841     if (rc != NULL) {
    842         printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    843         psFree(rc);
    844         testStatus = false;
    845     }
    846 
    847     printf("----------------------------------------------------------------------------------\n");
    848     printf("Calling pmSourceLocalSky with innerRadius>outerRadius.  Should generate error and return NULL.\n");
    849     rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 5.0);
    850     if (rc != NULL) {
    851         printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    852         psFree(rc);
    853         testStatus = false;
    854     }
    855     /* XXX: This is commented out since the EAM modification no longer generated NULLS for these tests.
    856         printf("----------------------------------------------------------------------------------\n");
    857         printf("Calling pmSourceLocalSky with subImage startRow < 0.  Should generate error and return NULL.\n");
    858         tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2);
    859         tmpPeak->y = (psF32) (TST04_NUM_COLS / 2);
    860         tmpPeak->y = 1;
    861         rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0);
    862         if (rc != NULL) {
    863             printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    864             psFree(rc);
    865             testStatus = false;
    866         }
    867         printf("----------------------------------------------------------------------------------\n");
    868         printf("Calling pmSourceLocalSky with subImage endRow > numRows.  Should generate error and return NULL.\n");
    869         tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2);
    870         tmpPeak->y = (psF32) (TST04_NUM_COLS / 2);
    871         tmpPeak->y = TST04_NUM_ROWS;
    872         rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0);
    873         if (rc != NULL) {
    874             printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    875             psFree(rc);
    876             testStatus = false;
    877         }
    878         printf("----------------------------------------------------------------------------------\n");
    879         printf("Calling pmSourceLocalSky with subImage startCol < 0.  Should generate error and return NULL.\n");
    880         tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2);
    881         tmpPeak->y = (psF32) (TST04_NUM_COLS / 2);
    882         tmpPeak->x = 1;
    883         rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, 10.0, 20.0);
    884         if (rc != NULL) {
    885             printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    886             psFree(rc);
    887             testStatus = false;
    888         }
    889         printf("----------------------------------------------------------------------------------\n");
    890         printf("Calling pmSourceLocalSky with subImage endCol > numCols.  Should generate error and return NULL.\n");
    891         tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2);
    892         tmpPeak->y = (psF32) (TST04_NUM_COLS / 2);
    893         tmpPeak->x = TST04_NUM_COLS;
    894         rc = pmSourceLocalSky(imgData, tmpPeak, PS_STAT_SAMPLE_MEAN, (psF32) TST04_INNER_RADIUS, (psF32) TST04_OUTER_RADIUS);
    895         if (rc != NULL) {
    896             printf("TEST ERROR: pmSourceLocalSky() returned a non-NULL pmSource.\n");
    897             psFree(rc);
    898             testStatus = false;
    899         }
    900     */
     831    pmSource *tmpSource = pmSourceAlloc();
     832    tmpSource->pixels = imgData;
     833    tmpSource->mask = imgMask;
     834    tmpSource->peak = tmpPeak;
     835
     836    printf("----------------------------------------------------------------------------------\n");
     837    printf("Calling pmSourceLocalSky with NULL tmpSource.  Should generate error and return FALSE.\n");
     838    bool rc = pmSourceLocalSky(NULL, PS_STAT_SAMPLE_MEAN, 10.0);
     839    if (rc != false) {
     840        printf("TEST ERROR: pmSourceLocalSky() returned a non-FALSE pmSource.\n");
     841        testStatus = false;
     842    }
     843
     844    printf("----------------------------------------------------------------------------------\n");
     845    printf("Calling pmSourceLocalSky with Radius<0.0.  Should generate error and return FALSE.\n");
     846    rc = pmSourceLocalSky(tmpSource, PS_STAT_SAMPLE_MEAN, -10.0);
     847    if (rc != false) {
     848        printf("TEST ERROR: pmSourceLocalSky() returned a non-FALSE pmSource.\n");
     849        testStatus = false;
     850    }
    901851
    902852    //
     
    908858    tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2);
    909859    tmpPeak->y = (psF32) (TST04_NUM_COLS / 2);
    910     rc = pmSourceLocalSky(imgData,
    911                           tmpPeak,
    912                           PS_STAT_SAMPLE_MEAN,
    913                           (psF32) TST04_INNER_RADIUS,
    914                           (psF32) TST04_OUTER_RADIUS);
    915 
    916     if (rc == NULL) {
    917         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
     860    rc = pmSourceLocalSky(tmpSource, PS_STAT_SAMPLE_MEAN, 10.0);
     861
     862    if (rc == false) {
     863        printf("TEST ERROR: pmSourceLocalSky() returned a FALSE pmSource.\n");
    918864        testStatus = false;
    919865    } else {
    920         if (rc->peak == NULL) {
     866        if (tmpSource->peak == NULL) {
    921867            printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource->peak.\n");
    922868            testStatus = false;
    923869        } else {
    924             if (rc->peak->x != tmpPeak->x) {
    925                 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->x was %d, should have been %d.\n", rc->peak->x, tmpPeak->x);
     870            if (tmpSource->peak->x != tmpPeak->x) {
     871                printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->x was %d, should have been %d.\n",
     872                       tmpSource->peak->x, tmpPeak->x);
    926873                testStatus = false;
    927874            }
    928875
    929             if (rc->peak->y != tmpPeak->y) {
    930                 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->y was %d, should have been %d.\n", rc->peak->y, tmpPeak->y);
     876            if (tmpSource->peak->y != tmpPeak->y) {
     877                printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->y was %d, should have been %d.\n",
     878                       tmpSource->peak->y, tmpPeak->y);
    931879                testStatus = false;
    932880            }
    933881
    934             if (rc->peak->counts != tmpPeak->counts) {
    935                 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->counts was %f, should have been %f.\n", rc->peak->counts, tmpPeak->counts);
     882            if (tmpSource->peak->counts != tmpPeak->counts) {
     883                printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->counts was %f, should have been %f.\n",
     884                       tmpSource->peak->counts, tmpPeak->counts);
    936885                testStatus = false;
    937886            }
    938887
    939             if (rc->peak->class != tmpPeak->class) {
    940                 printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->class was %d, should have been %d.\n", rc->peak->class, tmpPeak->class);
     888            if (tmpSource->peak->class != tmpPeak->class) {
     889                printf("TEST ERROR: pmSourceLocalSky() pmSource->peak->class was %d, should have been %d.\n",
     890                       tmpSource->peak->class, tmpPeak->class);
    941891                testStatus = false;
    942892            }
    943893        }
    944894
    945         if (rc->pixels == NULL) {
    946             printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels was NULL.\n");
     895        if (tmpSource->moments == NULL) {
     896            printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource->moments.\n");
    947897            testStatus = false;
    948898        } else {
    949             if (rc->pixels->numRows != (2 * TST04_OUTER_RADIUS)) {
    950                 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->numRows was %d, should have been %d.\n",
    951                        rc->pixels->numRows, (2 * TST04_OUTER_RADIUS));
     899            if (tmpSource->moments->Sky != TST04_SKY) {
     900                printf("TEST ERROR: pmSourceLocalSky() pmSource->moments->Sky was %f, should have been %f.\n", tmpSource->moments->Sky, TST04_SKY);
    952901                testStatus = false;
    953902            }
    954 
    955             if (rc->pixels->numCols != (2 * TST04_OUTER_RADIUS)) {
    956                 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->numCols was %d, should have been %d.\n",
    957                        rc->pixels->numCols, (2 * TST04_OUTER_RADIUS));
    958                 testStatus = false;
    959             }
    960 
    961             if (rc->pixels->col0 != (tmpPeak->x - TST04_OUTER_RADIUS)) {
    962                 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->col0 was %d, should have been %d.\n",
    963                        rc->pixels->col0, (tmpPeak->x - TST04_OUTER_RADIUS));
    964                 testStatus = false;
    965             }
    966 
    967             if (rc->pixels->row0 != (tmpPeak->y - TST04_OUTER_RADIUS)) {
    968                 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->row0 was %d, should have been %d.\n",
    969                        rc->pixels->row0, (tmpPeak->y - TST04_OUTER_RADIUS));
    970                 testStatus = false;
    971             }
    972 
    973             if (rc->pixels->type.type != PS_TYPE_F32) {
    974                 printf("TEST ERROR: pmSourceLocalSky() pmSource->pixels->type was %d, should have been %d.\n",
    975                        rc->pixels->type.type, PS_TYPE_F32);
    976                 testStatus = false;
    977             }
    978 
    979             // XXX: Test the rc->pixels-> row/col offsets.
    980             // XXX: Test that the pixels corresponds to the source image pixels.
    981         }
    982 
    983         if (rc->mask == NULL) {
    984             printf("TEST ERROR: pmSourceLocalSky() pmSource->mask was NULL.\n");
    985             testStatus = false;
    986         } else {
    987             if (rc->mask->numRows != (2 * TST04_OUTER_RADIUS)) {
    988                 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask->numRows was %d, should have been %d.\n",
    989                        rc->mask->numRows, (2 * TST04_OUTER_RADIUS));
    990                 testStatus = false;
    991             }
    992 
    993             if (rc->mask->numCols != (2 * TST04_OUTER_RADIUS)) {
    994                 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask->numCols was %d, should have been %d.\n",
    995                        rc->mask->numCols, (2 * TST04_OUTER_RADIUS));
    996                 testStatus = false;
    997             }
    998 
    999             if (rc->mask->type.type != PS_TYPE_U8) {
    1000                 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask->type was %d, should have been %d.\n",
    1001                        rc->mask->type.type, PS_TYPE_U8);
    1002                 testStatus = false;
    1003             }
    1004 
    1005             // XXX: Test the rc->mask-> row/col offsets.
    1006             // XXX: Test that the correct pixels were masked, not merely the number of masked pixels.
    1007             psS32 unmaskedPixels = 0;
    1008             psS32 maskedPixels = 0;
    1009 
    1010             for (psS32 row = 0 ; row < rc->mask->numRows; row++) {
    1011                 for (psS32 col = 0 ; col < rc->mask->numCols; col++) {
    1012                     if (rc->mask->data.U8[row][col] == 0) {
    1013                         unmaskedPixels++;
    1014                     } else {
    1015                         maskedPixels++;
    1016                     }
    1017                 }
    1018             }
    1019             if (maskedPixels != PS_SQR(2*(TST04_INNER_RADIUS-1))) {
    1020                 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask had %d masked pixels, should have been %d.\n",
    1021                        maskedPixels, PS_SQR(2*(TST04_INNER_RADIUS-1)));
    1022                 testStatus = false;
    1023             }
    1024             if (unmaskedPixels != (PS_SQR(2*TST04_OUTER_RADIUS) - PS_SQR(2*(TST04_INNER_RADIUS-1)))) {
    1025                 printf("TEST ERROR: pmSourceLocalSky() pmSource->mask had %d masked pixels, should have been %d.\n",
    1026                        unmaskedPixels, (PS_SQR(2*TST04_OUTER_RADIUS) - PS_SQR(2*(TST04_INNER_RADIUS-1))));
    1027                 testStatus = false;
    1028             }
    1029         }
    1030 
    1031         if (rc->moments == NULL) {
    1032             printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource->moments.\n");
    1033             testStatus = false;
    1034         } else {
    1035             if (rc->moments->Sky != TST04_SKY) {
    1036                 printf("TEST ERROR: pmSourceLocalSky() pmSource->moments->Sky was %f, should have been %f.\n", rc->moments->Sky, TST04_SKY);
    1037                 testStatus = false;
    1038             }
    1039         }
    1040     }
    1041 
    1042     printf("----------------------------------------------------------------------------------\n");
    1043     psFree(rc);
    1044     psFree(imgData);
    1045     psFree(imgDataF64);
    1046     return(testStatus);
    1047 }
    1048 
    1049 #define TST06_NUM_ROWS 100
    1050 #define TST06_NUM_COLS 100
    1051 #define TST06_SKY 20.0
    1052 #define TST06_INNER_RADIUS 3
    1053 #define TST06_OUTER_RADIUS 5
    1054 /******************************************************************************
    1055 test06(): We first test pmSourceLocalSky() with various NULL and unallowable
    1056 input parameters.
    1057  
    1058 XXX: Should we produce tests with boundary numbers for the inner/outer radius?
    1059  
    1060 XXX: Call this with varying sizes for the image.
    1061  *****************************************************************************/
    1062 int test06( void )
    1063 {
    1064     bool testStatus = true;
    1065     pmSource *tmpSource = NULL;
    1066     bool rc = false;
    1067     // Create the image used in this test.
    1068     psImage *imgData = psImageAlloc(TST06_NUM_COLS, TST06_NUM_ROWS, PS_TYPE_F32);
    1069     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    1070         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    1071             imgData->data.F32[i][j] = TST06_SKY;
    1072         }
    1073     }
    1074     psImage *imgDataF64 = psImageAlloc(TST06_NUM_COLS, TST06_NUM_ROWS, PS_TYPE_F64);
    1075     for (psS32 i = 0 ; i < imgDataF64->numRows; i++) {
    1076         for (psS32 j = 0 ; j < imgDataF64->numCols; j++) {
    1077             imgDataF64->data.F64[i][j] = 0.0;
    1078         }
    1079     }
    1080 
    1081     //
    1082     // Create a pmPeak with the center pixel set to the peak.
    1083     //
    1084     pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST06_NUM_ROWS / 2),
    1085                                   (psF32) (TST06_NUM_COLS / 2),
    1086                                   200.0,
    1087                                   PM_PEAK_LONE);
    1088 
    1089     tmpSource = pmSourceLocalSky(imgData,
    1090                                  tmpPeak,
    1091                                  PS_STAT_SAMPLE_MEAN,
    1092                                  (psF32) TST06_INNER_RADIUS,
    1093                                  (psF32) TST06_OUTER_RADIUS);
    1094     if (tmpSource == NULL) {
    1095         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
    1096         psFree(imgData);
    1097         psFree(imgDataF64);
    1098         psFree(tmpSource);
    1099         testStatus = false;
    1100         return(testStatus);
    1101     }
    1102 
    1103     printf("----------------------------------------------------------------------------------\n");
    1104     printf("Calling pmSourceSetPixelsCircle with NULL pmSource.  Should generate error and return NULL.\n");
    1105     rc = pmSourceSetPixelsCircle(NULL, imgData, 10.0);
    1106     if (rc == true) {
    1107         printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1108         testStatus = false;
    1109     }
    1110     // XXX: test with pmSource->peaks NULL
    1111 
    1112     printf("----------------------------------------------------------------------------------\n");
    1113     printf("Calling pmSourceSetPixelsCircle with NULL psImage.  Should generate error and return NULL.\n");
    1114     rc = pmSourceSetPixelsCircle(tmpSource, NULL, 10.0);
    1115     if (rc == true) {
    1116         printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1117         testStatus = false;
    1118     }
    1119 
    1120     printf("----------------------------------------------------------------------------------\n");
    1121     printf("Calling pmSourceSetPixelsCircle with wrong type psImage.  Should generate error and return NULL.\n");
    1122     rc = pmSourceSetPixelsCircle(tmpSource, imgDataF64, 10.0);
    1123     if (rc == true) {
    1124         printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1125         testStatus = false;
    1126     }
    1127 
    1128     printf("----------------------------------------------------------------------------------\n");
    1129     printf("Calling pmSourceSetPixelsCircle with radius < 0.0.  Should generate error and return NULL.\n");
    1130     rc = pmSourceSetPixelsCircle(tmpSource, imgData, -10.0);
    1131     if (rc == true) {
    1132         printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1133         testStatus = false;
    1134     }
    1135 
    1136     /* XXX: Commented away since the EAM mods no longer produced errors.
    1137         printf("----------------------------------------------------------------------------------\n");
    1138         printf("Calling pmSourceSetPixelsCircle with subImage startCol < 0.  Should generate error and return NULL.\n");
    1139         tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2);
    1140         tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2);
    1141         tmpSource->peak->x = 1;
    1142         rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0);
    1143         if (rc == true) {
    1144             printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1145             testStatus = false;
    1146         }
    1147 
    1148         printf("----------------------------------------------------------------------------------\n");
    1149         printf("Calling pmSourceSetPixelsCircle with subImage endCol > numCols.  Should generate error and return NULL.\n");
    1150         tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2);
    1151         tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2);
    1152         tmpSource->peak->x = TST06_NUM_COLS;
    1153         rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0);
    1154         if (rc == true) {
    1155             printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1156             testStatus = false;
    1157         }
    1158 
    1159         printf("----------------------------------------------------------------------------------\n");
    1160         printf("Calling pmSourceSetPixelsCircle with subImage startRow < 0.  Should generate error and return NULL.\n");
    1161         tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2);
    1162         tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2);
    1163         tmpSource->peak->y = 1;
    1164         rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0);
    1165         if (rc == true) {
    1166             printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1167             testStatus = false;
    1168         }
    1169 
    1170         printf("----------------------------------------------------------------------------------\n");
    1171         printf("Calling pmSourceSetPixelsCircle with subImage endRow > numRows.  Should generate error and return NULL.\n");
    1172         tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2);
    1173         tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2);
    1174         tmpSource->peak->y = TST06_NUM_ROWS;
    1175         rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0);
    1176         if (rc == true) {
    1177             printf("TEST ERROR: pmSourceSetPixelsCircle() returned TRUE.\n");
    1178             testStatus = false;
    1179         }
    1180     */
    1181     printf("----------------------------------------------------------------------------------\n");
    1182     printf("Calling pmSourceSetPixelsCircle with valid data.\n");
    1183     tmpSource->peak->x = (psF32) (TST06_NUM_ROWS / 2);
    1184     tmpSource->peak->y = (psF32) (TST06_NUM_COLS / 2);
    1185     rc = pmSourceSetPixelsCircle(tmpSource, imgData, 10.0);
    1186 
    1187     if (rc == false) {
    1188         printf("TEST ERROR: pmSourceSetPixelsCircle() returned FALSE.\n");
    1189         testStatus = false;
    1190     } else {
    1191         // XXX: Test correctness of the various psSetPixelsCircle members.
    1192     }
    1193 
    1194     printf("----------------------------------------------------------------------------------\n");
     903        }
     904    }
     905
     906    printf("----------------------------------------------------------------------------------\n");
     907    psFree(tmpSource);
    1195908    //    psFree(imgData);
    1196909    //    psFree(imgDataF64);
    1197     psFree(tmpSource);
     910    //    psFree(imgMask);
     911    //    psFree(imgMaskS8);
    1198912    return(testStatus);
    1199 
    1200913}
    1201914
     
    1218931{
    1219932    bool testStatus = true;
    1220     pmSource *tmpSource = NULL;
    1221     pmSource *rc = NULL;
    1222     // Create the image used in this test.
    1223     psImage *imgData = psImageAlloc(TST05_NUM_COLS, TST05_NUM_ROWS, PS_TYPE_F32);
    1224     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    1225         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    1226             imgData->data.F32[i][j] = TST05_SKY;
    1227         }
    1228     }
    1229 
    1230     //
    1231     // Create a pmPeak with the center pixel set to the peak.
    1232     //
    1233     pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST05_NUM_ROWS / 2),
    1234                                   (psF32) (TST05_NUM_COLS / 2),
    1235                                   200.0,
    1236                                   PM_PEAK_LONE);
    1237 
    1238     tmpSource = pmSourceLocalSky(imgData,
    1239                                  tmpPeak,
    1240                                  PS_STAT_SAMPLE_MEAN,
    1241                                  (psF32) TST05_INNER_RADIUS,
    1242                                  (psF32) TST05_OUTER_RADIUS);
    1243     if (tmpSource == NULL) {
    1244         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
    1245         psFree(tmpSource);
    1246         testStatus = false;
    1247         return(testStatus);
    1248     }
    1249 
    1250     printf("----------------------------------------------------------------------------------\n");
    1251     printf("Calling pmSourceMoments with NULL pmSource.  Should generate error and return NULL.\n");
    1252     rc = pmSourceMoments(NULL, 10.0);
    1253     if (rc != NULL) {
    1254         printf("TEST ERROR: pmSourceMoments() returned a non-NULL pmSource.\n");
    1255         testStatus = false;
    1256     }
    1257     // XXX: test with pmSource->peaks NULL
    1258     // XXX: test with pmSource->pixels NULL
    1259     // XXX: test with pmSource->mask NULL
    1260 
    1261     printf("----------------------------------------------------------------------------------\n");
    1262     printf("Calling pmSourceMoments with radius < 0.0.  Should generate error and return NULL.\n");
    1263     rc = pmSourceMoments(tmpSource, -10.0);
    1264     if (rc != NULL) {
    1265         printf("TEST ERROR: pmSourceMoments() returned a non-NULL pmSource.\n");
    1266         testStatus = false;
    1267     }
    1268 
    1269     printf("----------------------------------------------------------------------------------\n");
    1270     psFree(tmpSource);
    1271     return(testStatus);
    1272 
    1273 }
    1274 
    1275 /******************************************************************************
    1276 test07(): We first test the various psMinLM_... routines with various NULL and
    1277 unallowable input parameters.
    1278  
    1279 XXX: We don't verify the numbers.  Must do this.
    1280  *****************************************************************************/
    1281 int test07( void )
    1282 {
    1283     bool testStatus = true;
    1284     psF32 rc;
    1285     psVector *deriv = psVectorAlloc(7, PS_TYPE_F32);
    1286     psVector *params = psVectorAlloc(7, PS_TYPE_F32);
    1287     psVector *x = psVectorAlloc(2, PS_TYPE_F32);
    1288     for (psS32 i = 0 ; i < 7 ; i++) {
    1289         deriv->data.F32[i] = 1.0;
    1290         params->data.F32[i] = 1.0;
    1291     }
    1292 
    1293     printf("----------------------------------------------------------------------------------\n");
    1294     printf("Calling pmMinLM_Gauss2D with NULL deriv vector.  Should not generate error.\n");
    1295     rc = pmMinLM_Gauss2D(NULL, params, x);
    1296     if (isnan(rc)) {
    1297         printf("TEST ERROR: pmMinLM_Gauss2D() returned a NAN psF32.\n");
    1298         testStatus = false;
    1299     }
    1300     printf("----------------------------------------------------------------------------------\n");
    1301     printf("Calling pmMinLM_Gauss2D with NULL params vector.  Should generate error and return NAN.\n");
    1302     rc = pmMinLM_Gauss2D(deriv, NULL, x);
    1303     if (!isnan(rc)) {
    1304         printf("TEST ERROR: pmMinLM_Gauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1305         testStatus = false;
    1306     }
    1307     printf("----------------------------------------------------------------------------------\n");
    1308     printf("Calling pmMinLM_Gauss2D with NULL x vector.  Should generate error and return NAN.\n");
    1309     rc = pmMinLM_Gauss2D(deriv, params, NULL);
    1310     if (!isnan(rc)) {
    1311         printf("TEST ERROR: pmMinLM_Gauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1312         testStatus = false;
    1313     }
    1314     psFree(deriv);
    1315     psFree(params);
    1316 
    1317     deriv = psVectorAlloc(7, PS_TYPE_F32);
    1318     params = psVectorAlloc(7, PS_TYPE_F32);
    1319     for (psS32 i = 0 ; i < 7 ; i++) {
    1320         deriv->data.F32[i] = 1.0;
    1321         params->data.F32[i] = 1.0;
    1322     }
    1323     printf("----------------------------------------------------------------------------------\n");
    1324     printf("Calling pmMinLM_PsuedoGauss2D with NULL deriv vector.  Should not generate error.\n");
    1325     rc = pmMinLM_PsuedoGauss2D(NULL, params, x);
    1326     if (isnan(rc)) {
    1327         printf("TEST ERROR: pmMinLM_PsuedoGauss2D() returned a NAN psF32.\n");
    1328         testStatus = false;
    1329     }
    1330     printf("----------------------------------------------------------------------------------\n");
    1331     printf("Calling pmMinLM_PsuedoGauss2D with NULL params vector.  Should generate error and return NAN.\n");
    1332     rc = pmMinLM_PsuedoGauss2D(deriv, NULL, x);
    1333     if (!isnan(rc)) {
    1334         printf("TEST ERROR: pmMinLM_PsuedoGauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1335         testStatus = false;
    1336     }
    1337     printf("----------------------------------------------------------------------------------\n");
    1338     printf("Calling pmMinLM_PsuedoGauss2D with NULL x vector.  Should generate error and return NAN.\n");
    1339     rc = pmMinLM_PsuedoGauss2D(deriv, params, NULL);
    1340     if (!isnan(rc)) {
    1341         printf("TEST ERROR: pmMinLM_PsuedoGauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1342         testStatus = false;
    1343     }
    1344     psFree(deriv);
    1345     psFree(params);
    1346 
    1347 
    1348     deriv = psVectorAlloc(9, PS_TYPE_F32);
    1349     params = psVectorAlloc(9, PS_TYPE_F32);
    1350     for (psS32 i = 0 ; i < 9 ; i++) {
    1351         deriv->data.F32[i] = 1.0;
    1352         params->data.F32[i] = 1.0;
    1353     }
    1354     printf("----------------------------------------------------------------------------------\n");
    1355     printf("Calling pmMinLM_Wauss2D with NULL deriv vector.  Should not generate error.\n");
    1356     rc = pmMinLM_Wauss2D(NULL, params, x);
    1357     if (isnan(rc)) {
    1358         printf("TEST ERROR: pmMinLM_Wauss2D() returned a NAN psF32.\n");
    1359         testStatus = false;
    1360     }
    1361     printf("----------------------------------------------------------------------------------\n");
    1362     printf("Calling pmMinLM_Wauss2D with NULL params vector.  Should generate error and return NAN.\n");
    1363     rc = pmMinLM_Wauss2D(deriv, NULL, x);
    1364     if (!isnan(rc)) {
    1365         printf("TEST ERROR: pmMinLM_Wauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1366         testStatus = false;
    1367     }
    1368     printf("----------------------------------------------------------------------------------\n");
    1369     printf("Calling pmMinLM_Wauss2D with NULL x vector.  Should generate error and return NAN.\n");
    1370     rc = pmMinLM_Wauss2D(deriv, params, NULL);
    1371     if (!isnan(rc)) {
    1372         printf("TEST ERROR: pmMinLM_Wauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1373         testStatus = false;
    1374     }
    1375     psFree(deriv);
    1376     psFree(params);
    1377 
    1378     deriv = psVectorAlloc(11, PS_TYPE_F32);
    1379     params = psVectorAlloc(11, PS_TYPE_F32);
    1380     for (psS32 i = 0 ; i < 11 ; i++) {
    1381         deriv->data.F32[i] = 1.0;
    1382         params->data.F32[i] = 1.0;
    1383     }
    1384     printf("----------------------------------------------------------------------------------\n");
    1385     printf("Calling pmMinLM_TwistGauss2D with NULL deriv vector.  Should not generate error.\n");
    1386     rc = pmMinLM_TwistGauss2D(NULL, params, x);
    1387     if (isnan(rc)) {
    1388         printf("TEST ERROR: pmMinLM_TwistGauss2D() returned a NAN psF32.\n");
    1389         testStatus = false;
    1390     }
    1391     printf("----------------------------------------------------------------------------------\n");
    1392     printf("Calling pmMinLM_TwistGauss2D with NULL params vector.  Should generate error and return NAN.\n");
    1393     rc = pmMinLM_TwistGauss2D(deriv, NULL, x);
    1394     if (!isnan(rc)) {
    1395         printf("TEST ERROR: pmMinLM_TwistGauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1396         testStatus = false;
    1397     }
    1398     printf("----------------------------------------------------------------------------------\n");
    1399     printf("Calling pmMinLM_TwistGauss2D with NULL x vector.  Should generate error and return NAN.\n");
    1400     rc = pmMinLM_TwistGauss2D(deriv, params, NULL);
    1401     if (!isnan(rc)) {
    1402         printf("TEST ERROR: pmMinLM_TwistGauss2D() returned a non-NAN psF32 (%f).\n", rc);
    1403         testStatus = false;
    1404     }
    1405     psFree(deriv);
    1406     psFree(params);
    1407 
    1408     deriv = psVectorAlloc(8, PS_TYPE_F32);
    1409     params = psVectorAlloc(8, PS_TYPE_F32);
    1410     for (psS32 i = 0 ; i < 8 ; i++) {
    1411         deriv->data.F32[i] = 1.0;
    1412         params->data.F32[i] = 1.0;
    1413     }
    1414     printf("----------------------------------------------------------------------------------\n");
    1415     printf("Calling pmMinLM_Sersic with NULL deriv vector.  Should not generate error.\n");
    1416     rc = pmMinLM_Sersic(NULL, params, x);
    1417     if (isnan(rc)) {
    1418         printf("TEST ERROR: pmMinLM_Sersic() returned a NAN psF32.\n");
    1419         testStatus = false;
    1420     }
    1421     printf("----------------------------------------------------------------------------------\n");
    1422     printf("Calling pmMinLM_Sersic with NULL params vector.  Should generate error and return NAN.\n");
    1423     rc = pmMinLM_Sersic(deriv, NULL, x);
    1424     if (!isnan(rc)) {
    1425         printf("TEST ERROR: pmMinLM_Sersic() returned a non-NAN psF32 (%f).\n", rc);
    1426         testStatus = false;
    1427     }
    1428     printf("----------------------------------------------------------------------------------\n");
    1429     printf("Calling pmMinLM_Sersic with NULL x vector.  Should generate error and return NAN.\n");
    1430     rc = pmMinLM_Sersic(deriv, params, NULL);
    1431     if (!isnan(rc)) {
    1432         printf("TEST ERROR: pmMinLM_Sersic() returned a non-NAN psF32 (%f).\n", rc);
    1433         testStatus = false;
    1434     }
    1435     psFree(deriv);
    1436     psFree(params);
    1437 
    1438     deriv = psVectorAlloc(12, PS_TYPE_F32);
    1439     params = psVectorAlloc(12, PS_TYPE_F32);
    1440     for (psS32 i = 0 ; i < 12 ; i++) {
    1441         deriv->data.F32[i] = 1.0;
    1442         params->data.F32[i] = 1.0;
    1443     }
    1444     printf("----------------------------------------------------------------------------------\n");
    1445     printf("Calling pmMinLM_SersicCore with NULL deriv vector.  Should not generate error.\n");
    1446     rc = pmMinLM_SersicCore(NULL, params, x);
    1447     if (isnan(rc)) {
    1448         printf("TEST ERROR: pmMinLM_SersicCore() returned a NAN psF32.\n");
    1449         testStatus = false;
    1450     }
    1451     printf("----------------------------------------------------------------------------------\n");
    1452     printf("Calling pmMinLM_SersicCore with NULL params vector.  Should generate error and return NAN.\n");
    1453     rc = pmMinLM_SersicCore(deriv, NULL, x);
    1454     if (!isnan(rc)) {
    1455         printf("TEST ERROR: pmMinLM_SersicCore() returned a non-NAN psF32 (%f).\n", rc);
    1456         testStatus = false;
    1457     }
    1458     printf("----------------------------------------------------------------------------------\n");
    1459     printf("Calling pmMinLM_SersicCore with NULL x vector.  Should generate error and return NAN.\n");
    1460     rc = pmMinLM_SersicCore(deriv, params, NULL);
    1461     if (!isnan(rc)) {
    1462         printf("TEST ERROR: pmMinLM_SersicCore() returned a non-NAN psF32 (%f).\n", rc);
    1463         testStatus = false;
    1464     }
    1465 
    1466     psFree(deriv);
    1467     psFree(params);
    1468     psFree(x);
    1469     return(testStatus);
    1470 }
    1471 
    1472 /******************************************************************************
    1473 test08(): We first test pmSourceModelGuess() with various NULL and unallowable
    1474 input parameters.
    1475  
    1476 XXX: We don't verify the numbers.
    1477  *****************************************************************************/
    1478 int test08( void )
    1479 {
    1480     bool testStatus = true;
    1481933    psImage *imgData = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_F32);
    1482     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    1483         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    1484             imgData->data.F32[i][j] = TST04_SKY;
    1485         }
    1486     }
    1487     pmSource *mySrc = NULL;
    1488     bool rc = false;
     934    psImageInit(imgData, TST04_SKY);
     935    psImage *imgMask = psImageAlloc(TST04_NUM_COLS, TST04_NUM_ROWS, PS_TYPE_U8);
     936    psImageInit(imgMask, 0);
    1489937    pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST04_NUM_ROWS / 2),
    1490938                                  (psF32) (TST04_NUM_COLS / 2),
    1491939                                  200.0,
    1492940                                  PM_PEAK_LONE);
    1493 
    1494     printf("Calling pmSourceLocalSky with valid data.\n");
    1495     tmpPeak->x = (psF32) (TST04_NUM_ROWS / 2);
    1496     tmpPeak->y = (psF32) (TST04_NUM_COLS / 2);
    1497     mySrc = pmSourceLocalSky(imgData,
    1498                              tmpPeak,
    1499                              PS_STAT_SAMPLE_MEAN,
    1500                              (psF32) TST04_INNER_RADIUS,
    1501                              (psF32) TST04_OUTER_RADIUS);
    1502 
    1503     if (mySrc == NULL) {
    1504         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
    1505         testStatus = false;
    1506     }
    1507 
    1508     printf("----------------------------------------------------------------------------------\n");
    1509     printf("Calling pmSourceModelGuess with NULL pmSource.  Should generate error, return FALSE.\n");
    1510     rc = pmSourceModelGuess(NULL, imgData, PS_MODEL_GAUSS);
    1511     if (rc == true) {
    1512         printf("TEST ERROR: pmSourceModelGuess() returned TRUE.\n");
    1513         testStatus = false;
    1514     }
    1515 
    1516     printf("----------------------------------------------------------------------------------\n");
    1517     printf("Calling pmSourceModelGuess with NULL psImage.  Should generate error, return FALSE.\n");
    1518     rc = pmSourceModelGuess(mySrc, NULL, PS_MODEL_GAUSS);
    1519     if (rc == true) {
    1520         printf("TEST ERROR: pmSourceModelGuess() returned TRUE.\n");
    1521         testStatus = false;
    1522     }
    1523 
    1524     printf("----------------------------------------------------------------------------------\n");
    1525     printf("Calling pmSourceModelGuess with bad model type.  Should generate error, return FALSE.\n");
    1526     rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_UNDEFINED);
    1527     if (rc == true) {
    1528         printf("TEST ERROR: pmSourceModelGuess() returned TRUE.\n");
    1529         testStatus = false;
    1530     }
    1531 
    1532     printf("----------------------------------------------------------------------------------\n");
    1533     printf("Calling pmSourceModelGuess with PS_MODEL_GAUSS\n");
    1534     rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_GAUSS);
    1535     if (rc != true) {
    1536         printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");
    1537         testStatus = false;
    1538     }
    1539 
    1540     printf("----------------------------------------------------------------------------------\n");
    1541     printf("Calling pmSourceModelGuess with PS_MODEL_PGAUSS\n");
    1542     rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_PGAUSS);
    1543     if (rc != true) {
    1544         printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");
    1545         testStatus = false;
    1546     }
    1547 
    1548     printf("----------------------------------------------------------------------------------\n");
    1549     printf("Calling pmSourceModelGuess with PS_MODEL_TWIST_GAUSS\n");
    1550     rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_TWIST_GAUSS);
    1551     if (rc != true) {
    1552         printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");
    1553         testStatus = false;
    1554     }
    1555 
    1556     printf("----------------------------------------------------------------------------------\n");
    1557     printf("Calling pmSourceModelGuess with PS_MODEL_WAUSS\n");
    1558     rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_WAUSS);
    1559     if (rc != true) {
    1560         printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");
    1561         testStatus = false;
    1562     }
    1563 
    1564     printf("----------------------------------------------------------------------------------\n");
    1565     printf("Calling pmSourceModelGuess with PS_MODEL_SERSIC\n");
    1566     rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_SERSIC);
    1567     if (rc != true) {
    1568         printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");
    1569         testStatus = false;
    1570     }
    1571 
    1572     printf("----------------------------------------------------------------------------------\n");
    1573     printf("Calling pmSourceModelGuess with PS_MODEL_SERSIC_CORE\n");
    1574     rc = pmSourceModelGuess(mySrc, imgData, PS_MODEL_SERSIC_CORE);
    1575     if (rc != true) {
    1576         printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");
    1577         testStatus = false;
    1578     }
    1579 
    1580     psFree(mySrc);
    1581     //    psFree(tmpPeak);
    1582     psFree(imgData);
     941    pmSource *tmpSource = pmSourceAlloc();
     942    tmpSource->pixels = imgData;
     943    tmpSource->mask = imgMask;
     944    tmpSource->peak = tmpPeak;
     945    psBool rc = pmSourceLocalSky(tmpSource, PS_STAT_SAMPLE_MEAN, 10.0);
     946
     947    if (rc == false) {
     948        printf("TEST ERROR: pmSourceLocalSky() returned a FALSE pmSource.\n");
     949        testStatus = false;
     950    }
     951
     952    printf("----------------------------------------------------------------------------------\n");
     953    printf("Calling pmSourceMoments with NULL pmSource.  Should generate error and return FALSE.\n");
     954    rc = pmSourceMoments(NULL, 10.0);
     955    if (rc != false) {
     956        printf("TEST ERROR: pmSourceMoments() returned TRUE.\n");
     957        testStatus = false;
     958    }
     959    // XXX: test with pmSource->peaks NULL
     960    // XXX: test with pmSource->pixels NULL
     961    // XXX: test with pmSource->mask NULL
     962
     963    printf("----------------------------------------------------------------------------------\n");
     964    printf("Calling pmSourceMoments with radius < 0.0.  Should generate error and return FALSE.\n");
     965    rc = pmSourceMoments(tmpSource, -10.0);
     966    if (rc != false) {
     967        printf("TEST ERROR: pmSourceMoments() returned TRUE.\n");
     968        testStatus = false;
     969    }
     970
     971    printf("----------------------------------------------------------------------------------\n");
     972    psFree(tmpSource);
    1583973    return(testStatus);
     974
    1584975}
    1585976
    1586 
    1587 #define TST09_NUM_ROWS 70
    1588 #define TST09_NUM_COLS 70
    1589 #define TST09_SKY 5.0
    1590 #define TST09_INNER_RADIUS 3
    1591 #define TST09_OUTER_RADIUS 10
    1592 #define LEVEL (TST09_SKY + 10.0)
    1593 /******************************************************************************
    1594 test09(): We first test pmSourceContour() with various NULL and unallowable
    1595 input parameters.
    1596  
    1597 XXX: We don't verify the numbers.
    1598  *****************************************************************************/
    1599 int test09( void )
    1600 {
    1601     bool testStatus = true;
    1602     psImage *imgData = psImageAlloc(TST09_NUM_COLS, TST09_NUM_ROWS, PS_TYPE_F32);
    1603     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    1604         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    1605             imgData->data.F32[i][j] = TST09_SKY;
    1606         }
    1607     }
    1608     pmSource *mySrc = NULL;
    1609     psArray *rc = NULL;
    1610 
    1611     pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST09_NUM_ROWS / 2),
    1612                                   (psF32) (TST09_NUM_COLS / 2),
    1613                                   200.0,
    1614                                   PM_PEAK_LONE);
    1615 
    1616     printf("Calling pmSourceLocalSky with valid data.\n");
    1617     tmpPeak->x = (psF32) (TST09_NUM_ROWS / 2);
    1618     tmpPeak->y = (psF32) (TST09_NUM_COLS / 2);
    1619     mySrc = pmSourceLocalSky(imgData,
    1620                              tmpPeak,
    1621                              PS_STAT_SAMPLE_MEAN,
    1622                              (psF32) TST09_INNER_RADIUS,
    1623                              (psF32) TST09_OUTER_RADIUS);
    1624 
    1625     if (mySrc == NULL) {
    1626         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
    1627         testStatus = false;
    1628     }
    1629 
    1630     bool rcBool = pmSourceModelGuess(mySrc, imgData, PS_MODEL_GAUSS);
    1631     if (rcBool != true) {
    1632         printf("TEST ERROR: pmSourceModelGuess() returned FALSE.\n");
    1633         testStatus = false;
    1634     }
    1635 
    1636     printf("----------------------------------------------------------------------------------\n");
    1637     printf("Calling pmSourceContour with NULL pmSource .  Should generate error, return NULL.\n");
    1638     rc = pmSourceContour(NULL, imgData, LEVEL, PS_CONTOUR_CRUDE);
    1639     if (rc != NULL) {
    1640         printf("TEST ERROR: pmSourceContour() returned non-NULL.\n");
    1641         testStatus = false;
    1642         psFree(rc);
    1643     }
    1644 
    1645     printf("----------------------------------------------------------------------------------\n");
    1646     printf("Calling pmSourceContour with NULL psImage .  Should generate error, return NULL.\n");
    1647     rc = pmSourceContour(mySrc, NULL, LEVEL, PS_CONTOUR_CRUDE);
    1648     if (rc != NULL) {
    1649         printf("TEST ERROR: pmSourceContour() returned non-NULL.\n");
    1650         testStatus = false;
    1651         psFree(rc);
    1652     }
    1653 
    1654     //
    1655     // XXX: pmSourceContour() has a problem with contour tops/bottoms.
    1656     // Must correct this.
    1657     //
    1658     if (0) {
    1659         printf("----------------------------------------------------------------------------------\n");
    1660         printf("Calling pmSourceContour with acceptable data.\n");
    1661         printf("NOTE: must figure out the parameters for this test to be meaningful.\n");
    1662         mySrc->modelPSF->params->data.F32[0] = TST09_SKY;
    1663         mySrc->modelPSF->params->data.F32[1] = 15.0;
    1664         mySrc->modelPSF->params->data.F32[2] = (psF32) (TST09_NUM_ROWS / 2);
    1665         mySrc->modelPSF->params->data.F32[3] = (psF32) (TST09_NUM_COLS / 2);
    1666         mySrc->modelPSF->params->data.F32[4] = 2.0;
    1667         mySrc->modelPSF->params->data.F32[5] = 2.0;
    1668         mySrc->modelPSF->params->data.F32[6] = 2.0;
    1669         rc = pmSourceContour(mySrc, imgData, LEVEL, PS_CONTOUR_CRUDE);
    1670         if (rc == NULL) {
    1671             printf("TEST ERROR: pmSourceContour() returned NULL.\n");
    1672             testStatus = false;
    1673         } else {
    1674             psFree(rc);
    1675         }
    1676     }
    1677 
    1678     psFree(mySrc);
    1679     psFree(imgData);
    1680     // XXX: This psFree() causes an error.  Why?
    1681     //psFree(tmpPeak);
    1682     return(testStatus);
    1683 }
    1684 
    1685 #define TST15_NUM_ROWS 100
    1686 #define TST15_NUM_COLS 100
    1687 #define TST15_SKY 10.0
    1688 #define TST15_INNER_RADIUS 3
    1689 #define TST15_OUTER_RADIUS 5
    1690 /******************************************************************************
    1691 test15(): We first test pmSourceAddModel() with various NULL and unallowable
    1692 input parameters.
    1693  
    1694 XXX: We don't verify the numbers.
    1695  *****************************************************************************/
    1696 int test15( void )
    1697 {
    1698     bool testStatus = true;
    1699     psImage *imgData = psImageAlloc(TST15_NUM_COLS, TST15_NUM_ROWS, PS_TYPE_F32);
    1700     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    1701         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    1702             imgData->data.F32[i][j] = TST15_SKY;
    1703         }
    1704     }
    1705     pmSource *mySrc = NULL;
    1706     psBool rc = false;
    1707 
    1708     pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST15_NUM_ROWS / 2),
    1709                                   (psF32) (TST15_NUM_COLS / 2),
    1710                                   200.0,
    1711                                   PM_PEAK_LONE);
    1712 
    1713     printf("Calling pmSourceLocalSky with valid data.\n");
    1714     tmpPeak->x = (psF32) (TST15_NUM_ROWS / 2);
    1715     tmpPeak->y = (psF32) (TST15_NUM_COLS / 2);
    1716     mySrc = pmSourceLocalSky(imgData,
    1717                              tmpPeak,
    1718                              PS_STAT_SAMPLE_MEAN,
    1719                              (psF32) TST15_INNER_RADIUS,
    1720                              (psF32) TST15_OUTER_RADIUS);
    1721 
    1722     if (mySrc == NULL) {
    1723         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
    1724         testStatus = false;
    1725     }
    1726 
    1727     mySrc->modelPSF = pmModelAlloc(PS_MODEL_GAUSS);
    1728     mySrc->modelPSF->params->data.F32[0] = 5.0;
    1729     mySrc->modelPSF->params->data.F32[1] = 70.0;
    1730     mySrc->modelPSF->params->data.F32[2] = (psF32) (TST15_NUM_ROWS / 2);
    1731     mySrc->modelPSF->params->data.F32[3] = (psF32) (TST15_NUM_COLS / 2);
    1732     mySrc->modelPSF->params->data.F32[4] = 1.0;
    1733     mySrc->modelPSF->params->data.F32[5] = 1.0;
    1734     mySrc->modelPSF->params->data.F32[6] = 2.0;
    1735 
    1736     printf("----------------------------------------------------------------------------------\n");
    1737     printf("Calling pmSourceAddModel with NULL psImage.  Should generate error, return FALSE.\n");
    1738     rc = pmSourceAddModel(NULL, mySrc, true);
    1739     if (rc == true) {
    1740         printf("TEST ERROR: pmSourceAddModel() returned TRUE.\n");
    1741         testStatus = false;
    1742     }
    1743 
    1744     printf("----------------------------------------------------------------------------------\n");
    1745     printf("Calling pmSourceAddModel with NULL psSrc.  Should generate error, return FALSE.\n");
    1746     rc = pmSourceAddModel(imgData, NULL, true);
    1747     if (rc == true) {
    1748         printf("TEST ERROR: pmSourceAddModel() returned TRUE.\n");
    1749         testStatus = false;
    1750     }
    1751 
    1752     printf("----------------------------------------------------------------------------------\n");
    1753     printf("Calling pmSourceAddModel with acceptable data.\n");
    1754     rc = pmSourceAddModel(imgData, mySrc, true);
    1755     if (rc != true) {
    1756         printf("TEST ERROR: pmSourceAddModel() returned FALSE.\n");
    1757         testStatus = false;
    1758     }
    1759 
    1760     psFree(mySrc);
    1761     psFree(imgData);
    1762     return(testStatus);
    1763 }
    1764 
    1765 #define TST16_NUM_ROWS 100
    1766 #define TST16_NUM_COLS 100
    1767 #define TST16_SKY 10.0
    1768 #define TST16_INNER_RADIUS 3
    1769 #define TST16_OUTER_RADIUS 5
    1770 /******************************************************************************
    1771 test16(): We first test pmSourceSubModel() with various NULL and unallowable
    1772 input parameters.
    1773  
    1774 XXX: We don't verify the numbers.
    1775  *****************************************************************************/
    1776 int test16( void )
    1777 {
    1778     bool testStatus = true;
    1779     psImage *imgData = psImageAlloc(TST16_NUM_COLS, TST16_NUM_ROWS, PS_TYPE_F32);
    1780     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    1781         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    1782             imgData->data.F32[i][j] = TST16_SKY;
    1783         }
    1784     }
    1785     pmSource *mySrc = NULL;
    1786     psBool rc = false;
    1787 
    1788     pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST16_NUM_ROWS / 2),
    1789                                   (psF32) (TST16_NUM_COLS / 2),
    1790                                   200.0,
    1791                                   PM_PEAK_LONE);
    1792 
    1793     printf("Calling pmSourceLocalSky with valid data.\n");
    1794     tmpPeak->x = (psF32) (TST16_NUM_ROWS / 2);
    1795     tmpPeak->y = (psF32) (TST16_NUM_COLS / 2);
    1796     mySrc = pmSourceLocalSky(imgData,
    1797                              tmpPeak,
    1798                              PS_STAT_SAMPLE_MEAN,
    1799                              (psF32) TST16_INNER_RADIUS,
    1800                              (psF32) TST16_OUTER_RADIUS);
    1801 
    1802     if (mySrc == NULL) {
    1803         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
    1804         testStatus = false;
    1805     }
    1806 
    1807     mySrc->modelPSF = pmModelAlloc(PS_MODEL_GAUSS);
    1808     mySrc->modelPSF->params->data.F32[0] = 5.0;
    1809     mySrc->modelPSF->params->data.F32[1] = 70.0;
    1810     mySrc->modelPSF->params->data.F32[2] = (psF32) (TST16_NUM_ROWS / 2);
    1811     mySrc->modelPSF->params->data.F32[3] = (psF32) (TST16_NUM_COLS / 2);
    1812     mySrc->modelPSF->params->data.F32[4] = 1.0;
    1813     mySrc->modelPSF->params->data.F32[5] = 1.0;
    1814     mySrc->modelPSF->params->data.F32[6] = 2.0;
    1815 
    1816     printf("----------------------------------------------------------------------------------\n");
    1817     printf("Calling pmSourceSubModel with NULL psImage.  Should generate error, return FALSE.\n");
    1818     rc = pmSourceSubModel(NULL, mySrc, true);
    1819     if (rc == true) {
    1820         printf("TEST ERROR: pmSourceSubModel() returned TRUE.\n");
    1821         testStatus = false;
    1822     }
    1823 
    1824     printf("----------------------------------------------------------------------------------\n");
    1825     printf("Calling pmSourceSubModel with NULL psSrc.  Should generate error, return FALSE.\n");
    1826     rc = pmSourceSubModel(imgData, NULL, true);
    1827     if (rc == true) {
    1828         printf("TEST ERROR: pmSourceSubModel() returned TRUE.\n");
    1829         testStatus = false;
    1830     }
    1831 
    1832     printf("----------------------------------------------------------------------------------\n");
    1833     printf("Calling pmSourceSubModel with acceptable data.\n");
    1834     rc = pmSourceSubModel(imgData, mySrc, true);
    1835     if (rc != true) {
    1836         printf("TEST ERROR: pmSourceSubModel() returned FALSE.\n");
    1837         testStatus = false;
    1838     }
    1839 
    1840     psFree(mySrc);
    1841     psFree(imgData);
    1842     return(testStatus);
    1843 }
    1844 
    1845 #define TST20_NUM_ROWS 100
    1846 #define TST20_NUM_COLS 100
    1847 #define TST20_SKY 10.0
    1848 #define TST20_INNER_RADIUS 3
    1849 #define TST20_OUTER_RADIUS 5
    1850 /******************************************************************************
    1851 test20(): We first test pmSourceSubModel() with various NULL and unallowable
    1852 input parameters.
    1853  
    1854 XXX: We don't verify the numbers.
    1855  *****************************************************************************/
    1856 int test20( void )
    1857 {
    1858     bool testStatus = true;
    1859     psImage *imgData = psImageAlloc(TST20_NUM_COLS, TST20_NUM_ROWS, PS_TYPE_F32);
    1860     for (psS32 i = 0 ; i < imgData->numRows; i++) {
    1861         for (psS32 j = 0 ; j < imgData->numCols; j++) {
    1862             imgData->data.F32[i][j] = TST20_SKY;
    1863         }
    1864     }
    1865     pmSource *mySrc = NULL;
    1866     psBool rc = false;
    1867 
    1868     pmPeak *tmpPeak = pmPeakAlloc((psF32) (TST20_NUM_ROWS / 2),
    1869                                   (psF32) (TST20_NUM_COLS / 2),
    1870                                   200.0,
    1871                                   PM_PEAK_LONE);
    1872 
    1873     printf("Calling pmSourceLocalSky with valid data.\n");
    1874     tmpPeak->x = (psF32) (TST20_NUM_ROWS / 2);
    1875     tmpPeak->y = (psF32) (TST20_NUM_COLS / 2);
    1876     mySrc = pmSourceLocalSky(imgData,
    1877                              tmpPeak,
    1878                              PS_STAT_SAMPLE_MEAN,
    1879                              (psF32) TST20_INNER_RADIUS,
    1880                              (psF32) TST20_OUTER_RADIUS);
    1881 
    1882     if (mySrc == NULL) {
    1883         printf("TEST ERROR: pmSourceLocalSky() returned a NULL pmSource.\n");
    1884         testStatus = false;
    1885     }
    1886 
    1887     mySrc->modelPSF = pmModelAlloc(PS_MODEL_GAUSS);
    1888 
    1889 
    1890     mySrc->modelPSF->params->data.F32[0] = 5.0;
    1891     mySrc->modelPSF->params->data.F32[1] = 70.0;
    1892     mySrc->modelPSF->params->data.F32[2] = (psF32) (TST20_NUM_ROWS / 2);
    1893     mySrc->modelPSF->params->data.F32[3] = (psF32) (TST20_NUM_COLS / 2);
    1894     mySrc->modelPSF->params->data.F32[4] = 1.0;
    1895     mySrc->modelPSF->params->data.F32[5] = 1.0;
    1896     mySrc->modelPSF->params->data.F32[6] = 2.0;
    1897 
    1898     printf("----------------------------------------------------------------------------------\n");
    1899     printf("Calling pmSourceFitModel with NULL psImage.  Should generate error, return FALSE.\n");
    1900     rc = pmSourceFitModel(mySrc, NULL);
    1901     if (rc == true) {
    1902         printf("TEST ERROR: pmSourceFitModel() returned TRUE.\n");
    1903         testStatus = false;
    1904     }
    1905 
    1906     printf("----------------------------------------------------------------------------------\n");
    1907     printf("Calling pmSourceFitModel with NULL pmSource.  Should generate error, return FALSE.\n");
    1908     rc = pmSourceFitModel(NULL, imgData);
    1909     if (rc == true) {
    1910         printf("TEST ERROR: pmSourceFitModel() returned TRUE.\n");
    1911         testStatus = false;
    1912     }
    1913 
    1914     printf("----------------------------------------------------------------------------------\n");
    1915     printf("Calling pmSourceFitModel with acceptable data.\n");
    1916     rc = pmSourceFitModel(mySrc, imgData);
    1917     printf("pmSourceFitModel returned %d\n", rc);
    1918 
    1919     // XXX: Memory leaks are not being tested
    1920     psVector *junk = psVectorAlloc(10, PS_TYPE_F32);
    1921     junk->data.F32[0] = 0.0;
    1922 
    1923     psFree(mySrc);
    1924     psFree(imgData);
    1925     return(testStatus);
    1926 }
    1927 
    1928 
    1929977// this code will
    1930978
Note: See TracChangeset for help on using the changeset viewer.