Index: trunk/archive/conv_variance/Makefile
===================================================================
--- trunk/archive/conv_variance/Makefile	(revision 20210)
+++ trunk/archive/conv_variance/Makefile	(revision 20210)
@@ -0,0 +1,36 @@
+CC = gcc
+PSLIB_CFLAGS = `pslib-config --cflags`
+PSLIB_LDFLAGS = `pslib-config --libs`
+PSMODULES_CFLAGS = `psmodules-config --cflags`
+PSMODULES_LDFLAGS = `psmodules-config --libs`
+CFLAGS = -g -std=gnu99 $(PSMODULES_CFLAGS) $(PSLIB_CFLAGS)
+LDFLAGS = $(PSMODULES_LDFLAGS) $(PSLIB_LDFLAGS)
+
+.PHONY: all clean run_orig run_shift
+
+all: fake phot shift convolve significance
+
+clean:
+	-$(RM) *.o
+
+.c.o:
+	$(CC) -c $(CFLAGS) $<
+
+fake: fake.o
+phot: phot.o
+shift: shift.o
+convolve: convolve.o
+significance: significance.o
+
+run_orig: fake phot
+	./fake
+	psphot -file bright.fits -mask mask.fits -weight weight.fits bright
+	-psphot -file faint.fits -mask mask.fits -weight weight.fits -psf bright.psf faint -trace psphot 6
+	./phot
+
+run_shift: fake shift phot
+	./fake
+	./shift
+	psphot -file bright.shift.fits -mask mask.shift.fits -weight weight.shift.fits bright.shift
+	-psphot -file faint.shift.fits -mask mask.shift.fits -weight weight.shift.fits -psf bright.shift.psf faint.shift -trace psphot 6
+	./phot
Index: trunk/archive/conv_variance/README
===================================================================
--- trunk/archive/conv_variance/README	(revision 20210)
+++ trunk/archive/conv_variance/README	(revision 20210)
@@ -0,0 +1,7 @@
+The following programs were used to investigate the effect of convolution upon
+the variance maps.  They are designed to be used in series:
+fake -> shift -> convolve -> significance -> phot
+with the in-between steps optional.  The file names are hard-coded, so need to
+be updated in order to change the path.  The final result is a comparison
+between the actual significance of a source and the expected significance
+(according to psphot).
Index: trunk/archive/conv_variance/convolve.c
===================================================================
--- trunk/archive/conv_variance/convolve.c	(revision 20210)
+++ trunk/archive/conv_variance/convolve.c	(revision 20210)
@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#define KERNEL_SIZE 10                  // Kernel half-size
+#define KERNEL_SIGMA 2.0                // Gaussian width for kernel
+#define MASK_BAD 0xF0                   // Mask for bad pixels
+#define MASK_POOR 0x0F                  // Mask for poor pixels
+#define POOR_FRAC 0.1                   // Poor fraction
+
+
+static psImage *readImage(const char *name)
+{
+    psFits *fits = psFitsOpen(name, "r");
+    psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0);
+    psFitsClose(fits);
+    return image;
+}
+
+void writeImage(const psImage *image,   // Image to write
+                const char *name        // Name of FITS file
+    )
+{
+    psFits *fits = psFitsOpen(name, "w");
+    psFitsWriteImage(fits, NULL, image, 0, NULL);
+    psFitsClose(fits);
+}
+
+
+int main(int argc, char *argv[])
+{
+    psImage *inBright = readImage("bright.fits");
+    psImage *inFaint = readImage("faint.fits");
+    psImage *inWeight = readImage("weight.fits");
+    psImage *inMask = readImage("mask.fits");
+
+    psImage *subMask = pmSubtractionMask(inMask, NULL, MASK_BAD | MASK_POOR, KERNEL_SIZE, KERNEL_SIZE,
+                                         NAN, true);
+
+    pmSubtractionKernels *kernels = pmSubtractionKernelsPOIS(KERNEL_SIZE, 0, 0.0, PM_SUBTRACTION_MODE_1);
+    kernels->solution1 = psVectorAlloc(kernels->num + 2, PS_TYPE_F64);
+
+    double sum = 0.0;                   // Sum of kernel
+    for (int i = 0; i < kernels->num; i++) {
+        int u = kernels->u->data.S32[i];
+        int v = kernels->v->data.S32[i];
+
+        sum += kernels->solution1->data.F64[i] = 123.45 * exp(-(PS_SQR(u) + PS_SQR(v)) / 0.5 / PS_SQR(KERNEL_SIGMA));
+    }
+
+    int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation
+    kernels->solution1->data.F64[normIndex] = 2.0 * sum;
+    int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background
+    kernels->solution1->data.F64[bgIndex] = 0.0;
+
+    psImage *kernelImage = pmSubtractionKernelImage(kernels, 0.0, 0.0, false);
+    writeImage(kernelImage, "kernel.fits");
+    psFree(kernelImage);
+
+    pmReadout *in1 = pmReadoutAlloc(NULL);
+    pmReadout *in2 = pmReadoutAlloc(NULL);
+    in1->image = psMemIncrRefCounter(inBright);
+    in2->image = psMemIncrRefCounter(inFaint);
+    in2->weight = psMemIncrRefCounter(inWeight);
+
+    pmReadout *out1 = pmReadoutAlloc(NULL);
+    pmReadout *out2 = pmReadoutAlloc(NULL);
+
+    pmSubtractionConvolve(out1, NULL, in1, NULL, subMask, MASK_BAD, MASK_POOR, POOR_FRAC, NULL,
+                          kernels, false, true);
+    pmSubtractionConvolve(out2, NULL, in2, NULL, subMask, MASK_BAD, MASK_POOR, POOR_FRAC, NULL,
+                          kernels, false, true);
+    pmSubtractionBorder(out2->image, out2->weight, out2->mask, KERNEL_SIZE, MASK_BAD);
+
+    psFree(subMask);
+    psFree(kernels);
+
+    psFree(inBright);
+    psFree(inFaint);
+    psFree(inWeight);
+    psFree(inMask);
+
+    psFree(in1);
+    psFree(in2);
+
+    writeImage(out1->image, "bright.conv.fits");
+    writeImage(out2->image, "faint.conv.fits");
+    writeImage(out2->weight, "weight.conv.fits");
+    writeImage(out2->mask, "mask.conv.fits");
+
+    psFree(out1);
+    psFree(out2);
+
+    return PS_EXIT_SUCCESS;
+}
Index: trunk/archive/conv_variance/fake.c
===================================================================
--- trunk/archive/conv_variance/fake.c	(revision 20210)
+++ trunk/archive/conv_variance/fake.c	(revision 20210)
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <pslib.h>
+
+// Add fake sources to an image so we can measure their significance
+#define NUM_SOURCES 1000                // Number of sources to add
+#define SIGMA 3.0                       // Gaussian width of sources
+#define SOURCE_SIZE (3 * (SIGMA))       // Size of source
+#define BRIGHT_PEAK_FLUX 10000          // Peak flux of bright sources
+#define FAINT_PEAK_FLUX 10              // Peak flux of faint sources
+#define NOISE 10                        // Gaussian noise
+#define IMAGE_SIZE 4096                 // Size of image
+
+
+void writeImage(const psImage *image,   // Image to write
+                const char *name        // Name of FITS file
+    )
+{
+    psFits *fits = psFitsOpen(name, "w");
+    psFitsWriteImage(fits, NULL, image, 0, NULL);
+    psFitsClose(fits);
+}
+
+
+void addStar(psImage *image, int xStar, int yStar, float peak)
+{
+    for (int y = yStar - SOURCE_SIZE, v = -SOURCE_SIZE; v <= SOURCE_SIZE; y++, v++) {
+        for (int x = xStar - SOURCE_SIZE, u = -SOURCE_SIZE; u <= SOURCE_SIZE; x++, u++) {
+            image->data.F32[y][x] += peak * expf(-(PS_SQR(u) + PS_SQR(v)) * 0.5 / PS_SQR(SIGMA));
+        }
+    }
+    return;
+}
+
+
+
+int main(int argc, char *argv[])
+{
+    // Mask and weight are easy: they are constant
+    psImage *mask = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_MASK);
+    psImageInit(mask, 0);
+    psImage *weight = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_F32);
+    psImageInit(weight, PS_SQR(NOISE));
+
+    writeImage(mask, "mask.fits");
+    writeImage(weight, "weight.fits");
+    psFree(mask);
+    psFree(weight);
+
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, 0);
+
+    psImage *bright = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_F32);
+    psImage *faint = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_F32);
+
+    // Start with noise
+    for (int y = 0; y < IMAGE_SIZE; y++) {
+        for (int x = 0; x < IMAGE_SIZE; x++) {
+            bright->data.F32[y][x] = psRandomGaussian(rng) * NOISE;
+            faint->data.F32[y][x] = psRandomGaussian(rng) * NOISE;
+        }
+    }
+
+    // Add stars
+    FILE *stars = fopen("fake_stars.dat", "w");
+    for (int i = 0; i < NUM_SOURCES; i++) {
+        // Position for stars
+        int xStar = SOURCE_SIZE + (IMAGE_SIZE - 2 * SOURCE_SIZE - 1) * psRandomUniform(rng);
+        int yStar = SOURCE_SIZE + (IMAGE_SIZE - 2 * SOURCE_SIZE - 1) * psRandomUniform(rng);
+        fprintf(stars, "%d %d\n", xStar, yStar);
+
+        addStar(bright, xStar, yStar, BRIGHT_PEAK_FLUX);
+        addStar(faint, xStar, yStar, FAINT_PEAK_FLUX);
+    }
+    fclose(stars);
+
+    psFree(rng);
+
+    writeImage(bright, "bright.fits");
+    writeImage(faint, "faint.fits");
+
+    psFree(bright);
+    psFree(faint);
+
+    return PS_EXIT_SUCCESS;
+}
Index: trunk/archive/conv_variance/phot.c
===================================================================
--- trunk/archive/conv_variance/phot.c	(revision 20210)
+++ trunk/archive/conv_variance/phot.c	(revision 20210)
@@ -0,0 +1,129 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#define NUM_BG 1000000                  // Number of random background measurements to make
+#define SIGMA 3.0                       // Gaussian width for photometry
+#define SOURCE_SIZE (3 * SIGMA)         // Size of source for photometry
+
+static psImage *readImage(const char *name)
+{
+    psFits *fits = psFitsOpen(name, "r");
+    psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0);
+    psFitsClose(fits);
+    return image;
+}
+
+
+double measure(const psImage *image, const psImage *mask, psMaskType maskVal, double bg, int xStar, int yStar)
+{
+    double sumGauss = 0.0;
+    double sumFluxGauss = 0.0;
+    for (int y = yStar - SOURCE_SIZE, v = -SOURCE_SIZE; v <= SOURCE_SIZE; y++, v++) {
+        for (int x = xStar - SOURCE_SIZE, u = -SOURCE_SIZE; u <= SOURCE_SIZE; x++, u++) {
+            if (mask->data.PS_TYPE_MASK_DATA[y][x] & maskVal) {
+                continue;
+            }
+            if (!isfinite(image->data.F32[y][x])) {
+                continue;
+            }
+            float gauss = expf(-(PS_SQR(u) + PS_SQR(v)) * 0.5 / PS_SQR(SIGMA));
+
+            sumGauss += gauss;
+            sumFluxGauss += gauss * (image->data.F32[y][x] - bg);
+        }
+    }
+
+    return sumFluxGauss / sumGauss;
+}
+
+
+
+int main(int argc, char *argv[])
+{
+    psImage *image = readImage("faint.conv.fits");
+    psImage *mask = readImage("mask.conv.fits");
+    psImage *significance = readImage("faint.sig.fits");
+
+    assert(image->type.type == PS_TYPE_F32);
+    assert(mask->type.type == PS_TYPE_MASK);
+
+    int numCols = image->numCols, numRows = image->numRows;
+    psMaskType maskVal = 0;
+
+    psStats *bgStats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, 0);
+    psImageBackground(bgStats, NULL, image, mask, maskVal, rng);
+    double bg = bgStats->robustMedian;
+    assert(isfinite(bg));
+
+    psArray *stars = psVectorsReadFromFile("fake_stars.dat", "%f %f");
+    psVector *xStars = stars->data[0], *yStars = stars->data[1];
+    int number = xStars->n;
+    psVector *fluxStars = psVectorAlloc(number, PS_TYPE_F64);
+    psVector *sigStars = psVectorAlloc(number, PS_TYPE_F64);
+
+    int numStars = 0;
+    for (int i = 0; i < number; i++) {
+        int xStar = xStars->data.F32[i] + 0.5;
+        int yStar = yStars->data.F32[i] + 0.5;
+
+        if (xStar < SOURCE_SIZE || xStar > numCols - SOURCE_SIZE - 1 ||
+            yStar < SOURCE_SIZE || yStar > numRows - SOURCE_SIZE - 1) {
+            continue;
+        }
+
+        if (significance->data.F32[yStar][xStar] <= 0.0 || !isfinite(significance->data.F32[yStar][xStar])) {
+            continue;
+        }
+
+        float flux = measure(image, mask, maskVal, bg, xStar, yStar);
+        if (!isfinite(flux)) {
+            continue;
+        }
+
+        fluxStars->data.F64[numStars] = flux;
+        sigStars->data.F64[numStars] = significance->data.F32[yStar][xStar];
+        numStars++;
+    }
+
+    psVector *fluxBG = psVectorAlloc(NUM_BG, PS_TYPE_F64);
+    int numBG = 0;
+    double meanBG = 0.0;
+    for (int i = 0; i < NUM_BG; i++) {
+        int xBG = SOURCE_SIZE + (numCols - 2 * SOURCE_SIZE - 1) * psRandomUniform(rng);
+        int yBG = SOURCE_SIZE + (numRows - 2 * SOURCE_SIZE - 1) * psRandomUniform(rng);
+
+        float flux = measure(image, mask, maskVal, bg, xBG, yBG);
+
+        if (!isfinite(flux)) {
+            continue;
+        }
+
+        fluxBG->data.F64[numBG] = flux;
+        meanBG += flux;
+        numBG++;
+    }
+    meanBG /= numBG;
+
+    psFree(image);
+    psFree(mask);
+    psFree(significance);
+
+    double stdevBG = 0.0;
+    for (int i = 0; i < numBG; i++) {
+        stdevBG += PS_SQR(fluxBG->data.F64[i] - meanBG);
+    }
+    stdevBG = sqrt(stdevBG / numBG);
+
+    double sum = 0.0;
+    for (int i = 0; i < numStars; i++) {
+        double actual = fabs(fluxStars->data.F64[i]) / stdevBG;
+        double expected = sqrt(sigStars->data.F64[i]);
+        sum += actual/expected;
+    }
+    double meanRatio = sum / numStars;
+
+    printf("%d %d %lf %lf %lf %lf\n", numBG, numStars, bg, meanBG, stdevBG, meanRatio);
+
+    return PS_EXIT_SUCCESS;
+}
Index: trunk/archive/conv_variance/shift.c
===================================================================
--- trunk/archive/conv_variance/shift.c	(revision 20210)
+++ trunk/archive/conv_variance/shift.c	(revision 20210)
@@ -0,0 +1,184 @@
+#include <stdio.h>
+#include <math.h>
+#include <pslib.h>
+
+#define IMAGE_SIZE 4096                 // Size of output image
+#define INTERPOLATION PS_INTERPOLATE_BICUBE // Interpolation kernel
+#define SHIFT_X 0.1                     // Number of pixels to shift in x
+#define SHIFT_Y 0.2                     // Number of pixels to shift in y
+#define SCALE (2.0 * M_LN2)             // Scale difference
+#define MASK_BAD 0xF0                   // Mask for bad pixels
+#define MASK_POOR 0x0F                  // Mask for poor pixels
+#define POOR_FRAC 0.1                   // Poor fraction
+#define ROTATION (30 / 180 * M_PI)      // Rotation
+
+// ( xOut ) =  scale * ( cos  -sin ) ( xIn ) + ( xShift )
+// ( yOut )            ( sin   cos ) ( yIn )   ( yShift )
+
+
+static inline void transformIn(float *xIn, float *yIn, // Coordinates in input image
+                               int xOut, int yOut // Coordinates in output image
+    )
+{
+    float xShift = (xOut - SHIFT_X) / SCALE;
+    float yShift = (yOut - SHIFT_Y) / SCALE;
+
+    *xIn = xShift * cos(ROTATION) + yShift * sin(ROTATION);
+    *yIn = - xShift * sin(ROTATION) + yShift * cos(ROTATION);
+    return;
+}
+
+static inline void transformOut(float *xOut, float *yOut, // Coordinates in output image
+                                int xIn, int yIn // Coordinates in input image
+    )
+{
+    *xOut = SCALE * (xIn * cos(ROTATION) - yIn * sin(ROTATION)) + SHIFT_X;
+    *yOut = SCALE * (xIn * sin(ROTATION) + yIn * cos(ROTATION)) + SHIFT_Y;
+    return;
+}
+
+static psImage *readImage(const char *name)
+{
+    psFits *fits = psFitsOpen(name, "r");
+    psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0);
+    psFitsClose(fits);
+    return image;
+}
+
+void writeImage(const psImage *image,   // Image to write
+                const char *name        // Name of FITS file
+    )
+{
+    psFits *fits = psFitsOpen(name, "w");
+    psFitsWriteImage(fits, NULL, image, 0, NULL);
+    psFitsClose(fits);
+}
+
+int main(int argc, char *argv[])
+{
+    psImage *inBright = readImage("bright.fits");
+    psImage *inFaint = readImage("faint.fits");
+    psImage *inWeight = readImage("weight.fits");
+    psImage *inMask = readImage("mask.fits");
+
+    psImage *outBright = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_F32);
+    psImage *outFaint = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_F32);
+    psImage *outWeight = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_F32);
+    psImage *outMask = psImageAlloc(IMAGE_SIZE, IMAGE_SIZE, PS_TYPE_MASK);
+
+    int inNumCols = inBright->numCols, inNumRows = inBright->numRows; // Size of input image
+
+    // Transform forward
+    {
+        psImageInterpolateOptions *interp1 = psImageInterpolateOptionsAlloc(INTERPOLATION, inBright,
+                                                                            NULL, inMask, 0xFF, NAN, NAN,
+                                                                            MASK_BAD, MASK_POOR, POOR_FRAC);
+        psImageInterpolateOptions *interp2 = psImageInterpolateOptionsAlloc(INTERPOLATION, inFaint,
+                                                                            inWeight, inMask, 0xFF, NAN, NAN,
+                                                                            MASK_BAD, MASK_POOR, POOR_FRAC);
+
+        for (int yOut = 0; yOut < IMAGE_SIZE; yOut++) {
+            for (int xOut = 0; xOut < IMAGE_SIZE; xOut++) {
+                float xIn, yIn;
+                transformIn(&xIn, &yIn, xOut + 0.5, yOut + 0.5);
+                xIn += 0.5;
+                yIn += 0.5;
+
+                if (xIn < 0 || xIn >= inNumCols || yIn < 0 || yIn >= inNumRows) {
+                    outBright->data.F32[yOut][xOut] = NAN;
+                    outFaint->data.F32[yOut][xOut] = NAN;
+                    outWeight->data.F32[yOut][xOut] = NAN;
+                    outMask->data.PS_TYPE_MASK_DATA[yOut][xOut] = MASK_BAD;
+                    continue;
+                }
+
+                double brightValue, faintValue, weightValue;
+                psMaskType maskValue = inMask->data.PS_TYPE_MASK_DATA[(int)yIn][(int)xIn]; // Value of mask
+                psImageInterpolate(&brightValue, NULL, NULL, xIn, yIn, interp1);
+                psImageInterpolate(&faintValue, &weightValue, &maskValue, xIn, yIn, interp2);
+
+                outBright->data.F32[yOut][xOut] = brightValue / SCALE;
+                outFaint->data.F32[yOut][xOut] = faintValue / SCALE;
+                outWeight->data.F32[yOut][xOut] = weightValue / PS_SQR(SCALE);
+                outMask->data.PS_TYPE_MASK_DATA[yOut][xOut] = maskValue;
+            }
+        }
+
+        psFree(interp1);
+        psFree(interp2);
+    }
+
+    int outNumCols = outBright->numCols, outNumRows = inBright->numRows; // Size of output image
+
+    // Transform back
+    {
+        psImageInterpolateOptions *interp1 = psImageInterpolateOptionsAlloc(INTERPOLATION, outBright,
+                                                                            NULL, outMask, 0xFF, NAN, NAN,
+                                                                            MASK_BAD, MASK_POOR, POOR_FRAC);
+        psImageInterpolateOptions *interp2 = psImageInterpolateOptionsAlloc(INTERPOLATION, outFaint,
+                                                                            outWeight, outMask, 0xFF,
+                                                                            NAN, NAN, MASK_BAD, MASK_POOR,
+                                                                            POOR_FRAC);
+
+        for (int yIn = 0; yIn < inNumRows; yIn++) {
+            for (int xIn = 0; xIn < inNumCols; xIn++) {
+                float xOut, yOut;
+                transformOut(&xOut, &yOut, xIn + 0.5, yIn + 0.5);
+                xOut += 0.5;
+                yOut += 0.5;
+
+                if (xOut < 0 || xOut >= outNumCols || yOut < 0 || yOut >= outNumRows) {
+                    inBright->data.F32[yIn][xIn] = NAN;
+                    inFaint->data.F32[yIn][xIn] = NAN;
+                    inWeight->data.F32[yIn][xIn] = NAN;
+                    inMask->data.PS_TYPE_MASK_DATA[yIn][xIn] = MASK_BAD;
+                    continue;
+                }
+
+                double brightValue, faintValue, weightValue;
+                psMaskType maskValue = inMask->data.PS_TYPE_MASK_DATA[(int)yOut][(int)xOut]; // Value of mask
+                psImageInterpolate(&brightValue, NULL, NULL, xOut, yOut, interp1);
+                psImageInterpolate(&faintValue, &weightValue, &maskValue, xOut, yOut, interp2);
+
+                inBright->data.F32[yIn][xIn] = brightValue * SCALE;
+                inFaint->data.F32[yIn][xIn] = faintValue * SCALE;
+                inWeight->data.F32[yIn][xIn] = weightValue * PS_SQR(SCALE);
+                inMask->data.PS_TYPE_MASK_DATA[yIn][xIn] = maskValue;
+            }
+        }
+
+        psFree(interp1);
+        psFree(interp2);
+    }
+
+    writeImage(inBright, "bright.shift.fits");
+    writeImage(inFaint, "faint.shift.fits");
+    writeImage(inWeight, "weight.shift.fits");
+    writeImage(inMask, "mask.shift.fits");
+
+    psFree(inBright);
+    psFree(inFaint);
+    psFree(inWeight);
+    psFree(inMask);
+
+    psFree(outBright);
+    psFree(outFaint);
+    psFree(outWeight);
+    psFree(outMask);
+
+#if 0
+
+    psArray *stars = psVectorsReadFromFile("fake_stars.dat", "%d %d");
+    psVector *x = stars->data[0], *y = stars->data[1]; // Star coordinates
+    FILE *starFile = fopen("fake_stars.shift.dat", "w");
+    int num = x->n;                     // Number of stars
+    for (int i = 0; i < num; i++) {
+        float xOut, yOut;
+        transformOut(&xOut, &yOut, x->data.S32[i], y->data.S32[i]);
+        fprintf(starFile, "%f %f\n", xOut, yOut);
+    }
+    fclose(starFile);
+#endif
+
+    return PS_EXIT_SUCCESS;
+}
Index: trunk/archive/conv_variance/significance.c
===================================================================
--- trunk/archive/conv_variance/significance.c	(revision 20210)
+++ trunk/archive/conv_variance/significance.c	(revision 20210)
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#define SIGMA 3.0                       // Gaussian width
+#define NUM_SIGMA 3                     // Size of convolution
+
+static psImage *readImage(const char *name)
+{
+    psFits *fits = psFitsOpen(name, "r");
+    psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0);
+    psFitsClose(fits);
+    return image;
+}
+
+void writeImage(const psImage *image,   // Image to write
+                const char *name        // Name of FITS file
+    )
+{
+    psFits *fits = psFitsOpen(name, "w");
+    psFitsWriteImage(fits, NULL, image, 0, NULL);
+    psFitsClose(fits);
+}
+
+int main(int argc, char *argv[])
+{
+    psImage *bright = readImage("bright.conv.fits");
+    psImage *faint = readImage("faint.conv.fits");
+    psImage *weight = readImage("weight.conv.fits");
+    psImage *mask = readImage("mask.conv.fits");
+
+    // smooth the image, applying the mask as we go
+    psImageSmoothMaskF32(bright, mask, 0xFF, SIGMA, NUM_SIGMA);
+    psImageSmoothMaskF32(faint, mask, 0xFF, SIGMA, NUM_SIGMA);
+    psImageSmoothMaskF32(weight, mask, 0xFF, SIGMA/M_SQRT2, NUM_SIGMA);
+
+    float factor = 4.0 * M_PI * PS_SQR(SIGMA);
+
+    for (int j = 0; j < bright->numRows; j++) {
+        for (int i = 0; i < bright->numCols; i++) {
+            if (mask->data.PS_TYPE_MASK_DATA[j][i]) {
+                bright->data.F32[j][i] = 0.0;
+                faint->data.F32[j][i] = 0.0;
+            } else {
+                bright->data.F32[j][i] = factor * PS_SQR(bright->data.F32[j][i]) /
+                    weight->data.F32[j][i];
+                faint->data.F32[j][i] = factor * PS_SQR(faint->data.F32[j][i]) /
+                    weight->data.F32[j][i];
+            }
+        }
+    }
+
+    psFree(weight);
+    psFree(mask);
+
+    writeImage(bright, "bright.sig.fits");
+    writeImage(faint, "faint.sig.fits");
+
+    psFree(bright);
+    psFree(faint);
+
+    return PS_EXIT_SUCCESS;
+}
