IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:41:49 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/tap_branches
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/tap_branches

  • branches/tap_branches/psModules

  • branches/tap_branches/psModules/src/imcombine/pmSubtractionKernels.c

    r25120 r27838  
    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
     
    81142    kernels->penalties = psVectorRealloc(kernels->penalties, start + numNew);
    82143    kernels->inner = start;
     144    kernels->num += numNew;
    83145
    84146    // Generate a set of kernels for each (u,v)
     
    94156            kernels->v->data.S32[index] = v;
    95157            kernels->preCalc->data[index] = NULL;
    96             kernels->penalties->data.F32[index] = kernels->penalty * (PS_SQR(u) + PS_SQR(v));
    97 
     158            kernels->penalties->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v));
     159            psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty");
    98160            psTrace("psModules.imcombine", 7, "Kernel %d: %d %d\n", index, u, v);
    99161        }
    100162    }
    101163
     164    kernels->widths->n = start + numNew;
     165    kernels->u->n = start + numNew;
     166    kernels->v->n = start + numNew;
     167    kernels->preCalc->n = start + numNew;
     168    kernels->penalties->n = start + numNew;
     169
    102170    return true;
    103171}
    104172
     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
    105276pmSubtractionKernels *p_pmSubtractionKernelsRawISIS(int size, int spatialOrder,
    106                                                     const psVector *fwhms, const psVector *orders,
    107                                                     float penalty, pmSubtractionMode mode)
    108 {
    109     PS_ASSERT_VECTOR_NON_NULL(fwhms, NULL);
    110     PS_ASSERT_VECTOR_TYPE(fwhms, PS_TYPE_F32, NULL);
    111     PS_ASSERT_VECTOR_NON_NULL(orders, NULL);
    112     PS_ASSERT_VECTOR_TYPE(orders, PS_TYPE_S32, NULL);
    113     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);
    114285    PS_ASSERT_INT_POSITIVE(size, NULL);
    115286    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    }
    116296
    117297    int numGaussians = fwhms->n;       // Number of Gaussians
     
    126306
    127307    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size,
    128                                                               spatialOrder, penalty, mode); // The kernels
     308                                                              spatialOrder, penalty, bounds, mode); // Kernels
    129309    psStringAppend(&kernels->description, "ISIS(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
    130310
     
    134314
    135315    // Set the kernel parameters
    136     int fullSize = 2 * size + 1;        // Full size of kernels
    137316    for (int i = 0, index = 0; i < numGaussians; i++) {
    138317        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     
    140319        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
    141320            for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
    142                 psArray *preCalc = psArrayAlloc(2); // Array to hold precalculated values
    143                 psVector *xKernel = preCalc->data[0] = subtractionKernelISIS(sigma, uOrder, size); // x Kernel
    144                 psVector *yKernel = preCalc->data[1] = subtractionKernelISIS(sigma, vOrder, size); // y Kernel
    145 
    146                 // Calculate moments
    147                 double moment = 0.0;    // Moment, for penalty
    148                 for (int v = -size, y = 0; v <= size; v++, y++) {
    149                     for (int u = -size, x = 0; u <= size; u++, x++) {
    150                         double value = xKernel->data.F32[x] * yKernel->data.F32[y]; // Value of kernel
    151                         moment += value * (PS_SQR(u) + PS_SQR(v));
    152                     }
     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    psFree(orders);
     330    psFree(fwhms);
     331
     332    return kernels;
     333}
     334
     335pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, int spatialOrder,
     336                                                      const psVector *fwhmsIN, const psVector *ordersIN,
     337                                                      float penalty, psRegion bounds, pmSubtractionMode mode)
     338{
     339    PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL);
     340    PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL);
     341    PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL);
     342    PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL);
     343    PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL);
     344    PS_ASSERT_INT_POSITIVE(size, NULL);
     345    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     346
     347    // check the requested fwhm values: any values <= 0.0 should be dropped
     348    psVector *fwhms  = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32);
     349    psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32);
     350    for (int i = 0; i < fwhmsIN->n; i++) {
     351        if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue;
     352        psVectorAppend(fwhms, fwhmsIN->data.F32[i]);
     353        psVectorAppend(orders, ordersIN->data.S32[i]);
     354    }
     355
     356    int numGaussians = fwhms->n;       // Number of Gaussians
     357
     358    int num = 0;                        // Number of basis functions
     359    psString params = NULL;             // List of parameters
     360    for (int i = 0; i < numGaussians; i++) {
     361        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
     362        psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
     363        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
     364        num += (11 - gaussOrder - 1);   // include all higher order radial terms
     365    }
     366
     367    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size,
     368                                                              spatialOrder, penalty, bounds, mode); // Kernels
     369    psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
     370
     371    psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS_RADIAL kernel: %s,%d --> %d elements", params, spatialOrder, num);
     372    psFree(params);
     373
     374    // Set the kernel parameters
     375    for (int i = 0, index = 0; i < numGaussians; i++) {
     376        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     377        // Iterate over (u,v) order
     378        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
     379            for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
     380                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values
     381                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
     382            }
     383        }
     384        for (int order = orders->data.S32[i] + 1; order < 11; order ++, index ++) {
     385            // XXX modify size for hermitians to account for sqrt(2) in Hermitian definition (relative to ISIS Gaussian)
     386            pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS_RADIAL, order, order, size, sigma / sqrt(2.0)); // structure to hold precalculated values
     387            pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, order, order, fwhms->data.F32[i], true, true);
     388        }
     389    }
     390    return kernels;
     391}
     392
     393pmSubtractionKernels *pmSubtractionKernelsHERM(int size, int spatialOrder,
     394                                               const psVector *fwhmsIN, const psVector *ordersIN,
     395                                               float penalty, psRegion bounds, pmSubtractionMode mode)
     396{
     397    PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL);
     398    PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL);
     399    PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL);
     400    PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL);
     401    PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL);
     402    PS_ASSERT_INT_POSITIVE(size, NULL);
     403    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     404
     405    // check the requested fwhm values: any values <= 0.0 should be dropped
     406    psVector *fwhms  = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32);
     407    psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32);
     408    for (int i = 0; i < fwhmsIN->n; i++) {
     409        if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue;
     410        psVectorAppend(fwhms, fwhmsIN->data.F32[i]);
     411        psVectorAppend(orders, ordersIN->data.S32[i]);
     412    }
     413
     414    int numGaussians = fwhms->n;       // Number of Gaussians
     415
     416    int num = 0;                        // Number of basis functions
     417    psString params = NULL;             // List of parameters
     418    for (int i = 0; i < numGaussians; i++) {
     419        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
     420        psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
     421        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
     422    }
     423
     424    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size,
     425                                                              spatialOrder, penalty, bounds, mode); // Kernels
     426    psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
     427
     428    psLogMsg("psModules.imcombine", PS_LOG_INFO, "HERM kernel: %s,%d --> %d elements",
     429             params, spatialOrder, num);
     430    psFree(params);
     431
     432    // Set the kernel parameters
     433    for (int i = 0, index = 0; i < numGaussians; i++) {
     434        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     435        // Iterate over (u,v) order
     436        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
     437            for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
     438                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values
     439                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
     440            }
     441        }
     442    }
     443
     444    return kernels;
     445}
     446
     447pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, int spatialOrder,
     448                                                      const psVector *fwhmsIN, const psVector *ordersIN,
     449                                                      float penalty, psRegion bounds, pmSubtractionMode mode)
     450{
     451    PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL);
     452    PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL);
     453    PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL);
     454    PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL);
     455    PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL);
     456    PS_ASSERT_INT_POSITIVE(size, NULL);
     457    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     458
     459    // check the requested fwhm values: any values <= 0.0 should be dropped
     460    psVector *fwhms  = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32);
     461    psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32);
     462    for (int i = 0; i < fwhmsIN->n; i++) {
     463        if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue;
     464        psVectorAppend(fwhms, fwhmsIN->data.F32[i]);
     465        psVectorAppend(orders, ordersIN->data.S32[i]);
     466    }
     467
     468    int numGaussians = fwhms->n;       // Number of Gaussians
     469
     470    int num = 0;                        // Number of basis functions
     471    psString params = NULL;             // List of parameters
     472    for (int i = 0; i < numGaussians; i++) {
     473        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
     474        psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
     475        num += PS_SQR(gaussOrder + 1);
     476    }
     477
     478    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size,
     479                                                              spatialOrder, penalty, bounds, mode); // Kernels
     480    psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
     481
     482    psLogMsg("psModules.imcombine", PS_LOG_INFO, "DECONVOLVED HERM kernel: %s,%d --> %d elements", params, spatialOrder, num);
     483    psFree(params);
     484
     485    // XXXXX hard-wired reference sigma for now of 1.7 pix (== 4.0 pix fwhm == 1.0 arcsec in simtest)
     486    // generate the Gaussian deconvolution kernel
     487    # define DECONV_SIGMA 1.6
     488    psKernel *kernelGauss = pmSubtractionDeconvolveGauss (size, DECONV_SIGMA);
     489
     490# if 1
     491    psArray *deconKernels = psArrayAllocEmpty(100);
     492# endif
     493
     494    // Set the kernel parameters
     495    for (int i = 0, index = 0; i < numGaussians; i++) {
     496        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
     497        // Iterate over (u,v) order
     498        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
     499            for (int vOrder = 0; vOrder <= orders->data.S32[i]; vOrder++, index++) {
     500
     501                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values
     502
     503                // save the generated 2D kernel as the target, deconvolve it by Gaussian, replacing the generated 2D kernel
     504                psKernel *kernelTarget = preCalc->kernel;
     505                preCalc->kernel = pmSubtractionDeconvolveKernel(kernelTarget, kernelGauss); // Kernel
     506
     507                // XXX do we use Alard-Lupton normalization (last param true) or not?
     508                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
     509
     510                // XXXX test demo that deconvolved kernel is valid
     511# if 1
     512                psImage *kernelConv = psImageConvolveFFT(NULL, preCalc->kernel->image, NULL, 0, kernelGauss);
     513                psArrayAdd (deconKernels, 100, kernelConv);
     514                psFree (kernelConv);
     515
     516                if (!uOrder && !vOrder){
     517                    pmSubtractionVisualShowSubtraction (kernelTarget->image, preCalc->kernel->image, kernelConv);
    153518                }
    154 
    155                 // Normalise sum of kernel component to unity for even functions
    156                 if (uOrder % 2 == 0 && vOrder % 2 == 0) {
    157                     double sum = 0.0;   // Sum of kernel component
    158                     for (int v = 0; v < fullSize; v++) {
    159                         for (int u = 0; u < fullSize; u++) {
    160                             sum += xKernel->data.F32[u] * yKernel->data.F32[v];
    161                         }
    162                     }
    163                     sum = 1.0 / sqrt(sum);
    164                     psBinaryOp(xKernel, xKernel, "*", psScalarAlloc(sum, PS_TYPE_F32));
    165                     psBinaryOp(yKernel, yKernel, "*", psScalarAlloc(sum, PS_TYPE_F32));
    166                     moment *= PS_SQR(sum);
     519# endif
     520            }
     521        }
     522    }
     523
     524# if 1
     525    psImage *dot = psImageAlloc(deconKernels->n, deconKernels->n, PS_TYPE_F32);
     526    for (int i = 0; i < deconKernels->n; i++) {
     527        for (int j = 0; j <= i; j++) {
     528            psImage *t1 = deconKernels->data[i];
     529            psImage *t2 = deconKernels->data[j];
     530
     531            double sum = 0.0;
     532            for (int iy = 0; iy < t1->numRows; iy++) {
     533                for (int ix = 0; ix < t1->numCols; ix++) {
     534                    sum += t1->data.F32[iy][ix] * t2->data.F32[iy][ix];
    167535                }
    168 
    169                 kernels->widths->data.F32[index] = fwhms->data.F32[i];
    170                 kernels->u->data.S32[index] = uOrder;
    171                 kernels->v->data.S32[index] = vOrder;
    172                 if (kernels->preCalc->data[index]) {
    173                     psFree(kernels->preCalc->data[index]);
    174                 }
    175                 kernels->preCalc->data[index] = preCalc;
    176                 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);
    177 
    178                 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index,
    179                         fwhms->data.F32[i], uOrder, vOrder, fabsf(moment));
    180536            }
    181         }
    182     }
     537            dot->data.F32[j][i] = sum;
     538            dot->data.F32[i][j] = sum;
     539        }
     540    }
     541    pmSubtractionVisualShowSubtraction (dot, NULL, NULL);
     542    psFree (dot);
     543    psFree (deconKernels);
     544# endif
    183545
    184546    return kernels;
     
    190552
    191553pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type,
    192                                                 int size, int spatialOrder, float penalty,
     554                                                int size, int spatialOrder, float penalty, psRegion bounds,
    193555                                                pmSubtractionMode mode)
    194556{
     
    202564    kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
    203565    kernels->widths = psVectorAlloc(numBasisFunctions, PS_TYPE_F32);
     566    kernels->uStop = NULL;
     567    kernels->vStop = NULL;
     568    kernels->xMin = bounds.x0;
     569    kernels->xMax = bounds.x1;
     570    kernels->yMin = bounds.y0;
     571    kernels->yMax = bounds.y1;
    204572    kernels->preCalc = psArrayAlloc(numBasisFunctions);
    205573    kernels->penalty = penalty;
    206574    kernels->penalties = psVectorAlloc(numBasisFunctions, PS_TYPE_F32);
    207     kernels->uStop = NULL;
    208     kernels->vStop = NULL;
    209575    kernels->size = size;
    210576    kernels->inner = 0;
     
    212578    kernels->bgOrder = 0;
    213579    kernels->mode = mode;
    214     kernels->numCols = 0;
    215     kernels->numRows = 0;
    216580    kernels->solution1 = NULL;
    217581    kernels->solution2 = NULL;
     582    kernels->mean = NAN;
     583    kernels->rms = NAN;
     584    kernels->numStamps = 0;
     585    kernels->sampleStamps = NULL;
     586
     587    kernels->fSigResMean  = NAN;
     588    kernels->fSigResStdev = NAN;
     589    kernels->fMaxResMean  = NAN;
     590    kernels->fMaxResStdev = NAN;
     591    kernels->fMinResMean  = NAN;
     592    kernels->fMinResStdev = NAN;
    218593
    219594    return kernels;
    220595}
    221596
    222 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty,
     597pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc(pmSubtractionKernelsType type, int uOrder, int vOrder, int size, float sigma) {
     598
     599    pmSubtractionKernelPreCalc *preCalc = psAlloc(sizeof(pmSubtractionKernelPreCalc)); // Kernels, to return
     600    psMemSetDeallocator(preCalc, (psFreeFunc)pmSubtractionKernelPreCalcFree);
     601
     602    // 1D kernel realizations:
     603    switch (type) {
     604      case PM_SUBTRACTION_KERNEL_ISIS:
     605        preCalc->xKernel = pmSubtractionKernelISIS(sigma, uOrder, size);
     606        preCalc->yKernel = pmSubtractionKernelISIS(sigma, vOrder, size);
     607        preCalc->uCoords = NULL;
     608        preCalc->vCoords = NULL;
     609        preCalc->poly    = NULL;
     610        break;
     611      case PM_SUBTRACTION_KERNEL_HERM:
     612        preCalc->xKernel = pmSubtractionKernelHERM(sigma, uOrder, size);
     613        preCalc->yKernel = pmSubtractionKernelHERM(sigma, vOrder, size);
     614        preCalc->uCoords = NULL;
     615        preCalc->vCoords = NULL;
     616        preCalc->poly    = NULL;
     617        break;
     618      case PM_SUBTRACTION_KERNEL_RINGS:
     619        // the RINGS kernel uses the uCoords, vCoords, and poly elements of the structure
     620        // we allocate these vectors here, but leave the kernel generation to the main function
     621        preCalc->xKernel = NULL;
     622        preCalc->yKernel = NULL;
     623        preCalc->kernel  = NULL;
     624        preCalc->uCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // u coords
     625        preCalc->vCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // v coords
     626        preCalc->poly    = psVectorAllocEmpty(size, PS_TYPE_F32); // Polynomial
     627        return preCalc;
     628      case PM_SUBTRACTION_KERNEL_ISIS_RADIAL:
     629        preCalc->kernel  = pmSubtractionKernelHERM_RADIAL(sigma, uOrder, size);
     630        preCalc->xKernel = NULL;
     631        preCalc->yKernel = NULL;
     632        preCalc->uCoords = NULL;
     633        preCalc->vCoords = NULL;
     634        preCalc->poly    = NULL;
     635        return preCalc;
     636      default:
     637        psAbort("programming error: invalid type for PreCalc kernel");
     638    }
     639
     640    preCalc->kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel
     641
     642    // generate 2D kernel from 1D realizations
     643    for (int v = -size, y = 0; v <= size; v++, y++) {
     644        for (int u = -size, x = 0; u <= size; u++, x++) {
     645            preCalc->kernel->kernel[v][u] = preCalc->xKernel->data.F32[x] * preCalc->yKernel->data.F32[y]; // Value of kernel
     646        }
     647    }
     648
     649    return preCalc;
     650}
     651
     652pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, psRegion bounds,
    223653                                               pmSubtractionMode mode)
    224654{
     
    228658    int num = PS_SQR(2 * size + 1) - 1; // Number of basis functions
    229659
    230     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_POIS, size,
    231                                                               spatialOrder, penalty, mode); // The kernels
     660    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size,
     661                                                              spatialOrder, penalty, bounds, mode); // Kernels
    232662    psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", size, spatialOrder, penalty);
    233663    psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements",
     
    244674pmSubtractionKernels *pmSubtractionKernelsISIS(int size, int spatialOrder,
    245675                                               const psVector *fwhms, const psVector *orders,
    246                                                float penalty, pmSubtractionMode mode)
     676                                               float penalty, psRegion bounds, pmSubtractionMode mode)
    247677{
    248678    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders,
    249                                                                   penalty, mode); // Kernels
     679                                                                  penalty, bounds, mode); // Kernels
    250680    if (!kernels) {
    251681        return NULL;
     
    256686
    257687pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, int spatialOrder, int inner, int binning,
    258                                                float penalty, pmSubtractionMode mode)
     688                                               float penalty, psRegion bounds, pmSubtractionMode mode)
    259689{
    260690    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    277707
    278708    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size,
    279                                                               spatialOrder, penalty, mode); // The kernels
     709                                                              spatialOrder, penalty, bounds, mode); // Kernels
    280710    kernels->inner = inner;
    281711    psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", size, inner, binning, spatialOrder,
     
    348778
    349779pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, int spatialOrder, int inner, float penalty,
    350                                                 pmSubtractionMode mode)
     780                                                psRegion bounds, pmSubtractionMode mode)
    351781{
    352782    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    375805
    376806    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size,
    377                                                               spatialOrder, penalty, mode); // The kernels
     807                                                              spatialOrder, penalty, bounds, mode); // Kernels
    378808    kernels->inner = inner;
    379809    psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", size, inner, spatialOrder, penalty);
     
    441871}
    442872
    443 // Grid United with Normal Kernel
     873// Grid United with Normal Kernel [description: GUNK=ISIS(...)+POIS(...)]
    444874pmSubtractionKernels *pmSubtractionKernelsGUNK(int size, int spatialOrder, const psVector *fwhms,
    445875                                               const psVector *orders, int inner, float penalty,
    446                                                pmSubtractionMode mode)
     876                                               psRegion bounds, pmSubtractionMode mode)
    447877{
    448878    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    456886    PS_ASSERT_INT_LESS_THAN(inner, size, NULL);
    457887
    458     // XXX GUNK doesn't seem to work --- doesn't add the POIS components, or at least, they're not noticed
    459 
    460888    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders,
    461                                                                   penalty, mode); // Kernels
     889                                                                  penalty, bounds, mode); // Kernels
     890    kernels->type = PM_SUBTRACTION_KERNEL_GUNK;
    462891    psStringPrepend(&kernels->description, "GUNK=");
    463892    psStringAppend(&kernels->description, "+POIS(%d,%d)", inner, spatialOrder);
     
    474903// RINGS --- just what it says
    475904pmSubtractionKernels *pmSubtractionKernelsRINGS(int size, int spatialOrder, int inner, int ringsOrder,
    476                                                 float penalty, pmSubtractionMode mode)
     905                                                float penalty, psRegion bounds, pmSubtractionMode mode)
    477906{
    478907    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    505934
    506935    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size,
    507                                                               spatialOrder, penalty, mode); // The kernels
     936                                                              spatialOrder, penalty, bounds, mode); // Kernels
    508937    kernels->inner = inner;
    509938    psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", size, inner, ringsOrder, spatialOrder,
     
    545974            for (int vOrder = 0; vOrder <= (i == 0 ? 0 : ringsOrder - uOrder); vOrder++, index++) {
    546975
    547                 psArray *data = psArrayAlloc(3); // Container for data
    548                 psVector *uCoords = data->data[0] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // u coords
    549                 psVector *vCoords = data->data[1] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // v coords
    550                 psVector *poly = data->data[2] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_F32); // Polynomial
     976                pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc (PM_SUBTRACTION_KERNEL_RINGS, 0, 0, RINGS_BUFFER, 0.0);
    551977                double moment = 0.0;    // Moment, for penalty
    552978
    553979                if (i == 0) {
    554980                    // Central pixel is easy
    555                     uCoords->data.S32[0] = vCoords->data.S32[0] = 0;
    556                     poly->data.F32[0] = 1.0;
    557                     uCoords->n = vCoords->n = poly->n = 1;
     981                    preCalc->uCoords->data.S32[0] = 0;
     982                    preCalc->vCoords->data.S32[0] = 0;
     983                    preCalc->poly->data.F32[0] = 1.0;
     984                    preCalc->uCoords->n = 1;
     985                    preCalc->vCoords->n = 1;
     986                    preCalc->poly->n = 1;
    558987                    radiusLast = 0;
    559988                    moment = 0.0;
     
    5731002                                float polyVal = uPoly * vPoly; // Value of polynomial
    5741003                                if (polyVal != 0) { // No point adding it otherwise
    575                                     uCoords->data.S32[j] = u;
    576                                     vCoords->data.S32[j] = v;
    577                                     poly->data.F32[j] = polyVal;
     1004                                    preCalc->uCoords->data.S32[j] = u;
     1005                                    preCalc->vCoords->data.S32[j] = v;
     1006                                    preCalc->poly->data.F32[j] = polyVal;
    5781007                                    norm += polyVal;
    579                                     moment += polyVal * (PS_SQR(u) + PS_SQR(v));
    580 
    581                                     psVectorExtend(uCoords, RINGS_BUFFER, 1);
    582                                     psVectorExtend(vCoords, RINGS_BUFFER, 1);
    583                                     psVectorExtend(poly, RINGS_BUFFER, 1);
     1008                                    moment += PS_SQR(polyVal) * PS_SQR(PS_SQR(u) + PS_SQR(v));
     1009
     1010                                    psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1);
     1011                                    psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1);
     1012                                    psVectorExtend(preCalc->poly, RINGS_BUFFER, 1);
    5841013                                    psTrace("psModules.imcombine", 9, "u = %d, v = %d, poly = %f\n",
    585                                             u, v, poly->data.F32[j]);
     1014                                            u, v, preCalc->poly->data.F32[j]);
    5861015                                    j++;
    5871016                                }
     
    5911020                    // Normalise kernel component to unit sum
    5921021                    if (uOrder % 2 == 0 && vOrder % 2 == 0) {
    593                         psBinaryOp(poly, poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
     1022                        psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
    5941023                        // Add subtraction of 0,0 component to preserve photometric scaling
    595                         uCoords->data.S32[j] = 0;
    596                         vCoords->data.S32[j] = 0;
    597                         poly->data.F32[j] = -1.0;
    598                         psVectorExtend(uCoords, RINGS_BUFFER, 1);
    599                         psVectorExtend(vCoords, RINGS_BUFFER, 1);
    600                         psVectorExtend(poly, RINGS_BUFFER, 1);
     1024                        preCalc->uCoords->data.S32[j] = 0;
     1025                        preCalc->vCoords->data.S32[j] = 0;
     1026                        preCalc->poly->data.F32[j] = -1.0;
     1027                        psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1);
     1028                        psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1);
     1029                        psVectorExtend(preCalc->poly, RINGS_BUFFER, 1);
    6011030                    } else {
    6021031                        norm = powf(size, uOrder) * powf(size, vOrder);
    603                         psBinaryOp(poly, poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
     1032                        psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));
    6041033                    }
    605 //                    moment /= norm;
     1034                    moment /= PS_SQR(norm);
    6061035                }
    6071036
    608                 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", uCoords->n);
    609 
    610                 kernels->preCalc->data[index] = data;
     1037                psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", preCalc->uCoords->n);
     1038
     1039                kernels->preCalc->data[index] = preCalc;
    6111040                kernels->u->data.S32[index] = uOrder;
    6121041                kernels->v->data.S32[index] = vOrder;
    6131042                kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);
     1043                if (!isfinite(kernels->penalties->data.F32[index])) {
     1044                    psAbort ("invalid penalty");
     1045                }
    6141046
    6151047                psTrace("psModules.imcombine", 7, "Kernel %d: %d %d %d\n", index,
     
    6241056pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, int size, int spatialOrder,
    6251057                                                   const psVector *fwhms, const psVector *orders, int inner,
    626                                                    int binning, int ringsOrder, float penalty,
     1058                                                   int binning, int ringsOrder, float penalty, psRegion bounds,
    6271059                                                   pmSubtractionMode mode)
    6281060{
    6291061    switch (type) {
    6301062      case PM_SUBTRACTION_KERNEL_POIS:
    631         return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, mode);
     1063        return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, bounds, mode);
    6321064      case PM_SUBTRACTION_KERNEL_ISIS:
    633         return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, mode);
     1065        return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
     1066      case PM_SUBTRACTION_KERNEL_ISIS_RADIAL:
     1067        return pmSubtractionKernelsISIS_RADIAL(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
     1068      case PM_SUBTRACTION_KERNEL_HERM:
     1069        return pmSubtractionKernelsHERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
     1070      case PM_SUBTRACTION_KERNEL_DECONV_HERM:
     1071        return pmSubtractionKernelsDECONV_HERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode);
    6341072      case PM_SUBTRACTION_KERNEL_SPAM:
    635         return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, mode);
     1073        return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, bounds, mode);
    6361074      case PM_SUBTRACTION_KERNEL_FRIES:
    637         return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, mode);
     1075        return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, bounds, mode);
    6381076      case PM_SUBTRACTION_KERNEL_GUNK:
    639         return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, mode);
     1077        return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, bounds, mode);
    6401078      case PM_SUBTRACTION_KERNEL_RINGS:
    641         return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, mode);
     1079        return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, bounds, mode);
    6421080      default:
    6431081        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown kernel type: %x", type);
     
    6751113
    6761114pmSubtractionKernels *pmSubtractionKernelsFromDescription(const char *description, int bgOrder,
    677                                                           pmSubtractionMode mode)
     1115                                                          psRegion bounds, pmSubtractionMode mode)
    6781116{
    6791117    PS_ASSERT_STRING_NON_EMPTY(description, NULL);
     
    6941132    float penalty = 0.0;                // Penalty for wideness
    6951133
    696     if (strncmp(description, "ISIS", 4) == 0) {
    697         // XXX Support for GUNK
    698         if (strstr(description, "+POIS")) {
    699             type = PM_SUBTRACTION_KERNEL_GUNK;
    700             psAbort("Deciphering GUNK kernels (%s) is not currently supported.", description);
    701         } else {
    702             type = PM_SUBTRACTION_KERNEL_ISIS;
    703             char *ptr = (char*)description + 5;    // Eat "ISIS("
    704             PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt);
    705 
    706             // Count the number of Gaussians
    707             int numGauss = 0;
    708             for (char *string = ptr; string; string = strchr(string + 1, '(')) {
    709                 numGauss++;
    710             }
    711 
    712             fwhms = psVectorAlloc(numGauss, PS_TYPE_F32);
    713             orders = psVectorAlloc(numGauss, PS_TYPE_S32);
    714 
    715             for (int i = 0; i < numGauss; i++) {
    716                 ptr++;                  // Eat the '('
    717                 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234,"
    718                 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)"
    719             }
    720 
    721             ptr++;                      // Eat ','
    722             PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt);
    723             penalty = parseStringFloat(ptr);
    724         }
    725     } else if (strncmp(description, "RINGS", 5) == 0) {
    726         type = PM_SUBTRACTION_KERNEL_RINGS;
    727         char *ptr = (char*)description + 6;
     1134    // currently known descriptions:
     1135    // ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), SPAM(...),
     1136    // FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...),
     1137    // the descriptive name is the set of characters before the (
     1138
     1139    type = pmSubtractionKernelsTypeFromString (description);
     1140    char *ptr = strchr(description, '(') + 1;
     1141    psAssert (ptr, "description is missing kernel parameters");
     1142
     1143    switch (type) {
     1144      case PM_SUBTRACTION_KERNEL_ISIS:
     1145      case PM_SUBTRACTION_KERNEL_ISIS_RADIAL:
     1146      case PM_SUBTRACTION_KERNEL_HERM:
     1147      case PM_SUBTRACTION_KERNEL_DECONV_HERM:
     1148        PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt);
     1149
     1150        // Count the number of Gaussians
     1151        int numGauss = 0;
     1152        for (char *string = ptr; string; string = strchr(string + 1, '(')) {
     1153            numGauss++;
     1154        }
     1155
     1156        fwhms = psVectorAlloc(numGauss, PS_TYPE_F32);
     1157        orders = psVectorAlloc(numGauss, PS_TYPE_S32);
     1158
     1159        for (int i = 0; i < numGauss; i++) {
     1160            ptr++;                                                               // Eat the '('
     1161            PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234,"
     1162            PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt);  // Eat "3)"
     1163        }
     1164
     1165        ptr++;                      // Eat ','
     1166        PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt);
     1167        penalty = parseStringFloat(ptr);
     1168        break;
     1169      case PM_SUBTRACTION_KERNEL_RINGS:
    7281170        PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt);
    7291171        PARSE_STRING_NUMBER(inner, ptr, ',', parseStringInt);
     
    7311173        PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt);
    7321174        PARSE_STRING_NUMBER(penalty, ptr, ')', parseStringInt);
    733     } else {
    734         psAbort("Deciphering kernels other than ISIS and RINGS is not currently supported.");
    735     }
    736 
    737 
    738     return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders,
    739                                         inner, binning, ringsOrder, penalty, mode);
    740 }
    741 
    742 
     1175        break;
     1176      default:
     1177        psAbort("Deciphering kernels other than ISIS, HERM, DECONV_HERM or RINGS is not currently supported.");
     1178    }
     1179
     1180    return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, inner, binning,
     1181                                        ringsOrder, penalty, bounds, mode);
     1182}
     1183
     1184
     1185// the input string can either be just the name or the description string.  Currently known
     1186// descriptions: ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...),
     1187// SPAM(...), FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...),
    7431188pmSubtractionKernelsType pmSubtractionKernelsTypeFromString(const char *type)
    7441189{
    745     if (strcasecmp(type, "POIS") == 0) {
     1190    // for a bare name (ISIS, HERM), use the full string length.
     1191    // otherwise, use the length up to the first '('
     1192    int nameLength = strlen(type);
     1193    char *ptr = strchr(type, '(');
     1194    if (ptr) {
     1195        nameLength = ptr - type;
     1196    }
     1197
     1198    if (strncasecmp(type, "POIS", nameLength) == 0) {
    7461199        return PM_SUBTRACTION_KERNEL_POIS;
    7471200    }
    748     if (strcasecmp(type, "ISIS") == 0) {
     1201    if (strncasecmp(type, "ISIS", nameLength) == 0) {
    7491202        return PM_SUBTRACTION_KERNEL_ISIS;
    7501203    }
    751     if (strcasecmp(type, "SPAM") == 0) {
     1204    if (strncasecmp(type, "ISIS_RADIAL", nameLength) == 0) {
     1205        return PM_SUBTRACTION_KERNEL_ISIS_RADIAL;
     1206    }
     1207    if (strncasecmp(type, "HERM", nameLength) == 0) {
     1208        return PM_SUBTRACTION_KERNEL_HERM;
     1209    }
     1210    if (strncasecmp(type, "DECONV_HERM", nameLength) == 0) {
     1211        return PM_SUBTRACTION_KERNEL_DECONV_HERM;
     1212    }
     1213    if (strncasecmp(type, "SPAM", nameLength) == 0) {
    7521214        return PM_SUBTRACTION_KERNEL_SPAM;
    7531215    }
    754     if (strcasecmp(type, "FRIES") == 0) {
     1216    if (strncasecmp(type, "FRIES", nameLength) == 0) {
    7551217        return PM_SUBTRACTION_KERNEL_FRIES;
    7561218    }
    757     if (strcasecmp(type, "GUNK") == 0) {
     1219    if (strncasecmp(type, "GUNK", nameLength) == 0) {
    7581220        return PM_SUBTRACTION_KERNEL_GUNK;
    7591221    }
    760     if (strcasecmp(type, "RINGS") == 0) {
     1222    // note that GUNK has a somewhat different description
     1223    if (strncasecmp(type, "GUNK=ISIS", nameLength) == 0) {
     1224        return PM_SUBTRACTION_KERNEL_GUNK;
     1225    }
     1226    if (strncasecmp(type, "RINGS", nameLength) == 0) {
    7611227        return PM_SUBTRACTION_KERNEL_RINGS;
    7621228    }
     
    7891255    out->bgOrder = in->bgOrder;
    7901256    out->mode = in->mode;
    791     out->numCols = in->numCols;
    792     out->numRows = in->numRows;
     1257    out->xMin = in->xMin;
     1258    out->xMax = in->xMax;
     1259    out->yMin = in->yMin;
     1260    out->yMax = in->yMax;
    7931261    out->solution1 = in->solution1 ? psVectorCopy(NULL, in->solution1, PS_TYPE_F64) : NULL;
    7941262    out->solution2 = in->solution2 ? psVectorCopy(NULL, in->solution2, PS_TYPE_F64) : NULL;
     1263    out->sampleStamps = psMemIncrRefCounter(in->sampleStamps);
    7951264
    7961265    return out;
Note: See TracChangeset for help on using the changeset viewer.