IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 3510


Ignore:
Timestamp:
Mar 25, 2005, 1:18:35 PM (21 years ago)
Author:
gusciora
Message:

Added code for the pmSourceContour() routine.

Location:
trunk/psModules/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/pmObjects.c

    r3498 r3510  
    55 *  @author GLG, MHPCC
    66 *
    7  *  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
    8  *  @date $Date: 2005-03-24 22:36:52 $
     7 *  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
     8 *  @date $Date: 2005-03-25 23:18:35 $
    99 *
    1010 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    740740                             float SNlim,
    741741                             const psRegion *valid)
    742 XXX: Waiting for sample code from IfA.
    743  
    744 XXX: Most code this.
     742XXX: The sigX and sigY stuff in the SDRS is unclear.
     743 
     744XXX: How can this function ever return FALSE?
    745745 *****************************************************************************/
    746746#define SATURATE 0.0
     
    760760        psSource *tmpSrc = (psSource *) source->data[i];
    761761        PS_PTR_CHECK_NULL(tmpSrc->moments, false);
     762        tmpSrc->peak->class = 0;
    762763
    763764        if (tmpSrc->moments->Peak > SATURATE) {
    764             tmpSrc->peak->class = PS_SOURCE_SATURATED;
     765            tmpSrc->peak->class|= PS_SOURCE_SATURATED;
    765766        } else {
    766767            // XXX: gleen these from the metadata: keywords GAIN and READ_NOISE.
     
    773774                       PS_SQRT_F32(S + (A * B) + ((A * readNoise * readNoise) / PS_SQRT_F32(gain)));
    774775            if (SN < FAINT_SN_LIM) {
    775                 tmpSrc->peak->class = PS_SOURCE_FAINTSTAR;
     776                tmpSrc->peak->class|= PS_SOURCE_FAINTSTAR;
    776777            }
    777778            if (SN < PSF_SN_LIM) {
    778                 tmpSrc->peak->class = PS_SOURCE_FAINTSTAR;
     779                tmpSrc->peak->class|= PS_SOURCE_FAINTSTAR;
    779780            }
     781            // XXX: gleen these from the metadata: keywords GAIN and READ_NOISE.
     782            psF32 clumpX = 0.0;
     783            psF32 clumpDX = 0.0;
     784            psF32 clumpY = 0.0;
     785            psF32 clumpYX = 0.0;
     786            // XXX: The SDRS is not real clear on how to calculate sigX, sigY.
     787            psF32 sigX = 0.0
     788                         psF32 sigY = 0.0
     789                                      if ((fabs(sigX - clumpX) < clumpDX) &&
     790                                              (fabs(sigY - clumpY) < clumpDY)) {
     791                                          tmpSrc->peak->class|= PS_SOURCE_PSFSTAR;
     792                                      }
     793
     794                                      if ((sigX < (clumpX - clumpDX)) &&
     795                                              (sigY < (clumpY - clumpDY)))
     796                                          tmpSrc->peak->class|= PS_SOURCE_DEFECT;
    780797        }
    781     }
    782 
    783     return(rc);
     798
     799        if ((sigX > (clumpX + clumpDX)) &&
     800                (sigY > (clumpY + clumpDY)))
     801            tmpSrc->peak->class|= PS_SOURCE_GALAXY;
     802    }
     803
     804    if (tmpSrc->peak->class == 0) {
     805        tmpSrc->peak->class|= PS_SOURCE_OTHER;
     806    }
    784807}
    785 
    786 
    787 
    788 /******************************************************************************
    789 pmSourceSetPixelCircle(source, image, radius)
    790  
    791 XXX: Why boolean output?
    792  
    793 XXX: Why are we checking source->moments for NULL?  Should the circle be
    794      centered on the centroid or the peak?
    795  
    796 XXX: The circle will have a diameter of (1+radius).  This is different from
    797      the pmSourceSetLocal() function.
    798  *****************************************************************************/
    799 bool pmSourceSetPixelCircle(psSource *source,
    800                             const psImage *image,
    801                             psF32 radius)
    802 {
    803     PS_IMAGE_CHECK_NULL(image, false);
    804     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
    805     PS_PTR_CHECK_NULL(source, false);
    806     //    PS_PTR_CHECK_NULL(source->moments, false);
    807     PS_PTR_CHECK_NULL(source->peak, false);
    808     PS_FLOAT_COMPARE(0.0, radius, false);
    809 
    810     //
    811     // We define variables for code readability.
    812     //
    813     psS32 radiusS32 = (psS32) radius;
    814     psS32 SubImageCenterRow = source->peak->y;
    815     psS32 SubImageCenterCol = source->peak->x;
    816     psS32 SubImageStartRow = SubImageCenterRow - radiusS32;
    817     psS32 SubImageEndRow = SubImageCenterRow + radiusS32;
    818     psS32 SubImageStartCol = SubImageCenterCol - radiusS32;
    819     psS32 SubImageEndCol = SubImageCenterCol + radiusS32;
    820 
    821     if (SubImageStartRow < 0) {
    822         psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
    823                 SubImageStartRow);
    824         return(false);
    825     }
    826     if (SubImageEndRow+1 >= image->numRows) {
    827         psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n",
    828                 SubImageEndRow);
    829         return(false);
    830     }
    831     if (SubImageStartCol < 0) {
    832         psError(PS_ERR_UNKNOWN, true, "Sub image startCol is outside image boundaries (%d).\n",
    833                 SubImageStartCol);
    834         return(false);
    835     }
    836     if (SubImageEndCol+1 >= image->numCols) {
    837         psError(PS_ERR_UNKNOWN, true, "Sub image endCol is outside image boundaries (%d).\n",
    838                 SubImageEndCol);
    839         return(false);
    840     }
    841 
    842     // XXX: Must recycle image.
    843     if (source->pixels != NULL) {
    844         psLogMsg(__func__, PS_LOG_WARN,
    845                  "WARNING: pmSourceSetPixelCircle(): image->pixels not NULL.  Freeing and reallocating.\n");
    846         psFree(source->pixels);
    847     }
    848     source->pixels = psImageSubset((psImage *) image,
    849                                    SubImageStartCol,
    850                                    SubImageStartRow,
    851                                    SubImageEndCol+1,
    852                                    SubImageEndRow+1);
    853 
    854     // XXX: Must recycle image.
    855     if (source->mask != NULL) {
    856         psFree(source->mask);
    857     }
    858     source->mask = psImageAlloc(1 + 2 * radiusS32, 1 + 2 * radiusS32, PS_TYPE_F32);
    859 
    860     //
    861     // Loop through the subimage mask, initialize mask to 0 or 1.
    862     //
    863     for (psS32 row = 0 ; row < source->mask->numRows; row++) {
    864         for (psS32 col = 0 ; col < source->mask->numCols; col++) {
    865 
    866             if (CheckRadius2((psF32) radiusS32,
    867                              (psF32) radiusS32,
    868                              radius,
    869                              (psF32) col,
    870                              (psF32) row)) {
    871                 source->mask->data.U8[row][col] = 1;
    872             } else {
    873                 source->mask->data.U8[row][col] = 1;
    874             }
    875         }
    876     }
    877 
    878     /*
    879         for (psS32 row = SubImageCenterRow - radiusS32; row <= SubImageCenterRow + radiusS32; row++) {
    880             for (psS32 col = SubImageCenterCol - radiusS32; col <= SubImageCenterCol + radiusS32; col++) {
    881                 if (CheckRadius(source->peak, radius, (psF32) col, (psF32) row)) {
    882                     source->mask->data.U8[row-SubImageCenterRow][col-SubImageCenterCol] = 1;
    883                 }
    884             }
    885         }
    886     */
    887 
    888     return(true);
    889808}
    890809
    891 
    892 /******************************************************************************
    893 pmSourceModelGuess(source, image, model): This function allocates a new
    894 psModel structure and store it in the psSource data structure specified in the
    895 argument list.  The model type is specified in the argument list.  The params
    896 array in that psModel structure are allocated, and then set to the appropriate
    897 values.  This function returns true if everything was successful.
    898  
    899 XXX: Many of the initial parameters are set to 0.0 since I don't know what
    900 the appropiate initial guesses are.
    901  *****************************************************************************/
    902 bool pmSourceModelGuess(psSource *source,
    903                         const psImage *image,
    904                         psModelType model)
    905 {
    906     PS_PTR_CHECK_NULL(source, false);
    907     PS_PTR_CHECK_NULL(source->moments, false);
    908     PS_PTR_CHECK_NULL(source->peak, false);
    909     PS_IMAGE_CHECK_NULL(image, false);
    910     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
    911     if (source->models != NULL) {
    912         psLogMsg(__func__, PS_LOG_WARN, "WARNING: source->models was non-NULL; calling psFree(source->models).\n");
    913         psFree(source->models);
    914     }
    915     source->models = pmModelAlloc(PS_MODEL_UNDEFINED);
    916 
    917     switch (model) {
    918     case PS_MODEL_GAUSS:
    919         source->models->type = PS_MODEL_GAUSS;
    920         source->models->Nparams = 7;
    921         source->models->params = (psF32 *) psAlloc(7 * sizeof(psF32));
    922         source->models->dparams = (psF32 *) psAlloc(7 * sizeof(psF32));
    923         for (psS32 i = 0 ; i < 7 ; i++) {
    924             source->models->params[i] = 0.0;
    925             source->models->dparams[i] = 0.0;
    926         }
    927         source->models->params[0] = source->moments->Sky;
    928         source->models->params[1] = source->peak->counts - source->moments->Sky;
    929         source->models->params[2] = source->moments->x;
    930         source->models->params[3] = source->moments->y;
    931         source->models->params[4] = sqrt(2.0) / source->moments->Sx;
    932         source->models->params[5] = sqrt(2.0) / source->moments->Sy;
    933         source->models->params[6] = source->moments->Sxy;
    934         source->models->chisq = 0.0;
    935         return(true);
    936     case PS_MODEL_PGAUSS:
    937         source->models->type = PS_MODEL_PGAUSS;
    938         source->models->Nparams = 7;
    939         source->models->params = (psF32 *) psAlloc(7 * sizeof(psF32));
    940         source->models->dparams = (psF32 *) psAlloc(7 * sizeof(psF32));
    941         for (psS32 i = 0 ; i < 7 ; i++) {
    942             source->models->params[i] = 0.0;
    943             source->models->dparams[i] = 0.0;
    944         }
    945         source->models->params[0] = source->moments->Sky;
    946         source->models->params[1] = source->peak->counts - source->moments->Sky;
    947         source->models->params[2] = source->moments->x;
    948         source->models->params[3] = source->moments->y;
    949         source->models->params[4] = sqrt(2.0) / source->moments->Sx;
    950         source->models->params[5] = sqrt(2.0) / source->moments->Sy;
    951         source->models->params[6] = source->moments->Sxy;
    952         source->models->chisq = 0.0;
    953         return(true);
    954     case PS_MODEL_TWIST_GAUSS:
    955         source->models->type = PS_MODEL_TWIST_GAUSS;
    956         source->models->Nparams = 11;
    957         source->models->params = (psF32 *) psAlloc(11 * sizeof(psF32));
    958         source->models->dparams = (psF32 *) psAlloc(11 * sizeof(psF32));
    959         for (psS32 i = 0 ; i < 11 ; i++) {
    960             source->models->params[i] = 0.0;
    961             source->models->dparams[i] = 0.0;
    962         }
    963 
    964         source->models->params[0] = source->moments->Sky;
    965         source->models->params[1] = source->peak->counts - source->moments->Sky;
    966         source->models->params[2] = source->moments->x;
    967         source->models->params[3] = source->moments->y;
    968         // XXX: What are these?
    969         // source->models->params[4] = SxInner;
    970         // source->models->params[5] = SyInner;
    971         // source->models->params[6] = SxyInner;
    972         // source->models->params[7] = SxOuter;
    973         // source->models->params[8] = SyOuter;
    974         // source->models->params[9] = SxyOuter;
    975         // source->models->params[10] = N;
    976 
    977         source->models->chisq = 0.0;
    978         return(true);
    979     case PS_MODEL_WAUSS:
    980 
    981         source->models->params[0] = source->moments->Sky;
    982         source->models->params[1] = source->peak->counts - source->moments->Sky;
    983         source->models->params[2] = source->moments->x;
    984         source->models->params[3] = source->moments->y;
    985         source->models->params[4] = sqrt(2.0) / source->moments->Sx;
    986         source->models->params[5] = sqrt(2.0) / source->moments->Sy;
    987         source->models->params[6] = source->moments->Sxy;
    988         // XXX: What are these?
    989         // source->models->params[7] = B2;
    990         // source->models->params[8] = B3;
    991 
    992         source->models->type = PS_MODEL_WAUSS;
    993         source->models->Nparams = 9;
    994         source->models->params = (psF32 *) psAlloc(9 * sizeof(psF32));
    995         source->models->dparams = (psF32 *) psAlloc(9 * sizeof(psF32));
    996         for (psS32 i = 0 ; i < 9 ; i++) {
    997             source->models->params[i] = 0.0;
    998             source->models->dparams[i] = 0.0;
    999         }
    1000         source->models->chisq = 0.0;
    1001         return(true);
    1002     case PS_MODEL_SERSIC:
    1003         source->models->type = PS_MODEL_SERSIC;
    1004         source->models->Nparams = 8;
    1005         source->models->params = (psF32 *) psAlloc(8 * sizeof(psF32));
    1006         source->models->dparams = (psF32 *) psAlloc(8 * sizeof(psF32));
    1007         for (psS32 i = 0 ; i < 8 ; i++) {
    1008             source->models->params[i] = 0.0;
    1009             source->models->dparams[i] = 0.0;
    1010         }
    1011 
    1012         source->models->params[0] = source->moments->Sky;
    1013         source->models->params[1] = source->peak->counts - source->moments->Sky;
    1014         source->models->params[2] = source->moments->x;
    1015         source->models->params[3] = source->moments->y;
    1016         source->models->params[4] = sqrt(2.0) / source->moments->Sx;
    1017         source->models->params[5] = sqrt(2.0) / source->moments->Sy;
    1018         source->models->params[6] = source->moments->Sxy;
    1019         // XXX: What are these?
    1020         //source->models->params[7] = Nexp;
    1021 
    1022         source->models->chisq = 0.0;
    1023         return(true);
    1024     case PS_MODEL_SERSIC_CORE:
    1025         source->models->type = PS_MODEL_SERSIC_CORE;
    1026         source->models->Nparams = 12;
    1027         source->models->params = (psF32 *) psAlloc(12 * sizeof(psF32));
    1028         source->models->dparams = (psF32 *) psAlloc(12 * sizeof(psF32));
    1029         for (psS32 i = 0 ; i < 12 ; i++) {
    1030             source->models->params[i] = 0.0;
    1031             source->models->dparams[i] = 0.0;
    1032         }
    1033 
    1034         source->models->params[0] = source->moments->Sky;
    1035         source->models->params[1] = source->peak->counts - source->moments->Sky;
    1036         source->models->params[2] = source->moments->x;
    1037         source->models->params[3] = source->moments->y;
    1038         // XXX: What are these?
    1039         //source->models->params[4] SxInner;
    1040         //source->models->params[5] SyInner;
    1041         //source->models->params[6] SxyInner;
    1042         //source->models->params[7] Zd;
    1043         //source->models->params[8] SxOuter;
    1044         //source->models->params[9] SyOuter;
    1045         //source->models->params[10] = SxyOuter;
    1046         //source->models->params[11] = Nexp;
    1047 
    1048         source->models->chisq = 0.0;
    1049         return(true);
    1050     default:
    1051         psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
    1052         return(false);
    1053     }
    1054 }
    1055 
    1056 
    1057 /******************************************************************************
    1058  
    1059  *****************************************************************************/
    1060 psArray *pmSourceContour(psSource *source,
    1061                          const psImage *image,
    1062                          psF32 level,
    1063                          psS32 mode)
    1064 {
    1065     return(NULL);
    1066 }
    1067 
    1068 psVector *p_pmMinLM_Gauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1069 psVector *p_pmMinLM_PsuedoGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1070 psVector *p_pmMinLM_Wauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1071 psVector *p_pmMinLM_TwistGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
    1072 psVector *p_pmMinLM_Sersic_Vec(psImage *deriv, psVector *params, psArray *x);
    1073 psVector *p_pmMinLM_SersicCore_Vec(psImage *deriv, psVector *params, psArray *x);
    1074 
    1075 //XXX: What should these values be?
    1076 #define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 100
    1077 #define PM_SOURCE_FIT_MODEL_TOLERANCE 1.0
    1078 /******************************************************************************
    1079 pmSourceFitModel(source, image): must create the appropiate arguments to the
    1080 LM minimization routines for the various p_pmMinLM_XXXXXX_Vec() functions.
    1081  
    1082 XXX: should there be a mask value?
    1083  *****************************************************************************/
    1084 bool pmSourceFitModel(psSource *source,
    1085                       const psImage *image)
    1086 {
    1087     PS_PTR_CHECK_NULL(source, false);
    1088     PS_PTR_CHECK_NULL(source->moments, false);
    1089     PS_PTR_CHECK_NULL(source->peak, false);
    1090     PS_PTR_CHECK_NULL(source->pixels, false);
    1091     PS_PTR_CHECK_NULL(source->models, false);
    1092     PS_IMAGE_CHECK_NULL(image, false);
    1093     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
    1094 
    1095     psBool rc;
    1096     psS32 count = 0;
    1097     for (psS32 i = 0 ; i < source->pixels->numRows ; i++) {
    1098         for (psS32 j = 0 ; j < source->pixels->numCols ; j++) {
    1099             if (source->mask->data.U8[i][j] == 0) {
    1100                 count++;
    1101             }
    1102         }
    1103     }
    1104     psArray *x = psArrayAlloc(count);
    1105     psVector *y = psVectorAlloc(count, PS_TYPE_F32);
    1106     for (psS32 i = 0 ; i < source->pixels->numRows ; i++) {
    1107         for (psS32 j = 0 ; j < source->pixels->numCols ; j++) {
    1108             if (source->mask->data.U8[i][j] == 0) {
    1109                 psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
    1110                 // XXX: Should we use the subimage offsets here, or does it not matter?
    1111                 coord->data.F32[0] = (psF32) (i);
    1112                 coord->data.F32[1] = (psF32) (j);
    1113                 x->data[count] = (psPtr *) coord;
    1114                 y->data.F32[count] = source->pixels->data.F32[i][j];
    1115             }
    1116         }
    1117     }
    1118 
    1119     psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS,
    1120                             PM_SOURCE_FIT_MODEL_TOLERANCE);
    1121 
    1122     psVector *params = psVectorAlloc(source->models->Nparams, PS_TYPE_F32);
    1123 
    1124     switch (source->models->type) {
    1125     case PS_MODEL_GAUSS:
    1126         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
    1127                               NULL, (psMinimizeLMChi2Func) p_pmMinLM_Gauss2D_Vec);
    1128         break;
    1129     case PS_MODEL_PGAUSS:
    1130         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
    1131                               NULL, (psMinimizeLMChi2Func) p_pmMinLM_PsuedoGauss2D_Vec);
    1132         break;
    1133     case PS_MODEL_TWIST_GAUSS:
    1134         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
    1135                               NULL, (psMinimizeLMChi2Func) p_pmMinLM_Wauss2D_Vec);
    1136         break;
    1137     case PS_MODEL_WAUSS:
    1138         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
    1139                               NULL, (psMinimizeLMChi2Func) p_pmMinLM_TwistGauss2D_Vec);
    1140         break;
    1141     case PS_MODEL_SERSIC:
    1142         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
    1143                               NULL, (psMinimizeLMChi2Func) p_pmMinLM_Sersic_Vec);
    1144         break;
    1145     case PS_MODEL_SERSIC_CORE:
    1146         rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
    1147                               NULL, (psMinimizeLMChi2Func) p_pmMinLM_SersicCore_Vec);
    1148         break;
    1149     default:
    1150         psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
    1151         rc = false;
    1152     }
    1153 
    1154     psFree(x);
    1155     psFree(y);
    1156     psFree(myMin);
    1157     psFree(params);
    1158     return(rc);
    1159 }
    1160 
    1161 bool p_pmSourceAddOrSubModel(psImage *image,
    1162                              psSource *source,
    1163                              bool center,
    1164                              psS32 flag)
    1165 {
    1166     PS_PTR_CHECK_NULL(source, false);
    1167     PS_PTR_CHECK_NULL(source->moments, false);
    1168     PS_PTR_CHECK_NULL(source->peak, false);
    1169     PS_PTR_CHECK_NULL(source->pixels, false);
    1170     PS_PTR_CHECK_NULL(source->models, false);
    1171     PS_IMAGE_CHECK_NULL(image, false);
    1172     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
    1173 
    1174     // XXX: make static, document.
    1175     psVector *deriv = psVectorAlloc(100, PS_TYPE_F32);
    1176     psVector *params = psVectorAlloc(100, PS_TYPE_F32);
    1177     psVector *x = psVectorAlloc(2, PS_TYPE_F32);
    1178     for (psS32 i = 0 ; i < source->models->Nparams ; i++) {
    1179         params->data.F32[i] = source->models->params[i];
    1180     }
    1181 
    1182     for (psS32 i = 0 ; i < source->pixels->numRows ; i++) {
    1183         for (psS32 j = 0 ; j < source->pixels->numCols ; j++) {
    1184             psF32 pixelValue;
    1185             // XXX: Should you use offsets here?
    1186             // XXX: Make sure you have col/row order correct.
    1187             x->data.F32[0] = (float) j;
    1188             x->data.F32[1] = (float) i;
    1189             switch (source->models->type) {
    1190             case PS_MODEL_GAUSS:
    1191                 pixelValue = pmMinLM_Gauss2D(deriv, params, x);
    1192                 break;
    1193             case PS_MODEL_PGAUSS:
    1194                 pixelValue = pmMinLM_PsuedoGauss2D(deriv, params, x);
    1195                 break;
    1196             case PS_MODEL_TWIST_GAUSS:
    1197                 pixelValue = pmMinLM_TwistGauss2D(deriv, params, x);
    1198                 break;
    1199             case PS_MODEL_WAUSS:
    1200                 pixelValue = pmMinLM_Wauss2D(deriv, params, x);
    1201                 break;
    1202             case PS_MODEL_SERSIC:
    1203                 pixelValue = pmMinLM_Sersic(deriv, params, x);
    1204                 break;
    1205             case PS_MODEL_SERSIC_CORE:
    1206                 pixelValue = pmMinLM_SersicCore(deriv, params, x);
    1207                 break;
    1208             default:
    1209                 psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
    1210                 psFree(x);
    1211                 psFree(deriv);
    1212                 psFree(params);
    1213                 return(false);
    1214             }
    1215             if (flag == 1) {
    1216                 pixelValue = -pixelValue;
    1217             }
    1218 
    1219             // XXX: Must figure out how to calculate the image coordinates and
    1220             // how to use the boolean "center" flag.
    1221             psS32 imageRow = 0;
    1222             psS32 imageCol = 0;
    1223             image->data.F32[imageRow][imageCol]+= pixelValue;
    1224         }
    1225     }
    1226     psFree(x);
    1227     psFree(deriv);
    1228     psFree(params);
    1229     return(true);
    1230 }
    1231 
    1232 
    1233 
    1234 /******************************************************************************
    1235  *****************************************************************************/
    1236 bool pmSourceAddModel(psImage *image,
    1237                       psSource *source,
    1238                       bool center)
    1239 {
    1240     return(p_pmSourceAddOrSubModel(image, source, center, 0));
    1241 }
    1242 
    1243 /******************************************************************************
    1244  *****************************************************************************/
    1245 bool pmSourceSubModel(psImage *image,
    1246                       psSource *source,
    1247                       bool center)
    1248 {
    1249     return(p_pmSourceAddOrSubModel(image, source, center, 1));
    1250 }
    1251 
    1252 
    1253 // XXX: Put this is psConstants.h
    1254 #define PS_VECTOR_CHECK_SIZE(VEC1, N, RVAL) \
    1255 if (VEC1->n != N) { \
    1256     psError(PS_ERR_BAD_PARAMETER_SIZE, true, \
    1257             "psVector %s has size %d, should be %d.", \
    1258             #VEC1, VEC1->n, N); \
    1259     return(RVAL); \
    1260 }
    1261 
    1262 
    1263 /******************************************************************************
    1264 pmMinLM_Gauss2D(*deriv, *params, *x): the argument "x" contains a single "x,
    1265 y" coordinate pair.  This function computes the gaussian, specified by the
    1266 parameters in "params" at that x,y point and returns the value.  The
    1267 derivatives are also caculated and returned in the "deriv" argument.
    1268  
    1269     params->data.F32[0] = So;
    1270     params->data.F32[1] = Zo;
    1271     params->data.F32[2] = Xo;
    1272     params->data.F32[3] = Yo;
    1273     params->data.F32[4] = sqrt(2.0) / SigmaX;
    1274     params->data.F32[5] = sqrt(2.0) / SigmaY;
    1275     params->data.F32[6] = Sxy;
    1276  
    1277 XXX: Consider getting rid of the parameter checks since this might consume
    1278 a significant fraction of this function CPU time.
    1279  *****************************************************************************/
    1280 psF32 pmMinLM_Gauss2D(psVector *deriv,
    1281                       psVector *params,
    1282                       psVector *x)
    1283 {
    1284     PS_VECTOR_CHECK_NULL(deriv, NAN);
    1285     PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
    1286     PS_VECTOR_CHECK_SIZE(deriv, 7, NAN);
    1287     PS_VECTOR_CHECK_NULL(params, NAN);
    1288     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
    1289     PS_VECTOR_CHECK_SIZE(params, 7, NAN);
    1290     PS_VECTOR_CHECK_NULL(x, NAN);
    1291     PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
    1292     PS_VECTOR_CHECK_SIZE(x, 2, NAN);
    1293 
    1294     psF32 X = x->data.F32[0] - params->data.F32[2];
    1295     psF32 Y = x->data.F32[1] - params->data.F32[3];
    1296     psF32 px = params->data.F32[4]*X;
    1297     psF32 py = params->data.F32[5]*Y;
    1298     psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
    1299     psF32 r = exp(-z);
    1300     psF32 f = params->data.F32[1]*r + params->data.F32[0];
    1301 
    1302     psF32 q = params->data.F32[1]*r;
    1303     deriv->data.F32[0] = +1.0;
    1304     deriv->data.F32[1] = +r;
    1305     deriv->data.F32[2] = q*(2*px*params->data.F32[4] + params->data.F32[6]*Y);
    1306     deriv->data.F32[3] = q*(2*py*params->data.F32[5] + params->data.F32[6]*X);
    1307     deriv->data.F32[4] = -2.0*q*px*X;
    1308     deriv->data.F32[5] = -2.0*q*py*Y;
    1309     deriv->data.F32[6] = -q*X*Y;
    1310 
    1311     return(f);
    1312 }
    1313 
    1314 /******************************************************************************
    1315 p_pmMinLM_Gauss2D_Vec(*deriv, *params, *x): this function wraps the above
    1316 function in a form that is usable in the LM minimization routines.
    1317  *****************************************************************************/
    1318 psVector *p_pmMinLM_Gauss2D_Vec(psImage *deriv,
    1319                                 psVector *params,
    1320                                 psArray *x)
    1321 {
    1322     PS_IMAGE_CHECK_NULL(deriv, NULL);
    1323     PS_IMAGE_CHECK_EMPTY(deriv, NULL);
    1324     PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
    1325     PS_VECTOR_CHECK_NULL(params, NULL);
    1326     PS_VECTOR_CHECK_EMPTY(params, NULL);
    1327     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
    1328     PS_PTR_CHECK_NULL(x, NULL);
    1329     if (deriv->numRows != x->n) {
    1330         psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
    1331     }
    1332     psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
    1333     // XXX: use static memory here.
    1334     psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
    1335 
    1336     for (psS32 i = 0 ; i < x->n ; i++) {
    1337         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1338             tmpRow->data.F32[j] = deriv->data.F32[i][j];
    1339         }
    1340 
    1341         tmpVec->data.F32[i] = pmMinLM_Gauss2D(tmpRow,
    1342                                               params,
    1343                                               (psVector *) x->data[i]);
    1344 
    1345         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1346             deriv->data.F32[i][j] = tmpRow->data.F32[j];
    1347         }
    1348     }
    1349 
    1350     psFree(tmpRow);
    1351     return(tmpVec);
    1352 }
    1353 
    1354 
    1355 /******************************************************************************
    1356     params->data.F32[0] = So;
    1357     params->data.F32[1] = Zo;
    1358     params->data.F32[2] = Xo;
    1359     params->data.F32[3] = Yo;
    1360     params->data.F32[4] = sqrt(2) / SigmaX;
    1361     params->data.F32[5] = sqrt(2) / SigmaY;
    1362     params->data.F32[6] = Sxy;
    1363  *****************************************************************************/
    1364 psF32 pmMinLM_PsuedoGauss2D(psVector *deriv,
     810return(rc);
     811      }
     812
     813
     814
     815      /******************************************************************************
     816      pmSourceSetPixelCircle(source, image, radius)
     817       
     818      XXX: Why boolean output?
     819       
     820      XXX: Why are we checking source->moments for NULL?  Should the circle be
     821           centered on the centroid or the peak?
     822       
     823      XXX: The circle will have a diameter of (1+radius).  This is different from
     824           the pmSourceSetLocal() function.
     825       *****************************************************************************/
     826      bool pmSourceSetPixelCircle(psSource *source,
     827                                  const psImage *image,
     828                                  psF32 radius)
     829      {
     830          PS_IMAGE_CHECK_NULL(image, false);
     831          PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
     832          PS_PTR_CHECK_NULL(source, false);
     833          //    PS_PTR_CHECK_NULL(source->moments, false);
     834          PS_PTR_CHECK_NULL(source->peak, false);
     835          PS_FLOAT_COMPARE(0.0, radius, false);
     836
     837          //
     838          // We define variables for code readability.
     839          //
     840          psS32 radiusS32 = (psS32) radius;
     841          psS32 SubImageCenterRow = source->peak->y;
     842          psS32 SubImageCenterCol = source->peak->x;
     843          psS32 SubImageStartRow = SubImageCenterRow - radiusS32;
     844          psS32 SubImageEndRow = SubImageCenterRow + radiusS32;
     845          psS32 SubImageStartCol = SubImageCenterCol - radiusS32;
     846          psS32 SubImageEndCol = SubImageCenterCol + radiusS32;
     847
     848          if (SubImageStartRow < 0) {
     849              psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
     850                      SubImageStartRow);
     851              return(false);
     852          }
     853          if (SubImageEndRow+1 >= image->numRows) {
     854              psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n",
     855                      SubImageEndRow);
     856              return(false);
     857          }
     858          if (SubImageStartCol < 0) {
     859              psError(PS_ERR_UNKNOWN, true, "Sub image startCol is outside image boundaries (%d).\n",
     860                      SubImageStartCol);
     861              return(false);
     862          }
     863          if (SubImageEndCol+1 >= image->numCols) {
     864              psError(PS_ERR_UNKNOWN, true, "Sub image endCol is outside image boundaries (%d).\n",
     865                      SubImageEndCol);
     866              return(false);
     867          }
     868
     869          // XXX: Must recycle image.
     870          if (source->pixels != NULL) {
     871              psLogMsg(__func__, PS_LOG_WARN,
     872                       "WARNING: pmSourceSetPixelCircle(): image->pixels not NULL.  Freeing and reallocating.\n");
     873              psFree(source->pixels);
     874          }
     875          source->pixels = psImageSubset((psImage *) image,
     876                                         SubImageStartCol,
     877                                         SubImageStartRow,
     878                                         SubImageEndCol+1,
     879                                         SubImageEndRow+1);
     880
     881          // XXX: Must recycle image.
     882          if (source->mask != NULL) {
     883              psFree(source->mask);
     884          }
     885          source->mask = psImageAlloc(1 + 2 * radiusS32,
     886                                      1 + 2 * radiusS32,
     887                                      PS_TYPE_F32);
     888
     889          //
     890          // Loop through the subimage mask, initialize mask to 0 or 1.
     891          //
     892          for (psS32 row = 0 ; row < source->mask->numRows; row++) {
     893              for (psS32 col = 0 ; col < source->mask->numCols; col++) {
     894
     895                  if (CheckRadius2((psF32) radiusS32,
     896                                   (psF32) radiusS32,
     897                                   radius,
     898                                   (psF32) col,
     899                                   (psF32) row)) {
     900                      source->mask->data.U8[row][col] = 1;
     901                  } else {
     902                      source->mask->data.U8[row][col] = 0;
     903                  }
     904              }
     905          }
     906          return(true);
     907      }
     908
     909
     910      /******************************************************************************
     911      pmSourceModelGuess(source, image, model): This function allocates a new
     912      psModel structure and store it in the psSource data structure specified in the
     913      argument list.  The model type is specified in the argument list.  The params
     914      array in that psModel structure are allocated, and then set to the appropriate
     915      values.  This function returns true if everything was successful.
     916       
     917      XXX: Many of the initial parameters are set to 0.0 since I don't know what
     918      the appropiate initial guesses are.
     919       *****************************************************************************/
     920      bool pmSourceModelGuess(psSource *source,
     921                              const psImage *image,
     922                              psModelType model)
     923      {
     924          PS_PTR_CHECK_NULL(source, false);
     925          PS_PTR_CHECK_NULL(source->moments, false);
     926          PS_PTR_CHECK_NULL(source->peak, false);
     927          PS_IMAGE_CHECK_NULL(image, false);
     928          PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
     929          if (source->models != NULL) {
     930              psLogMsg(__func__, PS_LOG_WARN, "WARNING: source->models was non-NULL; calling psFree(source->models).\n");
     931              psFree(source->models);
     932          }
     933          source->models = pmModelAlloc(PS_MODEL_UNDEFINED);
     934
     935          switch (model) {
     936          case PS_MODEL_GAUSS:
     937              source->models->type = PS_MODEL_GAUSS;
     938              source->models->Nparams = 7;
     939              source->models->params = (psF32 *) psAlloc(7 * sizeof(psF32));
     940              source->models->dparams = (psF32 *) psAlloc(7 * sizeof(psF32));
     941              for (psS32 i = 0 ; i < 7 ; i++) {
     942                  source->models->params[i] = 0.0;
     943                  source->models->dparams[i] = 0.0;
     944              }
     945              source->models->params[0] = source->moments->Sky;
     946              source->models->params[1] = source->peak->counts - source->moments->Sky;
     947              source->models->params[2] = source->moments->x;
     948              source->models->params[3] = source->moments->y;
     949              source->models->params[4] = sqrt(2.0) / source->moments->Sx;
     950              source->models->params[5] = sqrt(2.0) / source->moments->Sy;
     951              source->models->params[6] = source->moments->Sxy;
     952              source->models->chisq = 0.0;
     953              return(true);
     954          case PS_MODEL_PGAUSS:
     955              source->models->type = PS_MODEL_PGAUSS;
     956              source->models->Nparams = 7;
     957              source->models->params = (psF32 *) psAlloc(7 * sizeof(psF32));
     958              source->models->dparams = (psF32 *) psAlloc(7 * sizeof(psF32));
     959              for (psS32 i = 0 ; i < 7 ; i++) {
     960                  source->models->params[i] = 0.0;
     961                  source->models->dparams[i] = 0.0;
     962              }
     963              source->models->params[0] = source->moments->Sky;
     964              source->models->params[1] = source->peak->counts - source->moments->Sky;
     965              source->models->params[2] = source->moments->x;
     966              source->models->params[3] = source->moments->y;
     967              source->models->params[4] = sqrt(2.0) / source->moments->Sx;
     968              source->models->params[5] = sqrt(2.0) / source->moments->Sy;
     969              source->models->params[6] = source->moments->Sxy;
     970              source->models->chisq = 0.0;
     971              return(true);
     972          case PS_MODEL_TWIST_GAUSS:
     973              source->models->type = PS_MODEL_TWIST_GAUSS;
     974              source->models->Nparams = 11;
     975              source->models->params = (psF32 *) psAlloc(11 * sizeof(psF32));
     976              source->models->dparams = (psF32 *) psAlloc(11 * sizeof(psF32));
     977              for (psS32 i = 0 ; i < 11 ; i++) {
     978                  source->models->params[i] = 0.0;
     979                  source->models->dparams[i] = 0.0;
     980              }
     981
     982              source->models->params[0] = source->moments->Sky;
     983              source->models->params[1] = source->peak->counts - source->moments->Sky;
     984              source->models->params[2] = source->moments->x;
     985              source->models->params[3] = source->moments->y;
     986              // XXX: What are these?
     987              // source->models->params[4] = SxInner;
     988              // source->models->params[5] = SyInner;
     989              // source->models->params[6] = SxyInner;
     990              // source->models->params[7] = SxOuter;
     991              // source->models->params[8] = SyOuter;
     992              // source->models->params[9] = SxyOuter;
     993              // source->models->params[10] = N;
     994
     995              source->models->chisq = 0.0;
     996              return(true);
     997          case PS_MODEL_WAUSS:
     998
     999              source->models->params[0] = source->moments->Sky;
     1000              source->models->params[1] = source->peak->counts - source->moments->Sky;
     1001              source->models->params[2] = source->moments->x;
     1002              source->models->params[3] = source->moments->y;
     1003              source->models->params[4] = sqrt(2.0) / source->moments->Sx;
     1004              source->models->params[5] = sqrt(2.0) / source->moments->Sy;
     1005              source->models->params[6] = source->moments->Sxy;
     1006              // XXX: What are these?
     1007              // source->models->params[7] = B2;
     1008              // source->models->params[8] = B3;
     1009
     1010              source->models->type = PS_MODEL_WAUSS;
     1011              source->models->Nparams = 9;
     1012              source->models->params = (psF32 *) psAlloc(9 * sizeof(psF32));
     1013              source->models->dparams = (psF32 *) psAlloc(9 * sizeof(psF32));
     1014              for (psS32 i = 0 ; i < 9 ; i++) {
     1015                  source->models->params[i] = 0.0;
     1016                  source->models->dparams[i] = 0.0;
     1017              }
     1018              source->models->chisq = 0.0;
     1019              return(true);
     1020          case PS_MODEL_SERSIC:
     1021              source->models->type = PS_MODEL_SERSIC;
     1022              source->models->Nparams = 8;
     1023              source->models->params = (psF32 *) psAlloc(8 * sizeof(psF32));
     1024              source->models->dparams = (psF32 *) psAlloc(8 * sizeof(psF32));
     1025              for (psS32 i = 0 ; i < 8 ; i++) {
     1026                  source->models->params[i] = 0.0;
     1027                  source->models->dparams[i] = 0.0;
     1028              }
     1029
     1030              source->models->params[0] = source->moments->Sky;
     1031              source->models->params[1] = source->peak->counts - source->moments->Sky;
     1032              source->models->params[2] = source->moments->x;
     1033              source->models->params[3] = source->moments->y;
     1034              source->models->params[4] = sqrt(2.0) / source->moments->Sx;
     1035              source->models->params[5] = sqrt(2.0) / source->moments->Sy;
     1036              source->models->params[6] = source->moments->Sxy;
     1037              // XXX: What are these?
     1038              //source->models->params[7] = Nexp;
     1039
     1040              source->models->chisq = 0.0;
     1041              return(true);
     1042          case PS_MODEL_SERSIC_CORE:
     1043              source->models->type = PS_MODEL_SERSIC_CORE;
     1044              source->models->Nparams = 12;
     1045              source->models->params = (psF32 *) psAlloc(12 * sizeof(psF32));
     1046              source->models->dparams = (psF32 *) psAlloc(12 * sizeof(psF32));
     1047              for (psS32 i = 0 ; i < 12 ; i++) {
     1048                  source->models->params[i] = 0.0;
     1049                  source->models->dparams[i] = 0.0;
     1050              }
     1051
     1052              source->models->params[0] = source->moments->Sky;
     1053              source->models->params[1] = source->peak->counts - source->moments->Sky;
     1054              source->models->params[2] = source->moments->x;
     1055              source->models->params[3] = source->moments->y;
     1056              // XXX: What are these?
     1057              //source->models->params[4] SxInner;
     1058              //source->models->params[5] SyInner;
     1059              //source->models->params[6] SxyInner;
     1060              //source->models->params[7] Zd;
     1061              //source->models->params[8] SxOuter;
     1062              //source->models->params[9] SyOuter;
     1063              //source->models->params[10] = SxyOuter;
     1064              //source->models->params[11] = Nexp;
     1065
     1066              source->models->chisq = 0.0;
     1067              return(true);
     1068          default:
     1069              psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
     1070              return(false);
     1071          }
     1072      }
     1073
     1074      /******************************************************************************
     1075      evalModel(source, level, row): a private function which evaluates the
     1076      source->model function at the specified coords.
     1077       
     1078      NOTE: The coords are in source->pixel coords, not image coords.
     1079       
     1080      XXX: reverse order of row,col args?
     1081       
     1082      XXX: This should probably be a public function.
     1083       
     1084      XXX: We don't care about the model derivatives here.  So, for the individual
     1085      model evaluation functions, we should probably separate the derivative
     1086      calculation.
     1087       
     1088      XXX: Get rid of deriv.
     1089       
     1090      XXX: Use static vectors for x.
     1091       
     1092      XXX: Figure out if it's (row, col) or (col, row) for the model functions.
     1093       *****************************************************************************/
     1094      psF32 evalModel(psSource *src,
     1095                      psU32 row,
     1096                      psU32 col)
     1097      {
     1098          // XXX: You won't need this once you separate the function evaluation.
     1099          // from the derivative calculation.
     1100          psVector *deriv = psVectorAlloc(src->models->Nparams, PS_TYPE_F32);
     1101          // XXX: The following step will not be necessary if the models->params
     1102          // member is a psVector.
     1103          psVector *params = psVectorAlloc(src->models->Nparams, PS_TYPE_F32);
     1104          for (psS32 i = 0 ; i < src->models->Nparams ; i++) {
     1105              params->data.F32[i] = src->models->params[i];
     1106          }
     1107          psVector *x = psVectorAlloc(2, PS_TYPE_F32);
     1108          x->data.F32[0] = (psF32) (col + src->pixels->col0);
     1109          x->data.F32[1] = (psF32) (row + src->pixels->row0);
     1110          psF32 tmpF;
     1111
     1112
     1113          switch (src->models->type) {
     1114          case PS_MODEL_GAUSS:
     1115              tmpF = pmMinLM_Gauss2D(deriv, params, x);
     1116              break;
     1117          case PS_MODEL_PGAUSS:
     1118              tmpF = pmMinLM_PsuedoGauss2D(deriv, params, x);
     1119              break;
     1120          case PS_MODEL_TWIST_GAUSS:
     1121              tmpF = pmMinLM_TwistGauss2D(deriv, params, x);
     1122              break;
     1123          case PS_MODEL_WAUSS:
     1124              tmpF = pmMinLM_Wauss2D(deriv, params, x);
     1125              break;
     1126          case PS_MODEL_SERSIC:
     1127              tmpF = pmMinLM_Sersic(deriv, params, x);
     1128              break;
     1129          case PS_MODEL_SERSIC_CORE:
     1130              tmpF = pmMinLM_SersicCore(deriv, params, x);
     1131              break;
     1132          default:
     1133              psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
     1134              return(NAN);
     1135          }
     1136
     1137          psFree(deriv);
     1138          psFree(params);
     1139          psFree(x);
     1140          return(tmpF);
     1141      }
     1142
     1143      /******************************************************************************
     1144      findValue(source, level, row, col, dir): a private function which determines
     1145      the column coordinate of the model function which has the value "level".  If
     1146      dir equals 0, then you loop leftwards from the peak pixel, otherwise,
     1147      rightwards.
     1148       
     1149      XXX: reverse order of row,col args?
     1150       
     1151      XXX: The result is returned in subImage coords, not image coords.
     1152       *****************************************************************************/
     1153      psF32 findValue(psSource *source,
     1154                      psF32 level,
     1155                      psU32 row,
     1156                      psU32 col,
     1157                      psU32 dir)
     1158      {
     1159          // Ensure that the starting column is allowable.
     1160          if (!((0 <= col) && (col < source->pixels->numCols))) {
     1161              psError(PS_ERR_UNKNOWN, true, "Starting column outside subImage range");
     1162              return(NAN);
     1163          }
     1164
     1165          psF32 oldValue = evalModel(source, row, col);
     1166          if (oldValue == level) {
     1167              return(((psF32) col));
     1168          }
     1169
     1170          //
     1171          // We define variables incr and lastColumn so that we can use the same loop
     1172          // whether we are stepping leftwards, or rightwards.
     1173          //
     1174          psS32 incr;
     1175          psS32 lastColumn;
     1176          if (dir == 0) {
     1177              incr = -1;
     1178              lastColumn = -1;
     1179          } else {
     1180              incr = 1;
     1181              lastColumn = source->pixels->numCols;
     1182          }
     1183          col+=incr;
     1184
     1185          while (col != lastColumn) {
     1186              psF32 newValue = evalModel(source, row, col);
     1187              if (oldValue == level) {
     1188                  return(col);
     1189              }
     1190
     1191              if ((newValue <= level) && (level <= oldValue)) {
     1192                  // This is simple linear interpolation.
     1193                  return( ((psF32) col) + ((psF32) incr) * ((level - newValue) / (oldValue - newValue)) );
     1194              }
     1195
     1196              if ((oldValue <= level) && (level <= newValue)) {
     1197                  // This is simple linear interpolation.
     1198                  return( ((psF32) col) + ((psF32) incr) * ((level - oldValue) / (newValue - oldValue)) );
     1199              }
     1200
     1201              col+=incr;
     1202          }
     1203
     1204          return(NAN);
     1205      }
     1206      /******************************************************************************
     1207      XXX: Probably should remove the "image" argument.
     1208      XXX: What type should the output coordinate vectors consist of?
     1209      XXX: Why a pmArray output?
     1210      XXX: doex x,y correspond with col,row or row/col?
     1211       *****************************************************************************/
     1212      psArray *pmSourceContour(psSource *source,
     1213                               const psImage *image,
     1214                               psF32 level,
     1215                               pmContourType mode)
     1216      {
     1217          PS_PTR_CHECK_NULL(source, false);
     1218          PS_PTR_CHECK_NULL(source->moments, false);
     1219          PS_PTR_CHECK_NULL(source->peak, false);
     1220          PS_PTR_CHECK_NULL(source->pixels, false);
     1221          PS_PTR_CHECK_NULL(source->models, false);
     1222
     1223          //
     1224          // Allocate data for x/y pairs.
     1225          //
     1226          psVector *xVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32);
     1227          psVector *yVec = psVectorAlloc(2 * source->pixels->numRows, PS_TYPE_F32);
     1228
     1229          //
     1230          // Start at the row with peak pixel, then decrement.
     1231          //
     1232          psS32 col = source->peak->x;
     1233          for (psS32 row = source->peak->y; row>= 0 ; row--) {
     1234              // XXX: yVec contain no real information.  Do we really need it?
     1235              yVec->data.F32[row] = (psF32) (source->pixels->row0 + row);
     1236              yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row);
     1237
     1238              // Starting at peak pixel, search leftwards for the column intercept.
     1239              psF32 leftIntercept = findValue(source, level, row, col, 0);
     1240              xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept;
     1241
     1242              // Starting at peak pixel, search rightwards for the column intercept.
     1243              psF32 rightIntercept = findValue(source, level, row, col, 1);
     1244              xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept;
     1245
     1246              // Set starting column for next row
     1247              col = (psS32) ((leftIntercept + rightIntercept) / 2.0);
     1248          }
     1249          //
     1250          // Start at the row (+1) with peak pixel, then increment.
     1251          //
     1252          col = source->peak->x;
     1253          for (psS32 row = 1 + source->peak->y; row < source->pixels->numRows ; row++) {
     1254              // XXX: yVec contain no real information.  Do we really need it?
     1255              yVec->data.F32[row] = (psF32) (source->pixels->row0 + row);
     1256              yVec->data.F32[row+yVec->n] = (psF32) (source->pixels->row0 + row);
     1257
     1258              // Starting at peak pixel, search leftwards for the column intercept.
     1259              psF32 leftIntercept = findValue(source, level, row, col, 0);
     1260              xVec->data.F32[row] = ((psF32) source->pixels->col0) + leftIntercept;
     1261
     1262              // Starting at peak pixel, search rightwards for the column intercept.
     1263              psF32 rightIntercept = findValue(source, level, row, col, 1);
     1264              xVec->data.F32[row+xVec->n] = ((psF32) source->pixels->col0) + rightIntercept;
     1265
     1266              // Set starting column for next row
     1267              col = (psS32) ((leftIntercept + rightIntercept) / 2.0);
     1268          }
     1269
     1270          //
     1271          // Allocate an array for result, store coord vectors there.
     1272          //
     1273          psArray *tmpArray = psArrayAlloc(2);
     1274          tmpArray->data[0] = (psPtr *) yVec;
     1275          tmpArray->data[1] = (psPtr *) xVec;
     1276          return(tmpArray);
     1277      }
     1278
     1279      psVector *p_pmMinLM_Gauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
     1280      psVector *p_pmMinLM_PsuedoGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
     1281      psVector *p_pmMinLM_Wauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
     1282      psVector *p_pmMinLM_TwistGauss2D_Vec(psImage *deriv, psVector *params, psArray *x);
     1283      psVector *p_pmMinLM_Sersic_Vec(psImage *deriv, psVector *params, psArray *x);
     1284      psVector *p_pmMinLM_SersicCore_Vec(psImage *deriv, psVector *params, psArray *x);
     1285
     1286      //XXX: What should these values be?
     1287      #define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 100
     1288      #define PM_SOURCE_FIT_MODEL_TOLERANCE 1.0
     1289      /******************************************************************************
     1290      pmSourceFitModel(source, image): must create the appropiate arguments to the
     1291      LM minimization routines for the various p_pmMinLM_XXXXXX_Vec() functions.
     1292       
     1293      XXX: should there be a mask value?
     1294      XXX: Probably should remove the "image" argument.
     1295       *****************************************************************************/
     1296      bool pmSourceFitModel(psSource *source,
     1297                            const psImage *image)
     1298      {
     1299          PS_PTR_CHECK_NULL(source, false);
     1300          PS_PTR_CHECK_NULL(source->moments, false);
     1301          PS_PTR_CHECK_NULL(source->peak, false);
     1302          PS_PTR_CHECK_NULL(source->pixels, false);
     1303          PS_PTR_CHECK_NULL(source->models, false);
     1304          PS_IMAGE_CHECK_NULL(image, false);
     1305          PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
     1306
     1307          psBool rc;
     1308          psS32 count = 0;
     1309          for (psS32 i = 0 ; i < source->pixels->numRows ; i++) {
     1310              for (psS32 j = 0 ; j < source->pixels->numCols ; j++) {
     1311                  if (source->mask->data.U8[i][j] == 0) {
     1312                      count++;
     1313                  }
     1314              }
     1315          }
     1316          psArray *x = psArrayAlloc(count);
     1317          psVector *y = psVectorAlloc(count, PS_TYPE_F32);
     1318          for (psS32 i = 0 ; i < source->pixels->numRows ; i++) {
     1319              for (psS32 j = 0 ; j < source->pixels->numCols ; j++) {
     1320                  if (source->mask->data.U8[i][j] == 0) {
     1321                      psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
     1322                      // XXX: Should we use the subimage offsets here, or does it not matter?
     1323                      coord->data.F32[0] = (psF32) (i);
     1324                      coord->data.F32[1] = (psF32) (j);
     1325                      x->data[count] = (psPtr *) coord;
     1326                      y->data.F32[count] = source->pixels->data.F32[i][j];
     1327                  }
     1328              }
     1329          }
     1330
     1331          psMinimization *myMin = psMinimizationAlloc(PM_SOURCE_FIT_MODEL_NUM_ITERATIONS,
     1332                                  PM_SOURCE_FIT_MODEL_TOLERANCE);
     1333
     1334          psVector *params = psVectorAlloc(source->models->Nparams, PS_TYPE_F32);
     1335
     1336          switch (source->models->type) {
     1337          case PS_MODEL_GAUSS:
     1338              rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
     1339                                    NULL, (psMinimizeLMChi2Func) p_pmMinLM_Gauss2D_Vec);
     1340              break;
     1341          case PS_MODEL_PGAUSS:
     1342              rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
     1343                                    NULL, (psMinimizeLMChi2Func) p_pmMinLM_PsuedoGauss2D_Vec);
     1344              break;
     1345          case PS_MODEL_TWIST_GAUSS:
     1346              rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
     1347                                    NULL, (psMinimizeLMChi2Func) p_pmMinLM_Wauss2D_Vec);
     1348              break;
     1349          case PS_MODEL_WAUSS:
     1350              rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
     1351                                    NULL, (psMinimizeLMChi2Func) p_pmMinLM_TwistGauss2D_Vec);
     1352              break;
     1353          case PS_MODEL_SERSIC:
     1354              rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
     1355                                    NULL, (psMinimizeLMChi2Func) p_pmMinLM_Sersic_Vec);
     1356              break;
     1357          case PS_MODEL_SERSIC_CORE:
     1358              rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
     1359                                    NULL, (psMinimizeLMChi2Func) p_pmMinLM_SersicCore_Vec);
     1360              break;
     1361          default:
     1362              psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
     1363              rc = false;
     1364          }
     1365
     1366          psFree(x);
     1367          psFree(y);
     1368          psFree(myMin);
     1369          psFree(params);
     1370          return(rc);
     1371      }
     1372
     1373      bool p_pmSourceAddOrSubModel(psImage *image,
     1374                                   psSource *src,
     1375                                   bool center,
     1376                                   psS32 flag)
     1377      {
     1378          PS_PTR_CHECK_NULL(src, false);
     1379          PS_PTR_CHECK_NULL(src->moments, false);
     1380          PS_PTR_CHECK_NULL(src->peak, false);
     1381          PS_PTR_CHECK_NULL(src->pixels, false);
     1382          PS_PTR_CHECK_NULL(src->models, false);
     1383          PS_IMAGE_CHECK_NULL(image, false);
     1384          PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
     1385
     1386          // XXX: make static, document.
     1387          // We use a length of 100 here since it is larger enough for all models.
     1388          #define MAX_PARAMS
     1389
     1390          psVector *deriv = psVectorAlloc(MAX_PARAMS, PS_TYPE_F32);
     1391          psVector *params = psVectorAlloc(MAX_PARAMS, PS_TYPE_F32);
     1392          psVector *x = psVectorAlloc(2, PS_TYPE_F32);
     1393          if (src->models->Nparams > MAX_PARAMS) {
     1394              psError(PS_ERR_UNKNOWN, true, "Internal error: increase MAX_PARAMS to %d", src->models->Nparams);
     1395          }
     1396          for (psS32 i = 0 ; i < src->models->Nparams ; i++) {
     1397              params->data.F32[i] = src->models->params[i];
     1398          }
     1399
     1400          for (psS32 i = 0 ; i < src->pixels->numRows ; i++) {
     1401              for (psS32 j = 0 ; j < src->pixels->numCols ; j++) {
     1402                  psF32 pixelValue;
     1403                  // XXX: Should you use offsets here?
     1404                  // XXX: Make sure you have col/row order correct.
     1405                  // XXX: Should you be adding the pixels for the entire subImage,
     1406                  // or a radius of pixels around it?
     1407
     1408                  x->data.F32[0] = (float) j;
     1409                  x->data.F32[1] = (float) i;
     1410                  switch (src->models->type) {
     1411                  case PS_MODEL_GAUSS:
     1412                      pixelValue = pmMinLM_Gauss2D(deriv, params, x);
     1413                      break;
     1414                  case PS_MODEL_PGAUSS:
     1415                      pixelValue = pmMinLM_PsuedoGauss2D(deriv, params, x);
     1416                      break;
     1417                  case PS_MODEL_TWIST_GAUSS:
     1418                      pixelValue = pmMinLM_TwistGauss2D(deriv, params, x);
     1419                      break;
     1420                  case PS_MODEL_WAUSS:
     1421                      pixelValue = pmMinLM_Wauss2D(deriv, params, x);
     1422                      break;
     1423                  case PS_MODEL_SERSIC:
     1424                      pixelValue = pmMinLM_Sersic(deriv, params, x);
     1425                      break;
     1426                  case PS_MODEL_SERSIC_CORE:
     1427                      pixelValue = pmMinLM_SersicCore(deriv, params, x);
     1428                      break;
     1429                  default:
     1430                      psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
     1431                      psFree(x);
     1432                      psFree(deriv);
     1433                      psFree(params);
     1434                      return(false);
     1435                  }
     1436                  if (flag == 1) {
     1437                      pixelValue = -pixelValue;
     1438                  }
     1439
     1440                  // XXX: Must figure out how to calculate the image coordinates and
     1441                  // how to use the boolean "center" flag.
     1442                  psS32 imageRow = i + src->pixels->row0;
     1443                  psS32 imageCol = j + src->pixles->col0;
     1444
     1445                  image->data.F32[imageRow][imageCol]+= pixelValue;
     1446              }
     1447          }
     1448          psFree(x);
     1449          psFree(deriv);
     1450          psFree(params);
     1451          return(true);
     1452      }
     1453
     1454
     1455
     1456      /******************************************************************************
     1457       *****************************************************************************/
     1458      bool pmSourceAddModel(psImage *image,
     1459                            psSource *src,
     1460                            bool center)
     1461      {
     1462          return(p_pmSourceAddOrSubModel(image, src, center, 0));
     1463      }
     1464
     1465      /******************************************************************************
     1466       *****************************************************************************/
     1467      bool pmSourceSubModel(psImage *image,
     1468                            psSource *src,
     1469                            bool center)
     1470      {
     1471          return(p_pmSourceAddOrSubModel(image, src, center, 1));
     1472      }
     1473
     1474
     1475      // XXX: Put this is psConstants.h
     1476      #define PS_VECTOR_CHECK_SIZE(VEC1, N, RVAL) \
     1477      if (VEC1->n != N) { \
     1478          psError(PS_ERR_BAD_PARAMETER_SIZE, true, \
     1479                  "psVector %s has size %d, should be %d.", \
     1480                  #VEC1, VEC1->n, N); \
     1481          return(RVAL); \
     1482      }
     1483
     1484
     1485      /******************************************************************************
     1486      pmMinLM_Gauss2D(*deriv, *params, *x): the argument "x" contains a single "x,
     1487      y" coordinate pair.  This function computes the gaussian, specified by the
     1488      parameters in "params" at that x,y point and returns the value.  The
     1489      derivatives are also caculated and returned in the "deriv" argument.
     1490       
     1491          params->data.F32[0] = So;
     1492          params->data.F32[1] = Zo;
     1493          params->data.F32[2] = Xo;
     1494          params->data.F32[3] = Yo;
     1495          params->data.F32[4] = sqrt(2.0) / SigmaX;
     1496          params->data.F32[5] = sqrt(2.0) / SigmaY;
     1497          params->data.F32[6] = Sxy;
     1498       
     1499      XXX: Consider getting rid of the parameter checks since this might consume
     1500      a significant fraction of this function CPU time.
     1501       *****************************************************************************/
     1502      psF32 pmMinLM_Gauss2D(psVector *deriv,
    13651503                            psVector *params,
    13661504                            psVector *x)
    1367 {
    1368     PS_VECTOR_CHECK_NULL(deriv, NAN);
    1369     PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
    1370     PS_VECTOR_CHECK_SIZE(deriv, 7, NAN);
    1371     PS_VECTOR_CHECK_NULL(params, NAN);
    1372     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
    1373     PS_VECTOR_CHECK_SIZE(params, 7, NAN);
    1374     PS_VECTOR_CHECK_NULL(x, NAN);
    1375     PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
    1376     PS_VECTOR_CHECK_SIZE(x, 2, NAN);
    1377 
    1378     psF32 X = x->data.F32[0] - params->data.F32[2];
    1379     psF32 Y = x->data.F32[1] - params->data.F32[3];
    1380     psF32 px = params->data.F32[4]*X;
    1381     psF32 py = params->data.F32[5]*Y;
    1382     psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
    1383     psF32 t = 1 + z + 0.5*z*z;
    1384     psF32 r = 1.0 / (t*(1 + z/3)); /* exp (-Z) */
    1385     psF32 f = params->data.F32[1]*r + params->data.F32[0];
    1386 
    1387     //
    1388     // note difference from a pure gaussian: q = params->data.F32[1]*r
    1389     //
    1390 
    1391     psF32 q = params->data.F32[1]*r*r*t;
    1392     deriv->data.F32[0] = +1.0;
    1393     deriv->data.F32[1] = +r;
    1394     deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
    1395     deriv->data.F32[3] = q *
    1396                          (2.0*py*params->data.F32[5] + params->data.F32[6]*X);
    1397     deriv->data.F32[4] = -2.0*q*px*X;
    1398     deriv->data.F32[5] = -2.0*q*py*Y;
    1399     deriv->data.F32[6] = -q*X*Y;
    1400 
    1401     return(f);
    1402 }
    1403 
    1404 /******************************************************************************
    1405 p_pmMinLM_PsuedoGauss2D_Vec(*deriv, *params, *x): this function wraps the
    1406 above function in a form that is usable in the LM minimization routines.
    1407  *****************************************************************************/
    1408 psVector *p_pmMinLM_PsuedoGauss2D_Vec(psImage *deriv,
     1505      {
     1506          PS_VECTOR_CHECK_NULL(deriv, NAN);
     1507          PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
     1508          PS_VECTOR_CHECK_SIZE(deriv, 7, NAN);
     1509          PS_VECTOR_CHECK_NULL(params, NAN);
     1510          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
     1511          PS_VECTOR_CHECK_SIZE(params, 7, NAN);
     1512          PS_VECTOR_CHECK_NULL(x, NAN);
     1513          PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
     1514          PS_VECTOR_CHECK_SIZE(x, 2, NAN);
     1515
     1516          psF32 X = x->data.F32[0] - params->data.F32[2];
     1517          psF32 Y = x->data.F32[1] - params->data.F32[3];
     1518          psF32 px = params->data.F32[4]*X;
     1519          psF32 py = params->data.F32[5]*Y;
     1520          psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
     1521          psF32 r = exp(-z);
     1522          psF32 f = params->data.F32[1]*r + params->data.F32[0];
     1523
     1524          psF32 q = params->data.F32[1]*r;
     1525          deriv->data.F32[0] = +1.0;
     1526          deriv->data.F32[1] = +r;
     1527          deriv->data.F32[2] = q*(2*px*params->data.F32[4] + params->data.F32[6]*Y);
     1528          deriv->data.F32[3] = q*(2*py*params->data.F32[5] + params->data.F32[6]*X);
     1529          deriv->data.F32[4] = -2.0*q*px*X;
     1530          deriv->data.F32[5] = -2.0*q*py*Y;
     1531          deriv->data.F32[6] = -q*X*Y;
     1532
     1533          return(f);
     1534      }
     1535
     1536      /******************************************************************************
     1537      p_pmMinLM_Gauss2D_Vec(*deriv, *params, *x): this function wraps the above
     1538      function in a form that is usable in the LM minimization routines.
     1539       *****************************************************************************/
     1540      psVector *p_pmMinLM_Gauss2D_Vec(psImage *deriv,
    14091541                                      psVector *params,
    14101542                                      psArray *x)
    1411 {
    1412     PS_IMAGE_CHECK_NULL(deriv, NULL);
    1413     PS_IMAGE_CHECK_EMPTY(deriv, NULL);
    1414     PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
    1415     PS_VECTOR_CHECK_NULL(params, NULL);
    1416     PS_VECTOR_CHECK_EMPTY(params, NULL);
    1417     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
    1418     PS_PTR_CHECK_NULL(x, NULL);
    1419     if (deriv->numRows != x->n) {
    1420         psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
    1421     }
    1422     psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
    1423     // XXX: use static memory here.
    1424     psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
    1425 
    1426     for (psS32 i = 0 ; i < x->n ; i++) {
    1427         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1428             tmpRow->data.F32[j] = deriv->data.F32[i][j];
    1429         }
    1430 
    1431         tmpVec->data.F32[i] = pmMinLM_PsuedoGauss2D(tmpRow,
    1432                               params,
    1433                               (psVector *) x->data[i]);
    1434 
    1435         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1436             deriv->data.F32[i][j] = tmpRow->data.F32[j];
    1437         }
    1438     }
    1439 
    1440     psFree(tmpRow);
    1441     return(tmpVec);
    1442 }
    1443 
    1444 
    1445 
    1446 
    1447 /******************************************************************************
    1448     params->data.F32[0] = So;
    1449     params->data.F32[1] = Zo;
    1450     params->data.F32[2] = Xo;
    1451     params->data.F32[3] = Yo;
    1452     params->data.F32[4] = Sx;
    1453     params->data.F32[5] = Sy;
    1454     params->data.F32[6] = Sxy;
    1455     params->data.F32[7] = B2;
    1456     params->data.F32[8] = B3;
    1457  *****************************************************************************/
    1458 psF32 pmMinLM_Wauss2D(psVector *deriv,
    1459                       psVector *params,
    1460                       psVector *x)
    1461 {
    1462     PS_VECTOR_CHECK_NULL(deriv, NAN);
    1463     PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
    1464     PS_VECTOR_CHECK_SIZE(deriv, 9, NAN);
    1465     PS_VECTOR_CHECK_NULL(params, NAN);
    1466     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
    1467     PS_VECTOR_CHECK_SIZE(params, 9, NAN);
    1468     PS_VECTOR_CHECK_NULL(x, NAN);
    1469     PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
    1470     PS_VECTOR_CHECK_SIZE(x, 2, NAN);
    1471 
    1472     psF32 X = x->data.F32[0] - params->data.F32[2];
    1473     psF32 Y = x->data.F32[1] - params->data.F32[2];
    1474     psF32 px = params->data.F32[4]*X;
    1475     psF32 py = params->data.F32[5]*Y;
    1476     psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
    1477     psF32 t = 0.5*z*z*(1.0 + params->data.F32[8]*z/3.0);
    1478     psF32 r = 1.0 / (1.0 + z + params->data.F32[7]*t); /* exp (-Z) */
    1479     psF32 f = params->data.F32[1]*r + params->data.F32[0];
    1480 
    1481     //
    1482     // note difference from gaussian: q = params->data.F32[1]*r
    1483     //
    1484     psF32 q = params->data.F32[1]*r*r*(1.0 + params->data.F32[7]*z*(1.0 + params->data.F32[8]*z/2.0));
    1485     deriv->data.F32[0] = +1.0;
    1486     deriv->data.F32[1] = +r;
    1487     deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
    1488     deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X);
    1489     deriv->data.F32[4] = -2.0*q*px*X;
    1490     deriv->data.F32[5] = -2.0*q*py*Y;
    1491     deriv->data.F32[6] = -q*X*Y;
    1492     deriv->data.F32[7] = -100.0*params->data.F32[1]*r*r*t;
    1493     deriv->data.F32[8] = -100.0*params->data.F32[1]*r*r*params->data.F32[7]*(z*z*z)/6.0;
    1494     //
    1495     // The values of 100 dampen the swing of params->data.F32[7,8] */
    1496     //
    1497 
    1498     return(f);
    1499 }
    1500 
    1501 /******************************************************************************
    1502 p_pmMinLM_Wauss2D_Vec(*deriv, *params, *x): this function wraps the above
    1503 function in a form that is usable in the LM minimization routines.
    1504  *****************************************************************************/
    1505 psVector *p_pmMinLM_Wauss2D_Vec(psImage *deriv,
    1506                                 psVector *params,
    1507                                 psArray *x)
    1508 {
    1509     PS_IMAGE_CHECK_NULL(deriv, NULL);
    1510     PS_IMAGE_CHECK_EMPTY(deriv, NULL);
    1511     PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
    1512     PS_VECTOR_CHECK_NULL(params, NULL);
    1513     PS_VECTOR_CHECK_EMPTY(params, NULL);
    1514     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
    1515     PS_PTR_CHECK_NULL(x, NULL);
    1516     if (deriv->numRows != x->n) {
    1517         psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
    1518     }
    1519     psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
    1520     // XXX: use static memory here.
    1521     psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
    1522 
    1523     for (psS32 i = 0 ; i < x->n ; i++) {
    1524         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1525             tmpRow->data.F32[j] = deriv->data.F32[i][j];
    1526         }
    1527 
    1528         tmpVec->data.F32[i] = pmMinLM_Wauss2D(tmpRow,
    1529                                               params,
    1530                                               (psVector *) x->data[i]);
    1531 
    1532         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1533             deriv->data.F32[i][j] = tmpRow->data.F32[j];
    1534         }
    1535     }
    1536 
    1537     psFree(tmpRow);
    1538     return(tmpVec);
    1539 }
    1540 
    1541 
    1542 
    1543 
    1544 
    1545 
    1546 // XXX: What should these be?
    1547 #define FFACTOR 1.0
    1548 #define FSCALE 1.0
    1549 /******************************************************************************
    1550     params->data.F32[0] = So;
    1551     params->data.F32[1] = Zo;
    1552     params->data.F32[2] = Xo;
    1553     params->data.F32[3] = Yo;
    1554     params->data.F32[4] = SxInner;
    1555     params->data.F32[5] = SyInner;
    1556     params->data.F32[6] = SxyInner;
    1557     params->data.F32[7] = SxOuter;
    1558     params->data.F32[8] = SyOuter;
    1559     params->data.F32[9] = SxyOuter;
    1560     params->data.F32[10] = N;
    1561  *****************************************************************************/
    1562 psF32 pmMinLM_TwistGauss2D(psVector *deriv,
     1543      {
     1544          PS_IMAGE_CHECK_NULL(deriv, NULL);
     1545          PS_IMAGE_CHECK_EMPTY(deriv, NULL);
     1546          PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
     1547          PS_VECTOR_CHECK_NULL(params, NULL);
     1548          PS_VECTOR_CHECK_EMPTY(params, NULL);
     1549          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
     1550          PS_PTR_CHECK_NULL(x, NULL);
     1551          if (deriv->numRows != x->n) {
     1552              psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
     1553          }
     1554          psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
     1555          // XXX: use static memory here.
     1556          psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
     1557
     1558          for (psS32 i = 0 ; i < x->n ; i++) {
     1559              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1560                  tmpRow->data.F32[j] = deriv->data.F32[i][j];
     1561              }
     1562
     1563              tmpVec->data.F32[i] = pmMinLM_Gauss2D(tmpRow,
     1564                                                    params,
     1565                                                    (psVector *) x->data[i]);
     1566
     1567              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1568                  deriv->data.F32[i][j] = tmpRow->data.F32[j];
     1569              }
     1570          }
     1571
     1572          psFree(tmpRow);
     1573          return(tmpVec);
     1574      }
     1575
     1576
     1577      /******************************************************************************
     1578          params->data.F32[0] = So;
     1579          params->data.F32[1] = Zo;
     1580          params->data.F32[2] = Xo;
     1581          params->data.F32[3] = Yo;
     1582          params->data.F32[4] = sqrt(2) / SigmaX;
     1583          params->data.F32[5] = sqrt(2) / SigmaY;
     1584          params->data.F32[6] = Sxy;
     1585       *****************************************************************************/
     1586      psF32 pmMinLM_PsuedoGauss2D(psVector *deriv,
     1587                                  psVector *params,
     1588                                  psVector *x)
     1589      {
     1590          PS_VECTOR_CHECK_NULL(deriv, NAN);
     1591          PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
     1592          PS_VECTOR_CHECK_SIZE(deriv, 7, NAN);
     1593          PS_VECTOR_CHECK_NULL(params, NAN);
     1594          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
     1595          PS_VECTOR_CHECK_SIZE(params, 7, NAN);
     1596          PS_VECTOR_CHECK_NULL(x, NAN);
     1597          PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
     1598          PS_VECTOR_CHECK_SIZE(x, 2, NAN);
     1599
     1600          psF32 X = x->data.F32[0] - params->data.F32[2];
     1601          psF32 Y = x->data.F32[1] - params->data.F32[3];
     1602          psF32 px = params->data.F32[4]*X;
     1603          psF32 py = params->data.F32[5]*Y;
     1604          psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
     1605          psF32 t = 1 + z + 0.5*z*z;
     1606          psF32 r = 1.0 / (t*(1 + z/3)); /* exp (-Z) */
     1607          psF32 f = params->data.F32[1]*r + params->data.F32[0];
     1608
     1609          //
     1610          // note difference from a pure gaussian: q = params->data.F32[1]*r
     1611          //
     1612
     1613          psF32 q = params->data.F32[1]*r*r*t;
     1614          deriv->data.F32[0] = +1.0;
     1615          deriv->data.F32[1] = +r;
     1616          deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
     1617          deriv->data.F32[3] = q *
     1618                               (2.0*py*params->data.F32[5] + params->data.F32[6]*X);
     1619          deriv->data.F32[4] = -2.0*q*px*X;
     1620          deriv->data.F32[5] = -2.0*q*py*Y;
     1621          deriv->data.F32[6] = -q*X*Y;
     1622
     1623          return(f);
     1624      }
     1625
     1626      /******************************************************************************
     1627      p_pmMinLM_PsuedoGauss2D_Vec(*deriv, *params, *x): this function wraps the
     1628      above function in a form that is usable in the LM minimization routines.
     1629       *****************************************************************************/
     1630      psVector *p_pmMinLM_PsuedoGauss2D_Vec(psImage *deriv,
     1631                                            psVector *params,
     1632                                            psArray *x)
     1633      {
     1634          PS_IMAGE_CHECK_NULL(deriv, NULL);
     1635          PS_IMAGE_CHECK_EMPTY(deriv, NULL);
     1636          PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
     1637          PS_VECTOR_CHECK_NULL(params, NULL);
     1638          PS_VECTOR_CHECK_EMPTY(params, NULL);
     1639          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
     1640          PS_PTR_CHECK_NULL(x, NULL);
     1641          if (deriv->numRows != x->n) {
     1642              psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
     1643          }
     1644          psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
     1645          // XXX: use static memory here.
     1646          psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
     1647
     1648          for (psS32 i = 0 ; i < x->n ; i++) {
     1649              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1650                  tmpRow->data.F32[j] = deriv->data.F32[i][j];
     1651              }
     1652
     1653              tmpVec->data.F32[i] = pmMinLM_PsuedoGauss2D(tmpRow,
     1654                                    params,
     1655                                    (psVector *) x->data[i]);
     1656
     1657              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1658                  deriv->data.F32[i][j] = tmpRow->data.F32[j];
     1659              }
     1660          }
     1661
     1662          psFree(tmpRow);
     1663          return(tmpVec);
     1664      }
     1665
     1666
     1667
     1668
     1669      /******************************************************************************
     1670          params->data.F32[0] = So;
     1671          params->data.F32[1] = Zo;
     1672          params->data.F32[2] = Xo;
     1673          params->data.F32[3] = Yo;
     1674          params->data.F32[4] = Sx;
     1675          params->data.F32[5] = Sy;
     1676          params->data.F32[6] = Sxy;
     1677          params->data.F32[7] = B2;
     1678          params->data.F32[8] = B3;
     1679       *****************************************************************************/
     1680      psF32 pmMinLM_Wauss2D(psVector *deriv,
     1681                            psVector *params,
     1682                            psVector *x)
     1683      {
     1684          PS_VECTOR_CHECK_NULL(deriv, NAN);
     1685          PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
     1686          PS_VECTOR_CHECK_SIZE(deriv, 9, NAN);
     1687          PS_VECTOR_CHECK_NULL(params, NAN);
     1688          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
     1689          PS_VECTOR_CHECK_SIZE(params, 9, NAN);
     1690          PS_VECTOR_CHECK_NULL(x, NAN);
     1691          PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
     1692          PS_VECTOR_CHECK_SIZE(x, 2, NAN);
     1693
     1694          psF32 X = x->data.F32[0] - params->data.F32[2];
     1695          psF32 Y = x->data.F32[1] - params->data.F32[2];
     1696          psF32 px = params->data.F32[4]*X;
     1697          psF32 py = params->data.F32[5]*Y;
     1698          psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
     1699          psF32 t = 0.5*z*z*(1.0 + params->data.F32[8]*z/3.0);
     1700          psF32 r = 1.0 / (1.0 + z + params->data.F32[7]*t); /* exp (-Z) */
     1701          psF32 f = params->data.F32[1]*r + params->data.F32[0];
     1702
     1703          //
     1704          // note difference from gaussian: q = params->data.F32[1]*r
     1705          //
     1706          psF32 q = params->data.F32[1]*r*r*(1.0 + params->data.F32[7]*z*(1.0 + params->data.F32[8]*z/2.0));
     1707          deriv->data.F32[0] = +1.0;
     1708          deriv->data.F32[1] = +r;
     1709          deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
     1710          deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X);
     1711          deriv->data.F32[4] = -2.0*q*px*X;
     1712          deriv->data.F32[5] = -2.0*q*py*Y;
     1713          deriv->data.F32[6] = -q*X*Y;
     1714          deriv->data.F32[7] = -100.0*params->data.F32[1]*r*r*t;
     1715          deriv->data.F32[8] = -100.0*params->data.F32[1]*r*r*params->data.F32[7]*(z*z*z)/6.0;
     1716          //
     1717          // The values of 100 dampen the swing of params->data.F32[7,8] */
     1718          //
     1719
     1720          return(f);
     1721      }
     1722
     1723      /******************************************************************************
     1724      p_pmMinLM_Wauss2D_Vec(*deriv, *params, *x): this function wraps the above
     1725      function in a form that is usable in the LM minimization routines.
     1726       *****************************************************************************/
     1727      psVector *p_pmMinLM_Wauss2D_Vec(psImage *deriv,
     1728                                      psVector *params,
     1729                                      psArray *x)
     1730      {
     1731          PS_IMAGE_CHECK_NULL(deriv, NULL);
     1732          PS_IMAGE_CHECK_EMPTY(deriv, NULL);
     1733          PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
     1734          PS_VECTOR_CHECK_NULL(params, NULL);
     1735          PS_VECTOR_CHECK_EMPTY(params, NULL);
     1736          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
     1737          PS_PTR_CHECK_NULL(x, NULL);
     1738          if (deriv->numRows != x->n) {
     1739              psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
     1740          }
     1741          psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
     1742          // XXX: use static memory here.
     1743          psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
     1744
     1745          for (psS32 i = 0 ; i < x->n ; i++) {
     1746              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1747                  tmpRow->data.F32[j] = deriv->data.F32[i][j];
     1748              }
     1749
     1750              tmpVec->data.F32[i] = pmMinLM_Wauss2D(tmpRow,
     1751                                                    params,
     1752                                                    (psVector *) x->data[i]);
     1753
     1754              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1755                  deriv->data.F32[i][j] = tmpRow->data.F32[j];
     1756              }
     1757          }
     1758
     1759          psFree(tmpRow);
     1760          return(tmpVec);
     1761      }
     1762
     1763
     1764
     1765
     1766
     1767
     1768      // XXX: What should these be?
     1769      #define FFACTOR 1.0
     1770      #define FSCALE 1.0
     1771      /******************************************************************************
     1772          params->data.F32[0] = So;
     1773          params->data.F32[1] = Zo;
     1774          params->data.F32[2] = Xo;
     1775          params->data.F32[3] = Yo;
     1776          params->data.F32[4] = SxInner;
     1777          params->data.F32[5] = SyInner;
     1778          params->data.F32[6] = SxyInner;
     1779          params->data.F32[7] = SxOuter;
     1780          params->data.F32[8] = SyOuter;
     1781          params->data.F32[9] = SxyOuter;
     1782          params->data.F32[10] = N;
     1783       *****************************************************************************/
     1784      psF32 pmMinLM_TwistGauss2D(psVector *deriv,
     1785                                 psVector *params,
     1786                                 psVector *x)
     1787      {
     1788          PS_VECTOR_CHECK_NULL(deriv, NAN);
     1789          PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
     1790          PS_VECTOR_CHECK_SIZE(deriv, 11, NAN);
     1791          PS_VECTOR_CHECK_NULL(params, NAN);
     1792          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
     1793          PS_VECTOR_CHECK_SIZE(params, 11, NAN);
     1794          PS_VECTOR_CHECK_NULL(x, NAN);
     1795          PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
     1796          PS_VECTOR_CHECK_SIZE(x, 2, NAN);
     1797
     1798          psF32 X = x->data.F32[0] - params->data.F32[2];
     1799          psF32 Y = x->data.F32[1] - params->data.F32[3];
     1800          psF32 px1 = params->data.F32[4]*X;
     1801          psF32 py1 = params->data.F32[5]*Y;
     1802          psF32 px2 = params->data.F32[7]*X;
     1803          psF32 py2 = params->data.F32[8]*Y;
     1804          psF32 z1 = 0.5*PS_SQR(px1) + 0.5*PS_SQR(py1) + params->data.F32[4]*X*Y;
     1805          psF32 z2 = 0.5*PS_SQR(px2) + 0.5*PS_SQR(py2) + params->data.F32[9]*X*Y;
     1806          psF32 r = 1.0 / (1.0 + z1 + pow(z2,params->data.F32[10]));
     1807
     1808
     1809          psF32 f = params->data.F32[5]*r + params->data.F32[6];
     1810          psF32 q1 = params->data.F32[5]*PS_SQR(r);
     1811          psF32 q2 = params->data.F32[5]*PS_SQR(r)*params->data.F32[10]*pow(z2,(params->data.F32[10]-1.0));
     1812          deriv->data.F32[0] = +1.0;
     1813          deriv->data.F32[1] = +r;
     1814          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);
     1815          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);
     1816
     1817          //
     1818          // These fudge factors impede the growth of params->data.F32[4] beyond
     1819          // params->data.F32[7].
     1820          //
     1821          psF32 f1 = fabs(params->data.F32[7]) / fabs(params->data.F32[4]);
     1822          psF32 f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
     1823          deriv->data.F32[4] = -2.0*q1*px1*X*f2;
     1824
     1825          //
     1826          // These fudge factors impede the growth of params->data.F32[5] beyond
     1827          // params->data.F32[8].
     1828          //
     1829          f1 = fabs(params->data.F32[8]) / fabs(params->data.F32[5]);
     1830          f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
     1831          deriv->data.F32[5] = -2.0*q1*py1*Y*f2;
     1832          deriv->data.F32[6] = -q1*X*Y;
     1833          deriv->data.F32[7] = -2.0*q2*px2*X;
     1834          deriv->data.F32[8] = -2.0*q2*py2*Y;
     1835          deriv->data.F32[9] = -q2*X*Y;
     1836          deriv->data.F32[10] = -q1*log(z2);
     1837
     1838          return(f);
     1839      }
     1840
     1841      /******************************************************************************
     1842      p_pmMinLM_TwistGauss2D_Vec(*deriv, *params, *x): this function wraps the above
     1843      function in a form that is usable in the LM minimization routines.
     1844       *****************************************************************************/
     1845      psVector *p_pmMinLM_TwistGauss2D_Vec(psImage *deriv,
     1846                                           psVector *params,
     1847                                           psArray *x)
     1848      {
     1849          PS_IMAGE_CHECK_NULL(deriv, NULL);
     1850          PS_IMAGE_CHECK_EMPTY(deriv, NULL);
     1851          PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
     1852          PS_VECTOR_CHECK_NULL(params, NULL);
     1853          PS_VECTOR_CHECK_EMPTY(params, NULL);
     1854          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
     1855          PS_PTR_CHECK_NULL(x, NULL);
     1856          if (deriv->numRows != x->n) {
     1857              psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
     1858          }
     1859          psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
     1860          // XXX: use static memory here.
     1861          psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
     1862
     1863          for (psS32 i = 0 ; i < x->n ; i++) {
     1864              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1865                  tmpRow->data.F32[j] = deriv->data.F32[i][j];
     1866              }
     1867
     1868              tmpVec->data.F32[i] = pmMinLM_TwistGauss2D(tmpRow,
     1869                                    params,
     1870                                    (psVector *) x->data[i]);
     1871
     1872              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1873                  deriv->data.F32[i][j] = tmpRow->data.F32[j];
     1874              }
     1875          }
     1876
     1877          psFree(tmpRow);
     1878          return(tmpVec);
     1879      }
     1880
     1881
     1882
     1883      /******************************************************************************
     1884          float Sersic()
     1885          params->data.F32[0] = So;
     1886          params->data.F32[1] = Zo;
     1887          params->data.F32[2] = Xo;
     1888          params->data.F32[3] = Yo;
     1889          params->data.F32[4] = Sx;
     1890          params->data.F32[5] = Sy;
     1891          params->data.F32[6] = Sxy;
     1892          params->data.F32[7] = Nexp;
     1893       *****************************************************************************/
     1894      psF32 pmMinLM_Sersic(psVector *deriv,
    15631895                           psVector *params,
    15641896                           psVector *x)
    1565 {
    1566     PS_VECTOR_CHECK_NULL(deriv, NAN);
    1567     PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
    1568     PS_VECTOR_CHECK_SIZE(deriv, 11, NAN);
    1569     PS_VECTOR_CHECK_NULL(params, NAN);
    1570     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
    1571     PS_VECTOR_CHECK_SIZE(params, 11, NAN);
    1572     PS_VECTOR_CHECK_NULL(x, NAN);
    1573     PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
    1574     PS_VECTOR_CHECK_SIZE(x, 2, NAN);
    1575 
    1576     psF32 X = x->data.F32[0] - params->data.F32[2];
    1577     psF32 Y = x->data.F32[1] - params->data.F32[3];
    1578     psF32 px1 = params->data.F32[4]*X;
    1579     psF32 py1 = params->data.F32[5]*Y;
    1580     psF32 px2 = params->data.F32[7]*X;
    1581     psF32 py2 = params->data.F32[8]*Y;
    1582     psF32 z1 = 0.5*PS_SQR(px1) + 0.5*PS_SQR(py1) + params->data.F32[4]*X*Y;
    1583     psF32 z2 = 0.5*PS_SQR(px2) + 0.5*PS_SQR(py2) + params->data.F32[9]*X*Y;
    1584     psF32 r = 1.0 / (1.0 + z1 + pow(z2,params->data.F32[10]));
    1585 
    1586 
    1587     psF32 f = params->data.F32[5]*r + params->data.F32[6];
    1588     psF32 q1 = params->data.F32[5]*PS_SQR(r);
    1589     psF32 q2 = params->data.F32[5]*PS_SQR(r)*params->data.F32[10]*pow(z2,(params->data.F32[10]-1.0));
    1590     deriv->data.F32[0] = +1.0;
    1591     deriv->data.F32[1] = +r;
    1592     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);
    1593     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);
    1594 
    1595     //
    1596     // These fudge factors impede the growth of params->data.F32[4] beyond
    1597     // params->data.F32[7].
    1598     //
    1599     psF32 f1 = fabs(params->data.F32[7]) / fabs(params->data.F32[4]);
    1600     psF32 f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
    1601     deriv->data.F32[4] = -2.0*q1*px1*X*f2;
    1602 
    1603     //
    1604     // These fudge factors impede the growth of params->data.F32[5] beyond
    1605     // params->data.F32[8].
    1606     //
    1607     f1 = fabs(params->data.F32[8]) / fabs(params->data.F32[5]);
    1608     f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
    1609     deriv->data.F32[5] = -2.0*q1*py1*Y*f2;
    1610     deriv->data.F32[6] = -q1*X*Y;
    1611     deriv->data.F32[7] = -2.0*q2*px2*X;
    1612     deriv->data.F32[8] = -2.0*q2*py2*Y;
    1613     deriv->data.F32[9] = -q2*X*Y;
    1614     deriv->data.F32[10] = -q1*log(z2);
    1615 
    1616     return(f);
    1617 }
    1618 
    1619 /******************************************************************************
    1620 p_pmMinLM_TwistGauss2D_Vec(*deriv, *params, *x): this function wraps the above
    1621 function in a form that is usable in the LM minimization routines.
    1622  *****************************************************************************/
    1623 psVector *p_pmMinLM_TwistGauss2D_Vec(psImage *deriv,
     1897      {
     1898          PS_VECTOR_CHECK_NULL(deriv, NAN);
     1899          PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
     1900          PS_VECTOR_CHECK_SIZE(deriv, 8, NAN);
     1901          PS_VECTOR_CHECK_NULL(params, NAN);
     1902          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
     1903          PS_VECTOR_CHECK_SIZE(params, 8, NAN);
     1904          PS_VECTOR_CHECK_NULL(x, NAN);
     1905          PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
     1906          PS_VECTOR_CHECK_SIZE(x, 2, NAN);
     1907
     1908          psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
     1909          return(0.0);
     1910      }
     1911      /******************************************************************************
     1912      p_pmMinLM_Sersic_Vec(*deriv, *params, *x): this function wraps the above
     1913      function in a form that is usable in the LM minimization routines.
     1914       *****************************************************************************/
     1915      psVector *p_pmMinLM_Sersic_Vec(psImage *deriv,
    16241916                                     psVector *params,
    16251917                                     psArray *x)
    1626 {
    1627     PS_IMAGE_CHECK_NULL(deriv, NULL);
    1628     PS_IMAGE_CHECK_EMPTY(deriv, NULL);
    1629     PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
    1630     PS_VECTOR_CHECK_NULL(params, NULL);
    1631     PS_VECTOR_CHECK_EMPTY(params, NULL);
    1632     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
    1633     PS_PTR_CHECK_NULL(x, NULL);
    1634     if (deriv->numRows != x->n) {
    1635         psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
    1636     }
    1637     psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
    1638     // XXX: use static memory here.
    1639     psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
    1640 
    1641     for (psS32 i = 0 ; i < x->n ; i++) {
    1642         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1643             tmpRow->data.F32[j] = deriv->data.F32[i][j];
    1644         }
    1645 
    1646         tmpVec->data.F32[i] = pmMinLM_TwistGauss2D(tmpRow,
    1647                               params,
    1648                               (psVector *) x->data[i]);
    1649 
    1650         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1651             deriv->data.F32[i][j] = tmpRow->data.F32[j];
    1652         }
    1653     }
    1654 
    1655     psFree(tmpRow);
    1656     return(tmpVec);
    1657 }
    1658 
    1659 
    1660 
    1661 /******************************************************************************
    1662     float Sersic()
    1663     params->data.F32[0] = So;
    1664     params->data.F32[1] = Zo;
    1665     params->data.F32[2] = Xo;
    1666     params->data.F32[3] = Yo;
    1667     params->data.F32[4] = Sx;
    1668     params->data.F32[5] = Sy;
    1669     params->data.F32[6] = Sxy;
    1670     params->data.F32[7] = Nexp;
    1671  *****************************************************************************/
    1672 psF32 pmMinLM_Sersic(psVector *deriv,
    1673                      psVector *params,
    1674                      psVector *x)
    1675 {
    1676     PS_VECTOR_CHECK_NULL(deriv, NAN);
    1677     PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
    1678     PS_VECTOR_CHECK_SIZE(deriv, 8, NAN);
    1679     PS_VECTOR_CHECK_NULL(params, NAN);
    1680     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
    1681     PS_VECTOR_CHECK_SIZE(params, 8, NAN);
    1682     PS_VECTOR_CHECK_NULL(x, NAN);
    1683     PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
    1684     PS_VECTOR_CHECK_SIZE(x, 2, NAN);
    1685 
    1686     psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
    1687     return(0.0);
    1688 }
    1689 /******************************************************************************
    1690 p_pmMinLM_Sersic_Vec(*deriv, *params, *x): this function wraps the above
    1691 function in a form that is usable in the LM minimization routines.
    1692  *****************************************************************************/
    1693 psVector *p_pmMinLM_Sersic_Vec(psImage *deriv,
     1918      {
     1919          PS_IMAGE_CHECK_NULL(deriv, NULL);
     1920          PS_IMAGE_CHECK_EMPTY(deriv, NULL);
     1921          PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
     1922          PS_VECTOR_CHECK_NULL(params, NULL);
     1923          PS_VECTOR_CHECK_EMPTY(params, NULL);
     1924          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
     1925          PS_PTR_CHECK_NULL(x, NULL);
     1926          if (deriv->numRows != x->n) {
     1927              psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
     1928          }
     1929          psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
     1930          // XXX: use static memory here.
     1931          psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
     1932
     1933          for (psS32 i = 0 ; i < x->n ; i++) {
     1934              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1935                  tmpRow->data.F32[j] = deriv->data.F32[i][j];
     1936              }
     1937
     1938              tmpVec->data.F32[i] = pmMinLM_Sersic(tmpRow,
     1939                                                   params,
     1940                                                   (psVector *) x->data[i]);
     1941
     1942              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     1943                  deriv->data.F32[i][j] = tmpRow->data.F32[j];
     1944              }
     1945          }
     1946
     1947          psFree(tmpRow);
     1948          return(tmpVec);
     1949      }
     1950
     1951      /******************************************************************************
     1952          float SersicBulge()
     1953          params->data.F32[0] So;
     1954          params->data.F32[1] Zo;
     1955          params->data.F32[2] Xo;
     1956          params->data.F32[3] Yo;
     1957          params->data.F32[4] SxInner;
     1958          params->data.F32[5] SyInner;
     1959          params->data.F32[6] SxyInner;
     1960          params->data.F32[7] Zd;
     1961          params->data.F32[8] SxOuter;
     1962          params->data.F32[9] SyOuter;
     1963          params->data.F32[10] = SxyOuter;
     1964          params->data.F32[11] = Nexp;
     1965       *****************************************************************************/
     1966      psF32 pmMinLM_SersicCore(psVector *deriv,
    16941967                               psVector *params,
    1695                                psArray *x)
    1696 {
    1697     PS_IMAGE_CHECK_NULL(deriv, NULL);
    1698     PS_IMAGE_CHECK_EMPTY(deriv, NULL);
    1699     PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
    1700     PS_VECTOR_CHECK_NULL(params, NULL);
    1701     PS_VECTOR_CHECK_EMPTY(params, NULL);
    1702     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
    1703     PS_PTR_CHECK_NULL(x, NULL);
    1704     if (deriv->numRows != x->n) {
    1705         psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
    1706     }
    1707     psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
    1708     // XXX: use static memory here.
    1709     psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
    1710 
    1711     for (psS32 i = 0 ; i < x->n ; i++) {
    1712         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1713             tmpRow->data.F32[j] = deriv->data.F32[i][j];
    1714         }
    1715 
    1716         tmpVec->data.F32[i] = pmMinLM_Sersic(tmpRow,
    1717                                              params,
    1718                                              (psVector *) x->data[i]);
    1719 
    1720         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1721             deriv->data.F32[i][j] = tmpRow->data.F32[j];
    1722         }
    1723     }
    1724 
    1725     psFree(tmpRow);
    1726     return(tmpVec);
    1727 }
    1728 
    1729 /******************************************************************************
    1730     float SersicBulge()
    1731     params->data.F32[0] So;
    1732     params->data.F32[1] Zo;
    1733     params->data.F32[2] Xo;
    1734     params->data.F32[3] Yo;
    1735     params->data.F32[4] SxInner;
    1736     params->data.F32[5] SyInner;
    1737     params->data.F32[6] SxyInner;
    1738     params->data.F32[7] Zd;
    1739     params->data.F32[8] SxOuter;
    1740     params->data.F32[9] SyOuter;
    1741     params->data.F32[10] = SxyOuter;
    1742     params->data.F32[11] = Nexp;
    1743  *****************************************************************************/
    1744 psF32 pmMinLM_SersicCore(psVector *deriv,
    1745                          psVector *params,
    1746                          psVector *x)
    1747 {
    1748     PS_VECTOR_CHECK_NULL(deriv, NAN);
    1749     PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
    1750     PS_VECTOR_CHECK_SIZE(deriv, 12, NAN);
    1751     PS_VECTOR_CHECK_NULL(params, NAN);
    1752     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
    1753     PS_VECTOR_CHECK_SIZE(params, 12, NAN);
    1754     PS_VECTOR_CHECK_NULL(x, NAN);
    1755     PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
    1756     PS_VECTOR_CHECK_SIZE(x, 2, NAN);
    1757 
    1758     psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
    1759     return(0.0);
    1760 }
    1761 /******************************************************************************
    1762 p_pmMinLM_SersicCore_Vec(*deriv, *params, *x): this function wraps the above
    1763 function in a form that is usable in the LM minimization routines.
    1764  *****************************************************************************/
    1765 psVector *p_pmMinLM_SersicCore_Vec(psImage *deriv,
    1766                                    psVector *params,
    1767                                    psArray *x)
    1768 {
    1769     PS_IMAGE_CHECK_NULL(deriv, NULL);
    1770     PS_IMAGE_CHECK_EMPTY(deriv, NULL);
    1771     PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
    1772     PS_VECTOR_CHECK_NULL(params, NULL);
    1773     PS_VECTOR_CHECK_EMPTY(params, NULL);
    1774     PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
    1775     PS_PTR_CHECK_NULL(x, NULL);
    1776     if (deriv->numRows != x->n) {
    1777         psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
    1778     }
    1779     psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
    1780     // XXX: use static memory here.
    1781     psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
    1782 
    1783     for (psS32 i = 0 ; i < x->n ; i++) {
    1784         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1785             tmpRow->data.F32[j] = deriv->data.F32[i][j];
    1786         }
    1787 
    1788         tmpVec->data.F32[i] = pmMinLM_SersicCore(tmpRow,
    1789                               params,
    1790                               (psVector *) x->data[i]);
    1791 
    1792         for (psS32 j = 0 ; j < tmpRow->n ; j++) {
    1793             deriv->data.F32[i][j] = tmpRow->data.F32[j];
    1794         }
    1795     }
    1796 
    1797     psFree(tmpRow);
    1798     return(tmpVec);
    1799 }
    1800 
    1801 
    1802 
    1803 /******************************************************************************
    1804  *****************************************************************************/
    1805 psF32 pmMinLM_PsuedoSersic(psVector *deriv,
    1806                            psVector *params,
    1807                            psVector *x)
    1808 {
    1809     return(0.0);
    1810 }
     1968                               psVector *x)
     1969      {
     1970          PS_VECTOR_CHECK_NULL(deriv, NAN);
     1971          PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
     1972          PS_VECTOR_CHECK_SIZE(deriv, 12, NAN);
     1973          PS_VECTOR_CHECK_NULL(params, NAN);
     1974          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
     1975          PS_VECTOR_CHECK_SIZE(params, 12, NAN);
     1976          PS_VECTOR_CHECK_NULL(x, NAN);
     1977          PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
     1978          PS_VECTOR_CHECK_SIZE(x, 2, NAN);
     1979
     1980          psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
     1981          return(0.0);
     1982      }
     1983      /******************************************************************************
     1984      p_pmMinLM_SersicCore_Vec(*deriv, *params, *x): this function wraps the above
     1985      function in a form that is usable in the LM minimization routines.
     1986       *****************************************************************************/
     1987      psVector *p_pmMinLM_SersicCore_Vec(psImage *deriv,
     1988                                         psVector *params,
     1989                                         psArray *x)
     1990      {
     1991          PS_IMAGE_CHECK_NULL(deriv, NULL);
     1992          PS_IMAGE_CHECK_EMPTY(deriv, NULL);
     1993          PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
     1994          PS_VECTOR_CHECK_NULL(params, NULL);
     1995          PS_VECTOR_CHECK_EMPTY(params, NULL);
     1996          PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
     1997          PS_PTR_CHECK_NULL(x, NULL);
     1998          if (deriv->numRows != x->n) {
     1999              psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
     2000          }
     2001          psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
     2002          // XXX: use static memory here.
     2003          psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
     2004
     2005          for (psS32 i = 0 ; i < x->n ; i++) {
     2006              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     2007                  tmpRow->data.F32[j] = deriv->data.F32[i][j];
     2008              }
     2009
     2010              tmpVec->data.F32[i] = pmMinLM_SersicCore(tmpRow,
     2011                                    params,
     2012                                    (psVector *) x->data[i]);
     2013
     2014              for (psS32 j = 0 ; j < tmpRow->n ; j++) {
     2015                  deriv->data.F32[i][j] = tmpRow->data.F32[j];
     2016              }
     2017          }
     2018
     2019          psFree(tmpRow);
     2020          return(tmpVec);
     2021      }
     2022
     2023
     2024
     2025      /******************************************************************************
     2026       *****************************************************************************/
     2027      psF32 pmMinLM_PsuedoSersic(psVector *deriv,
     2028                                 psVector *params,
     2029                                 psVector *x)
     2030      {
     2031          return(0.0);
     2032      }
  • trunk/psModules/src/pmObjects.h

    r3498 r3510  
    55 *  @author GLG, MHPCC
    66 *
    7  *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
    8  *  @date $Date: 2005-03-24 22:36:52 $
     7 *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
     8 *  @date $Date: 2005-03-25 23:18:35 $
    99 *
    1010 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    6565} psModelType;
    6666
     67// XXX: It will be better if params, and dparams, were psVectors.
    6768typedef struct
    6869{
     
    173174/******************************************************************************
    174175 *****************************************************************************/
     176typedef enum {
     177    PS_CONTOUR_CRUDE,
     178} pmContourType;
     179
    175180psArray *pmSourceContour(psSource *source,
    176181                         const psImage *image,
    177182                         psF32 level,
    178                          psS32 mode);
     183                         pmContourType mode);
    179184
    180185/******************************************************************************
Note: See TracChangeset for help on using the changeset viewer.