IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Feb 10, 2010, 7:34:39 PM (16 years ago)
Author:
eugene
Message:

updates from eam_branches/20091201 (substantially changes to the kernel matching code; updates to pmDetection container, added pmPattern, etc)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/imcombine/pmSubtractionKernels.c

    r26156 r26893  
    1010#include "pmSubtraction.h"
    1111#include "pmSubtractionKernels.h"
     12#include "pmSubtractionHermitian.h"
     13#include "pmSubtractionDeconvolve.h"
     14#include "pmSubtractionVisual.h"
    1215
    1316#define RINGS_BUFFER 10                 // Buffer size for RINGS data
    14 
    1517
    1618// Free function for pmSubtractionKernels
     
    2729    psFree(kernels->solution1);
    2830    psFree(kernels->solution2);
     31    psFree(kernels->sampleStamps);
     32}
     33
     34// Free function for pmSubtractionPreCalcKernel
     35static void pmSubtractionKernelPreCalcFree(pmSubtractionKernelPreCalc *kernel)
     36{
     37    psFree(kernel->xKernel);
     38    psFree(kernel->yKernel);
     39    psFree(kernel->kernel);
     40
     41    psFree(kernel->uCoords);
     42    psFree(kernel->vCoords);
     43    psFree(kernel->poly);
    2944}
    3045
     
    4560
    4661// Generate 1D convolution kernel for ISIS
    47 static psVector *subtractionKernelISIS(float sigma, // Gaussian width
     62psVector *pmSubtractionKernelISIS(float sigma, // Gaussian width
    4863                                       int order, // Polynomial order
    4964                                       int size // Kernel half-size
     
    5772    for (int i = 0, x = -size; x <= size; i++, x++) {
    5873        kernel->data.F32[i] = norm * power(x, order) * expf(expNorm * PS_SQR(x));
     74    }
     75
     76    return kernel;
     77}
     78
     79// Generate 1D convolution kernel for HERM (normalized for 2D)
     80psVector *pmSubtractionKernelHERM(float sigma, // Gaussian width
     81                                       int order, // Polynomial order
     82                                       int size // Kernel half-size
     83    )
     84{
     85    int fullSize = 2 * size + 1;        // Full size of kernel
     86    psVector *kernel = psVectorAlloc(fullSize, PS_TYPE_F32); // Kernel to return
     87
     88    // for now, we are only allowing equal orders and sigmas in X and Y
     89    float nf = exp(lgamma(order + 1));
     90    float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI));
     91
     92    for (int i = 0, x = -size; x <= size; i++, x++) {
     93        float xf = x / sigma;
     94        float z = -0.25*xf*xf;
     95        kernel->data.F32[i] = norm * p_pmSubtractionHermitianPolynomial(xf, order) * exp(z);
     96    }
     97
     98    return kernel;
     99}
     100
     101// Generate 1D convolution kernel for HERM (normalized for 2D)
     102psKernel *pmSubtractionKernelHERM_RADIAL(float sigma, // Gaussian width
     103                                         int order, // Polynomial order
     104                                         int size // Kernel half-size
     105    )
     106{
     107    psKernel *kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel
     108
     109    // for now, we are only allowing equal orders and sigmas in X and Y
     110    float nf = exp(lgamma(order + 1));
     111    float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI));
     112
     113    // generate 2D radial hermitian
     114    for (int v = -size; v <= size; v++) {
     115        for (int u = -size; u <= size; u++) {
     116            float r = hypot(u, v) / sigma;
     117            float z = -0.25*r*r;
     118            kernel->kernel[v][u] = norm * p_pmSubtractionHermitianPolynomial(r, order) * exp(z);
     119        }
    59120    }
    60121
     
    96157            kernels->preCalc->data[index] = NULL;
    97158            kernels->penalties->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v));
    98 
     159            psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty");
    99160            psTrace("psModules.imcombine", 7, "Kernel %d: %d %d\n", index, u, v);
    100161        }
     
    110171}
    111172
     173bool pmSubtractionKernelPreCalcNormalize(pmSubtractionKernels *kernels, pmSubtractionKernelPreCalc *preCalc,
     174                                         int index, int size, int uOrder, int vOrder, float fwhm,
     175                                         bool AlardLuptonStyle, bool forceZeroNull)
     176{
     177    // we have 4 cases here:
     178    // 1) for odd functions, normalize the kernel by the maximum swing / Npix
     179    // 2) for even functions, normalize the kernel to unity
     180    // 3) for alard-lupton style normalization, subtract 1 from the 0,0 pixel for all even functions
     181    // 4) for deconvolved hermitians, subtract 1 from the 0,0 pixel for the 0,0 function(s)
     182
     183    // Calculate moments
     184    double penalty = 0.0;                   // Moment, for penalty
     185    double sum = 0.0, sum2 = 0.0;           // Sum of kernel component
     186    float min = INFINITY, max = -INFINITY;  // Minimum and maximum kernel value
     187    for (int v = -size; v <= size; v++) {
     188        for (int u = -size; u <= size; u++) {
     189            double value = preCalc->kernel->kernel[v][u];
     190            double value2 = PS_SQR(value);
     191            sum += value;
     192            sum2 += value2;
     193            penalty += value2 * PS_SQR((PS_SQR(u) + PS_SQR(v)));
     194            min = PS_MIN(value, min);
     195            max = PS_MAX(value, max);
     196        }
     197    }
     198
     199#if 0
     200    fprintf(stderr, "%d raw: %lf, null: %f, min: %lf, max: %lf, moment: %lf\n", index, sum, preCalc->kernel->kernel[0][0], min, max, penalty);
     201#endif
     202
     203    bool zeroNull = false;              // Zero out using the null position?
     204    float scale2D = NAN;                // Scaling for 2-D kernels
     205
     206    if (AlardLuptonStyle) {
     207        if (uOrder % 2 == 0 && vOrder % 2 == 0) {
     208            // Even functions: normalise to unit sum and subtract null pixel so that sum is zero
     209            scale2D = 1.0 / fabs(sum);
     210            zeroNull = true;
     211        } else {
     212            // Odd functions: choose normalisation so that parameters have about the same strength as for even
     213            // functions, no subtraction of null pixel because the sum is already (near) zero
     214            scale2D = 1.0 / sqrt(sum2);
     215            zeroNull = false;
     216        }
     217    }
     218
     219    if (!AlardLuptonStyle && (uOrder == 0 && vOrder == 0)) {
     220        zeroNull = true;
     221    }
     222    if (forceZeroNull) {
     223        // Force rescaling and subtraction of null pixel even though the order doesn't indicate it's even
     224        scale2D = 1.0 / fabs(sum);
     225        zeroNull = true;
     226    }
     227    if (!forceZeroNull && ((uOrder % 2) || (vOrder % 2))) {
     228        // Odd function
     229        scale2D = 1.0 / sqrt(sum2);
     230    }
     231
     232    float scale1D = sqrtf(scale2D);     // Scaling for 1-D kernels
     233    if (preCalc->xKernel) {
     234        psBinaryOp(preCalc->xKernel, preCalc->xKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32));
     235    }
     236    if (preCalc->yKernel) {
     237        psBinaryOp(preCalc->yKernel, preCalc->yKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32));
     238    }
     239
     240    psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "*", psScalarAlloc(scale2D, PS_TYPE_F32));
     241    penalty *= 1.0 / sum2;
     242
     243    if (zeroNull) {
     244        preCalc->kernel->kernel[0][0] -= 1.0;
     245    }
     246
     247#if 0
     248    {
     249        double sum = 0.0;   // Sum of kernel component
     250        float min = INFINITY, max = -INFINITY;  // Minimum and maximum kernel value
     251        for (int v = -size; v <= size; v++) {
     252            for (int u = -size; u <= size; u++) {
     253                sum += preCalc->kernel->kernel[v][u];
     254                min = PS_MIN(preCalc->kernel->kernel[v][u], min);
     255                max = PS_MAX(preCalc->kernel->kernel[v][u], max);
     256            }
     257        }
     258        fprintf(stderr, "%d mod: %lf, null: %f, min: %lf, max: %lf, scale: %f\n", index, sum, preCalc->kernel->kernel[0][0], min, max, scale2D);
     259    }
     260#endif
     261
     262    kernels->widths->data.F32[index] = fwhm;
     263    kernels->u->data.S32[index] = uOrder;
     264    kernels->v->data.S32[index] = vOrder;
     265    if (kernels->preCalc->data[index]) {
     266        psFree(kernels->preCalc->data[index]);
     267    }
     268    kernels->preCalc->data[index] = preCalc;
     269    kernels->penalties->data.F32[index] = kernels->penalty * penalty;
     270    psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty");
     271    psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index, fwhm, uOrder, vOrder, penalty);
     272
     273    return true;
     274}
     275
    112276pmSubtractionKernels *p_pmSubtractionKernelsRawISIS(int size, int spatialOrder,
    113                                                     const psVector *fwhms, const psVector *orders,
    114                                                     float penalty, pmSubtractionMode mode)
    115 {
    116     PS_ASSERT_VECTOR_NON_NULL(fwhms, NULL);
    117     PS_ASSERT_VECTOR_TYPE(fwhms, PS_TYPE_F32, NULL);
    118     PS_ASSERT_VECTOR_NON_NULL(orders, NULL);
    119     PS_ASSERT_VECTOR_TYPE(orders, PS_TYPE_S32, NULL);
    120     PS_ASSERT_VECTORS_SIZE_EQUAL(fwhms, orders, NULL);
     277                                                    const psVector *fwhmsIN, const psVector *ordersIN,
     278                                                    float penalty, psRegion bounds, pmSubtractionMode mode)
     279{
     280    PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL);
     281    PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL);
     282    PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL);
     283    PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL);
     284    PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL);
    121285    PS_ASSERT_INT_POSITIVE(size, NULL);
    122286    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     287
     288    // check the requested fwhm values: any values <= 0.0 should be dropped
     289    psVector *fwhms  = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32);
     290    psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32);
     291    for (int i = 0; i < fwhmsIN->n; i++) {
     292        if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue;
     293        psVectorAppend(fwhms, fwhmsIN->data.F32[i]);
     294        psVectorAppend(orders, ordersIN->data.S32[i]);
     295    }
    123296
    124297    int numGaussians = fwhms->n;       // Number of Gaussians
     
    133306
    134307    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size,
    135                                                               spatialOrder, penalty, mode); // The kernels
     308                                                              spatialOrder, penalty, bounds, mode); // Kernels
    136309    psStringAppend(&kernels->description, "ISIS(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
    137310
     
    141314
    142315    // Set the kernel parameters
    143     int fullSize = 2 * size + 1;        // Full size of kernels
    144316    for (int i = 0, index = 0; i < numGaussians; i++) {
    145317        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     
    147319        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
    148320            for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
    149                 psArray *preCalc = psArrayAlloc(3); // Array to hold precalculated values
    150                 psVector *xKernel = preCalc->data[0] = subtractionKernelISIS(sigma, uOrder, size); // x Kernel
    151                 psVector *yKernel = preCalc->data[1] = subtractionKernelISIS(sigma, vOrder, size); // y Kernel
    152                 psKernel *kernel = preCalc->data[2] = psKernelAlloc(-size, size, -size, size);      // Kernel
    153 
    154                 // Calculate moments
    155                 double moment = 0.0;    // Moment, for penalty
    156                 for (int v = -size, y = 0; v <= size; v++, y++) {
    157                     for (int u = -size, x = 0; u <= size; u++, x++) {
    158                         double value = xKernel->data.F32[x] * yKernel->data.F32[y]; // Value of kernel
    159                         kernel->kernel[v][u] = value;
    160                         moment += value * PS_SQR((PS_SQR(u) + PS_SQR(v)));
    161                     }
     321
     322                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values
     323                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
     324                // pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], false, false);
     325            }
     326        }
     327    }
     328
     329    return kernels;
     330}
     331
     332pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, int spatialOrder,
     333                                                      const psVector *fwhmsIN, const psVector *ordersIN,
     334                                                      float penalty, psRegion bounds, pmSubtractionMode mode)
     335{
     336    PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL);
     337    PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL);
     338    PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL);
     339    PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL);
     340    PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL);
     341    PS_ASSERT_INT_POSITIVE(size, NULL);
     342    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     343
     344    // check the requested fwhm values: any values <= 0.0 should be dropped
     345    psVector *fwhms  = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32);
     346    psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32);
     347    for (int i = 0; i < fwhmsIN->n; i++) {
     348        if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue;
     349        psVectorAppend(fwhms, fwhmsIN->data.F32[i]);
     350        psVectorAppend(orders, ordersIN->data.S32[i]);
     351    }
     352
     353    int numGaussians = fwhms->n;       // Number of Gaussians
     354
     355    int num = 0;                        // Number of basis functions
     356    psString params = NULL;             // List of parameters
     357    for (int i = 0; i < numGaussians; i++) {
     358        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
     359        psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
     360        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
     361        num += (11 - gaussOrder - 1);   // include all higher order radial terms
     362    }
     363
     364    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size,
     365                                                              spatialOrder, penalty, bounds, mode); // Kernels
     366    psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
     367
     368    psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS_RADIAL kernel: %s,%d --> %d elements", params, spatialOrder, num);
     369    psFree(params);
     370
     371    // Set the kernel parameters
     372    for (int i = 0, index = 0; i < numGaussians; i++) {
     373        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     374        // Iterate over (u,v) order
     375        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
     376            for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
     377                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values
     378                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
     379            }
     380        }
     381        for (int order = orders->data.S32[i] + 1; order < 11; order ++, index ++) {
     382            // XXX modify size for hermitians to account for sqrt(2) in Hermitian definition (relative to ISIS Gaussian)
     383            pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS_RADIAL, order, order, size, sigma / sqrt(2.0)); // structure to hold precalculated values
     384            pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, order, order, fwhms->data.F32[i], true, true);
     385        }
     386    }
     387    return kernels;
     388}
     389
     390pmSubtractionKernels *pmSubtractionKernelsHERM(int size, int spatialOrder,
     391                                               const psVector *fwhmsIN, const psVector *ordersIN,
     392                                               float penalty, psRegion bounds, pmSubtractionMode mode)
     393{
     394    PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL);
     395    PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL);
     396    PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL);
     397    PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL);
     398    PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL);
     399    PS_ASSERT_INT_POSITIVE(size, NULL);
     400    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     401
     402    // check the requested fwhm values: any values <= 0.0 should be dropped
     403    psVector *fwhms  = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32);
     404    psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32);
     405    for (int i = 0; i < fwhmsIN->n; i++) {
     406        if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue;
     407        psVectorAppend(fwhms, fwhmsIN->data.F32[i]);
     408        psVectorAppend(orders, ordersIN->data.S32[i]);
     409    }
     410
     411    int numGaussians = fwhms->n;       // Number of Gaussians
     412
     413    int num = 0;                        // Number of basis functions
     414    psString params = NULL;             // List of parameters
     415    for (int i = 0; i < numGaussians; i++) {
     416        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
     417        psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
     418        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
     419    }
     420
     421    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size,
     422                                                              spatialOrder, penalty, bounds, mode); // Kernels
     423    psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
     424
     425    psLogMsg("psModules.imcombine", PS_LOG_INFO, "HERM kernel: %s,%d --> %d elements",
     426             params, spatialOrder, num);
     427    psFree(params);
     428
     429    // Set the kernel parameters
     430    for (int i = 0, index = 0; i < numGaussians; i++) {
     431        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     432        // Iterate over (u,v) order
     433        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
     434            for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
     435                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values
     436                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
     437            }
     438        }
     439    }
     440
     441    return kernels;
     442}
     443
     444pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, int spatialOrder,
     445                                                      const psVector *fwhmsIN, const psVector *ordersIN,
     446                                                      float penalty, psRegion bounds, pmSubtractionMode mode)
     447{
     448    PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL);
     449    PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL);
     450    PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL);
     451    PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL);
     452    PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL);
     453    PS_ASSERT_INT_POSITIVE(size, NULL);
     454    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     455
     456    // check the requested fwhm values: any values <= 0.0 should be dropped
     457    psVector *fwhms  = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32);
     458    psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32);
     459    for (int i = 0; i < fwhmsIN->n; i++) {
     460        if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue;
     461        psVectorAppend(fwhms, fwhmsIN->data.F32[i]);
     462        psVectorAppend(orders, ordersIN->data.S32[i]);
     463    }
     464
     465    int numGaussians = fwhms->n;       // Number of Gaussians
     466
     467    int num = 0;                        // Number of basis functions
     468    psString params = NULL;             // List of parameters
     469    for (int i = 0; i < numGaussians; i++) {
     470        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
     471        psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
     472        num += PS_SQR(gaussOrder + 1);
     473    }
     474
     475    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size,
     476                                                              spatialOrder, penalty, bounds, mode); // Kernels
     477    psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
     478
     479    psLogMsg("psModules.imcombine", PS_LOG_INFO, "DECONVOLVED HERM kernel: %s,%d --> %d elements", params, spatialOrder, num);
     480    psFree(params);
     481
     482    // XXXXX hard-wired reference sigma for now of 1.7 pix (== 4.0 pix fwhm == 1.0 arcsec in simtest)
     483    // generate the Gaussian deconvolution kernel
     484    # define DECONV_SIGMA 1.6
     485    psKernel *kernelGauss = pmSubtractionDeconvolveGauss (size, DECONV_SIGMA);
     486
     487# if 1
     488    psArray *deconKernels = psArrayAllocEmpty(100);
     489# endif
     490
     491    // Set the kernel parameters
     492    for (int i = 0, index = 0; i < numGaussians; i++) {
     493        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     494        // Iterate over (u,v) order
     495        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
     496            for (int vOrder = 0; vOrder <= orders->data.S32[i]; vOrder++, index++) {
     497
     498                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values
     499
     500                // save the generated 2D kernel as the target, deconvolve it by Gaussian, replacing the generated 2D kernel
     501                psKernel *kernelTarget = preCalc->kernel;
     502                preCalc->kernel = pmSubtractionDeconvolveKernel(kernelTarget, kernelGauss); // Kernel
     503
     504                // XXX do we use Alard-Lupton normalization (last param true) or not?
     505                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
     506
     507                // XXXX test demo that deconvolved kernel is valid
     508# if 1
     509                psImage *kernelConv = psImageConvolveFFT(NULL, preCalc->kernel->image, NULL, 0, kernelGauss);
     510                psArrayAdd (deconKernels, 100, kernelConv);
     511                psFree (kernelConv);
     512
     513                if (!uOrder && !vOrder){
     514                    pmSubtractionVisualShowSubtraction (kernelTarget->image, preCalc->kernel->image, kernelConv);
    162515                }
    163 
    164                 // Normalise sum of kernel component to unity for even functions
    165                 if (uOrder % 2 == 0 && vOrder % 2 == 0) {
    166                     double sum = 0.0;   // Sum of kernel component
    167                     for (int v = 0; v < fullSize; v++) {
    168                         for (int u = 0; u < fullSize; u++) {
    169                             sum += xKernel->data.F32[u] * yKernel->data.F32[v];
    170                         }
    171                     }
    172                     sum = 1.0 / sqrt(sum);
    173                     psBinaryOp(xKernel, xKernel, "*", psScalarAlloc(sum, PS_TYPE_F32));
    174                     psBinaryOp(yKernel, yKernel, "*", psScalarAlloc(sum, PS_TYPE_F32));
    175                     psBinaryOp(kernel->image, kernel->image, "*", psScalarAlloc(PS_SQR(sum), PS_TYPE_F32));
    176                     kernel->kernel[0][0] -= 1.0;
    177                     moment *= PS_SQR(sum);
     516# endif
     517            }
     518        }
     519    }
     520
     521# if 1
     522    psImage *dot = psImageAlloc(deconKernels->n, deconKernels->n, PS_TYPE_F32);
     523    for (int i = 0; i < deconKernels->n; i++) {
     524        for (int j = 0; j <= i; j++) {
     525            psImage *t1 = deconKernels->data[i];
     526            psImage *t2 = deconKernels->data[j];
     527
     528            double sum = 0.0;
     529            for (int iy = 0; iy < t1->numRows; iy++) {
     530                for (int ix = 0; ix < t1->numCols; ix++) {
     531                    sum += t1->data.F32[iy][ix] * t2->data.F32[iy][ix];
    178532                }
    179 
    180 
    181 #if 0
    182                 double sum = 0.0;   // Sum of kernel component
    183                 for (int v = -size; v <= size; v++) {
    184                     for (int u = -size; u <= size; u++) {
    185                         sum += kernel->kernel[v][u];
    186                     }
    187                 }
    188                 fprintf(stderr, "%d sum: %lf\n", index, sum);
    189 #endif
    190 
    191                 kernels->widths->data.F32[index] = fwhms->data.F32[i];
    192                 kernels->u->data.S32[index] = uOrder;
    193                 kernels->v->data.S32[index] = vOrder;
    194                 if (kernels->preCalc->data[index]) {
    195                     psFree(kernels->preCalc->data[index]);
    196                 }
    197                 kernels->preCalc->data[index] = preCalc;
    198                 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);
    199 
    200                 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index,
    201                         fwhms->data.F32[i], uOrder, vOrder, fabsf(moment));
    202533            }
    203         }
    204     }
     534            dot->data.F32[j][i] = sum;
     535            dot->data.F32[i][j] = sum;
     536        }
     537    }
     538    pmSubtractionVisualShowSubtraction (dot, NULL, NULL);
     539    psFree (dot);
     540    psFree (deconKernels);
     541# endif
    205542
    206543    return kernels;
     
    212549
    213550pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type,
    214                                                 int size, int spatialOrder, float penalty,
     551                                                int size, int spatialOrder, float penalty, psRegion bounds,
    215552                                                pmSubtractionMode mode)
    216553{
     
    224561    kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
    225562    kernels->widths = psVectorAlloc(numBasisFunctions, PS_TYPE_F32);
     563    kernels->uStop = NULL;
     564    kernels->vStop = NULL;
     565    kernels->xMin = bounds.x0;
     566    kernels->xMax = bounds.x1;
     567    kernels->yMin = bounds.y0;
     568    kernels->yMax = bounds.y1;
    226569    kernels->preCalc = psArrayAlloc(numBasisFunctions);
    227570    kernels->penalty = penalty;
    228571    kernels->penalties = psVectorAlloc(numBasisFunctions, PS_TYPE_F32);
    229     kernels->uStop = NULL;
    230     kernels->vStop = NULL;
    231572    kernels->size = size;
    232573    kernels->inner = 0;
     
    234575    kernels->bgOrder = 0;
    235576    kernels->mode = mode;
    236     kernels->numCols = 0;
    237     kernels->numRows = 0;
    238577    kernels->solution1 = NULL;
    239578    kernels->solution2 = NULL;
     579    kernels->mean = NAN;
     580    kernels->rms = NAN;
     581    kernels->numStamps = 0;
     582    kernels->sampleStamps = NULL;
     583
     584    kernels->fSigResMean  = NAN;
     585    kernels->fSigResStdev = NAN;
     586    kernels->fMaxResMean  = NAN;
     587    kernels->fMaxResStdev = NAN;
     588    kernels->fMinResMean  = NAN;
     589    kernels->fMinResStdev = NAN;
    240590
    241591    return kernels;
    242592}
    243593
    244 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty,
     594pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc(pmSubtractionKernelsType type, int uOrder, int vOrder, int size, float sigma) {
     595
     596    pmSubtractionKernelPreCalc *preCalc = psAlloc(sizeof(pmSubtractionKernelPreCalc)); // Kernels, to return
     597    psMemSetDeallocator(preCalc, (psFreeFunc)pmSubtractionKernelPreCalcFree);
     598
     599    // 1D kernel realizations:
     600    switch (type) {
     601      case PM_SUBTRACTION_KERNEL_ISIS:
     602        preCalc->xKernel = pmSubtractionKernelISIS(sigma, uOrder, size);
     603        preCalc->yKernel = pmSubtractionKernelISIS(sigma, vOrder, size);
     604        preCalc->uCoords = NULL;
     605        preCalc->vCoords = NULL;
     606        preCalc->poly    = NULL;
     607        break;
     608      case PM_SUBTRACTION_KERNEL_HERM:
     609        preCalc->xKernel = pmSubtractionKernelHERM(sigma, uOrder, size);
     610        preCalc->yKernel = pmSubtractionKernelHERM(sigma, vOrder, size);
     611        preCalc->uCoords = NULL;
     612        preCalc->vCoords = NULL;
     613        preCalc->poly    = NULL;
     614        break;
     615      case PM_SUBTRACTION_KERNEL_RINGS:
     616        // the RINGS kernel uses the uCoords, vCoords, and poly elements of the structure
     617        // we allocate these vectors here, but leave the kernel generation to the main function
     618        preCalc->xKernel = NULL;
     619        preCalc->yKernel = NULL;
     620        preCalc->kernel  = NULL;
     621        preCalc->uCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // u coords
     622        preCalc->vCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // v coords
     623        preCalc->poly    = psVectorAllocEmpty(size, PS_TYPE_F32); // Polynomial
     624        return preCalc;
     625      case PM_SUBTRACTION_KERNEL_ISIS_RADIAL:
     626        preCalc->kernel  = pmSubtractionKernelHERM_RADIAL(sigma, uOrder, size);
     627        preCalc->xKernel = NULL;
     628        preCalc->yKernel = NULL;
     629        preCalc->uCoords = NULL;
     630        preCalc->vCoords = NULL;
     631        preCalc->poly    = NULL;
     632        return preCalc;
     633      default:
     634        psAbort("programming error: invalid type for PreCalc kernel");
     635    }
     636
     637    preCalc->kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel
     638
     639    // generate 2D kernel from 1D realizations
     640    for (int v = -size, y = 0; v <= size; v++, y++) {
     641        for (int u = -size, x = 0; u <= size; u++, x++) {
     642            preCalc->kernel->kernel[v][u] = preCalc->xKernel->data.F32[x] * preCalc->yKernel->data.F32[y]; // Value of kernel
     643        }
     644    }
     645
     646    return preCalc;
     647}
     648
     649pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, psRegion bounds,
    245650                                               pmSubtractionMode mode)
    246651{
     
    251656
    252657    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size,
    253                                                               spatialOrder, penalty, mode); // The kernels
     658                                                              spatialOrder, penalty, bounds, mode); // Kernels
    254659    psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", size, spatialOrder, penalty);
    255660    psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements",
     
    266671pmSubtractionKernels *pmSubtractionKernelsISIS(int size, int spatialOrder,
    267672                                               const psVector *fwhms, const psVector *orders,
    268                                                float penalty, pmSubtractionMode mode)
     673                                               float penalty, psRegion bounds, pmSubtractionMode mode)
    269674{
    270675    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders,
    271                                                                   penalty, mode); // Kernels
     676                                                                  penalty, bounds, mode); // Kernels
    272677    if (!kernels) {
    273678        return NULL;
     
    278683
    279684pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, int spatialOrder, int inner, int binning,
    280                                                float penalty, pmSubtractionMode mode)
     685                                               float penalty, psRegion bounds, pmSubtractionMode mode)
    281686{
    282687    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    299704
    300705    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size,
    301                                                               spatialOrder, penalty, mode); // The kernels
     706                                                              spatialOrder, penalty, bounds, mode); // Kernels
    302707    kernels->inner = inner;
    303708    psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", size, inner, binning, spatialOrder,
     
    370775
    371776pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, int spatialOrder, int inner, float penalty,
    372                                                 pmSubtractionMode mode)
     777                                                psRegion bounds, pmSubtractionMode mode)
    373778{
    374779    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    397802
    398803    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size,
    399                                                               spatialOrder, penalty, mode); // The kernels
     804                                                              spatialOrder, penalty, bounds, mode); // Kernels
    400805    kernels->inner = inner;
    401806    psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", size, inner, spatialOrder, penalty);
     
    463868}
    464869
    465 // Grid United with Normal Kernel
     870// Grid United with Normal Kernel [description: GUNK=ISIS(...)+POIS(...)]
    466871pmSubtractionKernels *pmSubtractionKernelsGUNK(int size, int spatialOrder, const psVector *fwhms,
    467872                                               const psVector *orders, int inner, float penalty,
    468                                                pmSubtractionMode mode)
     873                                               psRegion bounds, pmSubtractionMode mode)
    469874{
    470875    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    479884
    480885    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders,
    481                                                                   penalty, mode); // Kernels
     886                                                                  penalty, bounds, mode); // Kernels
    482887    kernels->type = PM_SUBTRACTION_KERNEL_GUNK;
    483888    psStringPrepend(&kernels->description, "GUNK=");
     
    495900// RINGS --- just what it says
    496901pmSubtractionKernels *pmSubtractionKernelsRINGS(int size, int spatialOrder, int inner, int ringsOrder,
    497                                                 float penalty, pmSubtractionMode mode)
     902                                                float penalty, psRegion bounds, pmSubtractionMode mode)
    498903{
    499904    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    526931
    527932    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size,
    528                                                               spatialOrder, penalty, mode); // The kernels
     933                                                              spatialOrder, penalty, bounds, mode); // Kernels
    529934    kernels->inner = inner;
    530935    psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", size, inner, ringsOrder, spatialOrder,
     
    566971            for (int vOrder = 0; vOrder <= (i == 0 ? 0 : ringsOrder - uOrder); vOrder++, index++) {
    567972
    568                 psArray *data = psArrayAlloc(3); // Container for data
    569                 psVector *uCoords = data->data[0] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // u coords
    570                 psVector *vCoords = data->data[1] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // v coords
    571                 psVector *poly = data->data[2] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_F32); // Polynomial
     973                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc (PM_SUBTRACTION_KERNEL_RINGS, 0, 0, RINGS_BUFFER, 0.0);
    572974                double moment = 0.0;    // Moment, for penalty
    573975
    574976                if (i == 0) {
    575977                    // Central pixel is easy
    576                     uCoords->data.S32[0] = vCoords->data.S32[0] = 0;
    577                     poly->data.F32[0] = 1.0;
    578                     uCoords->n = vCoords->n = poly->n = 1;
     978                    preCalc->uCoords->data.S32[0] = 0;
     979                    preCalc->vCoords->data.S32[0] = 0;
     980                    preCalc->poly->data.F32[0] = 1.0;
     981                    preCalc->uCoords->n = 1;
     982                    preCalc->vCoords->n = 1;
     983                    preCalc->poly->n = 1;
    579984                    radiusLast = 0;
    580985                    moment = 0.0;
     
    594999                                float polyVal = uPoly * vPoly; // Value of polynomial
    5951000                                if (polyVal != 0) { // No point adding it otherwise
    596                                     uCoords->data.S32[j] = u;
    597                                     vCoords->data.S32[j] = v;
    598                                     poly->data.F32[j] = polyVal;
     1001                                    preCalc->uCoords->data.S32[j] = u;
     1002                                    preCalc->vCoords->data.S32[j] = v;
     1003                                    preCalc->poly->data.F32[j] = polyVal;
    5991004                                    norm += polyVal;
    600                                     moment += polyVal * PS_SQR(PS_SQR(u) + PS_SQR(v));
    601 
    602                                     psVectorExtend(uCoords, RINGS_BUFFER, 1);
    603                                     psVectorExtend(vCoords, RINGS_BUFFER, 1);
    604                                     psVectorExtend(poly, RINGS_BUFFER, 1);
     1005                                    moment += PS_SQR(polyVal) * PS_SQR(PS_SQR(u) + PS_SQR(v));
     1006
     1007                                    psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1);
     1008                                    psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1);
     1009                                    psVectorExtend(preCalc->poly, RINGS_BUFFER, 1);
    6051010                                    psTrace("psModules.imcombine", 9, "u = %d, v = %d, poly = %f\n",
    606                                             u, v, poly->data.F32[j]);
     1011                                            u, v, preCalc->poly->data.F32[j]);
    6071012                                    j++;
    6081013                                }
     
    6121017                    // Normalise kernel component to unit sum
    6131018                    if (uOrder % 2 == 0 && vOrder % 2 == 0) {
    614                         psBinaryOp(poly, poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
     1019                        psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
    6151020                        // Add subtraction of 0,0 component to preserve photometric scaling
    616                         uCoords->data.S32[j] = 0;
    617                         vCoords->data.S32[j] = 0;
    618                         poly->data.F32[j] = -1.0;
    619                         psVectorExtend(uCoords, RINGS_BUFFER, 1);
    620                         psVectorExtend(vCoords, RINGS_BUFFER, 1);
    621                         psVectorExtend(poly, RINGS_BUFFER, 1);
     1021                        preCalc->uCoords->data.S32[j] = 0;
     1022                        preCalc->vCoords->data.S32[j] = 0;
     1023                        preCalc->poly->data.F32[j] = -1.0;
     1024                        psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1);
     1025                        psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1);
     1026                        psVectorExtend(preCalc->poly, RINGS_BUFFER, 1);
    6221027                    } else {
    6231028                        norm = powf(size, uOrder) * powf(size, vOrder);
    624                         psBinaryOp(poly, poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
     1029                        psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
    6251030                    }
    626                     moment /= norm;
     1031                    moment /= PS_SQR(norm);
    6271032                }
    6281033
    629                 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", uCoords->n);
    630 
    631                 kernels->preCalc->data[index] = data;
     1034                psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", preCalc->uCoords->n);
     1035
     1036                kernels->preCalc->data[index] = preCalc;
    6321037                kernels->u->data.S32[index] = uOrder;
    6331038                kernels->v->data.S32[index] = vOrder;
    6341039                kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);
     1040                if (!isfinite(kernels->penalties->data.F32[index])) {
     1041                    psAbort ("invalid penalty");
     1042                }
    6351043
    6361044                psTrace("psModules.imcombine", 7, "Kernel %d: %d %d %d\n", index,
     
    6451053pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, int size, int spatialOrder,
    6461054                                                   const psVector *fwhms, const psVector *orders, int inner,
    647                                                    int binning, int ringsOrder, float penalty,
     1055                                                   int binning, int ringsOrder, float penalty, psRegion bounds,
    6481056                                                   pmSubtractionMode mode)
    6491057{
    6501058    switch (type) {
    6511059      case PM_SUBTRACTION_KERNEL_POIS:
    652         return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, mode);
     1060        return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, bounds, mode);
    6531061      case PM_SUBTRACTION_KERNEL_ISIS:
    654         return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, mode);
     1062        return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
     1063      case PM_SUBTRACTION_KERNEL_ISIS_RADIAL:
     1064        return pmSubtractionKernelsISIS_RADIAL(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
     1065      case PM_SUBTRACTION_KERNEL_HERM:
     1066        return pmSubtractionKernelsHERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
     1067      case PM_SUBTRACTION_KERNEL_DECONV_HERM:
     1068        return pmSubtractionKernelsDECONV_HERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
    6551069      case PM_SUBTRACTION_KERNEL_SPAM:
    656         return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, mode);
     1070        return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, bounds, mode);
    6571071      case PM_SUBTRACTION_KERNEL_FRIES:
    658         return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, mode);
     1072        return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, bounds, mode);
    6591073      case PM_SUBTRACTION_KERNEL_GUNK:
    660         return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, mode);
     1074        return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, bounds, mode);
    6611075      case PM_SUBTRACTION_KERNEL_RINGS:
    662         return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, mode);
     1076        return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, bounds, mode);
    6631077      default:
    6641078        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown kernel type: %x", type);
     
    6961110
    6971111pmSubtractionKernels *pmSubtractionKernelsFromDescription(const char *description, int bgOrder,
    698                                                           pmSubtractionMode mode)
     1112                                                          psRegion bounds, pmSubtractionMode mode)
    6991113{
    7001114    PS_ASSERT_STRING_NON_EMPTY(description, NULL);
     
    7151129    float penalty = 0.0;                // Penalty for wideness
    7161130
    717     if (strncmp(description, "ISIS", 4) == 0) {
    718         // XXX Support for GUNK
    719         if (strstr(description, "+POIS")) {
    720             type = PM_SUBTRACTION_KERNEL_GUNK;
    721             psAbort("Deciphering GUNK kernels (%s) is not currently supported.", description);
    722         } else {
    723             type = PM_SUBTRACTION_KERNEL_ISIS;
    724             char *ptr = (char*)description + 5;    // Eat "ISIS("
    725             PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt);
    726 
    727             // Count the number of Gaussians
    728             int numGauss = 0;
    729             for (char *string = ptr; string; string = strchr(string + 1, '(')) {
    730                 numGauss++;
    731             }
    732 
    733             fwhms = psVectorAlloc(numGauss, PS_TYPE_F32);
    734             orders = psVectorAlloc(numGauss, PS_TYPE_S32);
    735 
    736             for (int i = 0; i < numGauss; i++) {
    737                 ptr++;                  // Eat the '('
    738                 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234,"
    739                 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)"
    740             }
    741 
    742             ptr++;                      // Eat ','
    743             PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt);
    744             penalty = parseStringFloat(ptr);
    745         }
    746     } else if (strncmp(description, "RINGS", 5) == 0) {
    747         type = PM_SUBTRACTION_KERNEL_RINGS;
    748         char *ptr = (char*)description + 6;
     1131    // currently known descriptions:
     1132    // ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), SPAM(...),
     1133    // FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...),
     1134    // the descriptive name is the set of characters before the (
     1135
     1136    type = pmSubtractionKernelsTypeFromString (description);
     1137    char *ptr = strchr(description, '(') + 1;
     1138    psAssert (ptr, "description is missing kernel parameters");
     1139
     1140    switch (type) {
     1141      case PM_SUBTRACTION_KERNEL_ISIS:
     1142      case PM_SUBTRACTION_KERNEL_ISIS_RADIAL:
     1143      case PM_SUBTRACTION_KERNEL_HERM:
     1144      case PM_SUBTRACTION_KERNEL_DECONV_HERM:
     1145        PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt);
     1146
     1147        // Count the number of Gaussians
     1148        int numGauss = 0;
     1149        for (char *string = ptr; string; string = strchr(string + 1, '(')) {
     1150            numGauss++;
     1151        }
     1152
     1153        fwhms = psVectorAlloc(numGauss, PS_TYPE_F32);
     1154        orders = psVectorAlloc(numGauss, PS_TYPE_S32);
     1155
     1156        for (int i = 0; i < numGauss; i++) {
     1157            ptr++;                                                               // Eat the '('
     1158            PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234,"
     1159            PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt);  // Eat "3)"
     1160        }
     1161
     1162        ptr++;                      // Eat ','
     1163        PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt);
     1164        penalty = parseStringFloat(ptr);
     1165        break;
     1166      case PM_SUBTRACTION_KERNEL_RINGS:
    7491167        PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt);
    7501168        PARSE_STRING_NUMBER(inner, ptr, ',', parseStringInt);
     
    7521170        PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt);
    7531171        PARSE_STRING_NUMBER(penalty, ptr, ')', parseStringInt);
    754     } else {
    755         psAbort("Deciphering kernels other than ISIS and RINGS is not currently supported.");
    756     }
    757 
    758 
    759     return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders,
    760                                         inner, binning, ringsOrder, penalty, mode);
    761 }
    762 
    763 
     1172        break;
     1173      default:
     1174        psAbort("Deciphering kernels other than ISIS, HERM, DECONV_HERM or RINGS is not currently supported.");
     1175    }
     1176
     1177    return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, inner, binning,
     1178                                        ringsOrder, penalty, bounds, mode);
     1179}
     1180
     1181
     1182// the input string can either be just the name or the description string.  Currently known
     1183// descriptions: ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...),
     1184// SPAM(...), FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...),
    7641185pmSubtractionKernelsType pmSubtractionKernelsTypeFromString(const char *type)
    7651186{
    766     if (strcasecmp(type, "POIS") == 0) {
     1187    // for a bare name (ISIS, HERM), use the full string length.
     1188    // otherwise, use the length up to the first '('
     1189    int nameLength = strlen(type);
     1190    char *ptr = strchr(type, '(');
     1191    if (ptr) {
     1192        nameLength = ptr - type;
     1193    }
     1194
     1195    if (strncasecmp(type, "POIS", nameLength) == 0) {
    7671196        return PM_SUBTRACTION_KERNEL_POIS;
    7681197    }
    769     if (strcasecmp(type, "ISIS") == 0) {
     1198    if (strncasecmp(type, "ISIS", nameLength) == 0) {
    7701199        return PM_SUBTRACTION_KERNEL_ISIS;
    7711200    }
    772     if (strcasecmp(type, "SPAM") == 0) {
     1201    if (strncasecmp(type, "ISIS_RADIAL", nameLength) == 0) {
     1202        return PM_SUBTRACTION_KERNEL_ISIS_RADIAL;
     1203    }
     1204    if (strncasecmp(type, "HERM", nameLength) == 0) {
     1205        return PM_SUBTRACTION_KERNEL_HERM;
     1206    }
     1207    if (strncasecmp(type, "DECONV_HERM", nameLength) == 0) {
     1208        return PM_SUBTRACTION_KERNEL_DECONV_HERM;
     1209    }
     1210    if (strncasecmp(type, "SPAM", nameLength) == 0) {
    7731211        return PM_SUBTRACTION_KERNEL_SPAM;
    7741212    }
    775     if (strcasecmp(type, "FRIES") == 0) {
     1213    if (strncasecmp(type, "FRIES", nameLength) == 0) {
    7761214        return PM_SUBTRACTION_KERNEL_FRIES;
    7771215    }
    778     if (strcasecmp(type, "GUNK") == 0) {
     1216    if (strncasecmp(type, "GUNK", nameLength) == 0) {
    7791217        return PM_SUBTRACTION_KERNEL_GUNK;
    7801218    }
    781     if (strcasecmp(type, "RINGS") == 0) {
     1219    // note that GUNK has a somewhat different description
     1220    if (strncasecmp(type, "GUNK=ISIS", nameLength) == 0) {
     1221        return PM_SUBTRACTION_KERNEL_GUNK;
     1222    }
     1223    if (strncasecmp(type, "RINGS", nameLength) == 0) {
    7821224        return PM_SUBTRACTION_KERNEL_RINGS;
    7831225    }
     
    8101252    out->bgOrder = in->bgOrder;
    8111253    out->mode = in->mode;
    812     out->numCols = in->numCols;
    813     out->numRows = in->numRows;
     1254    out->xMin = in->xMin;
     1255    out->xMax = in->xMax;
     1256    out->yMin = in->yMin;
     1257    out->yMax = in->yMax;
    8141258    out->solution1 = in->solution1 ? psVectorCopy(NULL, in->solution1, PS_TYPE_F64) : NULL;
    8151259    out->solution2 = in->solution2 ? psVectorCopy(NULL, in->solution2, PS_TYPE_F64) : NULL;
     1260    out->sampleStamps = psMemIncrRefCounter(in->sampleStamps);
    8161261
    8171262    return out;
Note: See TracChangeset for help on using the changeset viewer.