XMM-Newton Science Analysis System
asmooth (asmooth-2.32.1) [22.0.0-9173c7d25-20250127]
Algorithm
read parameters;
read --inset;
if (--withoutmaskset) {
read --outmaskset;
} else {
outMask = TRUE;
}
if (--withweightset) {
read --weightset;
} else {
weightImage = 1;
}
weightImage = weightImage / maxval(weightImage)
(xyLimits) = &findWidthOfBlackBorder(inImage);
inImage = &cutBorder(inImage, xyLimits);
outMask = &cutBorder(outMask, xyLimits);
weightImage = &cutBorder(weightImage, xyLimits);
if (--withexpimageset) {
read --expimageset;
expImage = &cutBorder(expImage, xyLimits);
where(expImage>0) {
inImage = inImage / expImage;
} elsewhere {
inImage = 0;
weightImage = 0;
}
}
# Choice of smoothing type:
if (--smoothstyle='simple') {
if (--convolverstyle='gaussian') {
convolvers(1) = &makeGaussianConvolver;
} elsif(--convolverstyle='tophat') {
convolvers(1) = &makeTopHatConvolver;
} elsif(--convolverstyle='squarebox') {
convolvers(1) = &makeBoxConvolver;
}
} elsif(--smoothstyle='template') {
(indexImage, convolvers) = &makeConvolversFromTemplate;
} elsif(--smoothstyle='withset') {
(indexImage, convolvers) = &readConvolversFromSets;
} elsif(--smoothstyle='adaptive') {
# Adaptive smoothing calculation of convolvers:
if (--readvarianceset) {
read --invarianceset;
varianceImage = &cutBorder(varianceImage, xyLimits);
} else {
if (--withexpimageset) {
varianceImage = inImage * expMapImage;
# Because inImage has already been divided by expMapImage, and we
# need to reverse that.
} else {
varianceImage = inImage;
}
}
if (--withexpimageset) {
if (--expmapuse='samesnr') {
where(expImage>0) {
varianceImage = varianceImage / expImage / expImage;
} elsewhere {
varianceImage = 0;
}
} else {
where(expImage>0) {
varianceImage = varianceImage / expImage / maxval(expImage);
} elsewhere {
varianceImage = 0;
}
}
}
convolvers = &calculateConvolverLibrary;
where(outMask) {
indexImage = 1;
} elsewhere {
indexImage = 0;
}
smoothedImage = 0.0;
rmsSmoothedImage = 0.0;
i = 1;
smoothedImage = smoothedImage + &patchSmooth(convolvers(i)
, weightImage, mask=(indexImage==i));
rmsSmoothedImage = rmsSmoothedImage + sqrt(&patchSmooth(convolvers**2(i)
, weightImage, mask=(indexImage==i)));
where(indexImage == i) {
where(! failureMask) {
where(rmsSmoothedImage>0 && smoothedImage>0) {
bestSnr = smoothedImage / rmsSmoothedImage;
where(bestSnr > desiredSnr) {
# This means that we are still
# smoothing too hard, and need to try this pixel again with a
# narrower gaussian. Therefore increment the index:
indexImage = i + 1;
}
}
}
}
foreach(i = 2, numConvolvers) {
secondBestSnr = bestSnr;
smoothedImage = smoothedImage + &patchSmooth(convolvers(i)
, weightImage, mask=(indexImage==i));
rmsSmoothedImage = rmsSmoothedImage + sqrt(&patchSmooth(convolvers**2(i)
, weightImage, mask=(indexImage==i)));
where(indexImage == i) {
where(failureMask) {
indexImage = i - 1; # This pixel didn't fail for the previous
# value of index (=> next larger gaussian), otherwise it would
# never have got here. Hence we will drop the index value for
# this pixel back to this last known 'good' value.
} elsewhere {
where(rmsSmoothedImage>0 && smoothedImage>0) {
bestSnr = smoothedImage / rmsSmoothedImage;
} elsewhere {
bestSnr = 0;
}
where(bestSnr > desiredSnr) {
# This means that we are still
# smoothing too hard, and need to try this pixel again with a
# narrower gaussian. Therefore increment the index:
indexImage = i + 1;
} elsewhere { # go to the value that gave the best SNR:
where(abs(secondBestSnr-desiredSnr)<abs(bestSnr-desiredSnr)) {
indexImage = i - 1;
# Otherwise, leave indexImage at i.
}
}
}
}
}
where(indexImage > numConvolvers) {indexImage = numConvolvers;}
}
# Do the smoothing:
smoothedImage = 0.0;
where(outMask) {smoothedImage = inImage;}
failureMask = FALSE;
foreach(i = 1, numConvolvers) {
patchMask = outMask && (indexImage == i);
# The actual convolution:
foreach(xi = outStartX, outFinisX) {
foreach(yi = outStartY, outFinisY) {
next if (! outMask(xi, yi));
summ = 0.0;
weight = 0.0;
foreach(cxi = 1, convolverXSize) {
xxi = (cxi - 1 - halfConvolverXSize) - xi;
foreach(cyi = 1, convolverYSize) {
yyi = (cyi - 1 - halfConvolverYSize) - yi;
next if (weightImage(xxi, yyi) <= 0.0);
summ = summ + convolver(cxi, cyi) * inImage(xxi, yyi);
weight = weight + convolver(cxi, cyi) * weightImage(xxi, yyi);
}
}
if (weight >= minAllowedWeight) {
outImage(xi, yi) = summ * norm / weight;
} else {
outImage(xi, yi) = 0.0;
failureMask(xi, yi) = TRUE; # indicates those pixels where the
# weight is too small.
}
}
}
}
# Outputs:
if (--writevarianceset) {
outVarianceImage = &calculateOutVariance(inImage, weightImage, outMask
, indexImage, convolvers);
outVarianceImage = &restoreBlankBorder(outVarianceImage, xyLimits);
write to --outvarianceset;
}
where(failureMask) {smoothedImage = 0;}
if (--writebadmaskset) {
failureMask = &restoreBlankBorder(failureMask, xyLimits);
write to --badmaskset;
}
if (--smoothstyle='adaptive') {
if (--writetemplateset) {
templateImage = &calculateTemplateImage;
templateImage = &restoreBlankBorder(templateImage, xyLimits);
write to --outtemplateset;
}
if (--writeconvolvers) {
indexImage = &restoreBlankBorder(indexImage, xyLimits);
write indexImage to --outindeximageset;
write convolvers to --outconvolversset;
}
}
if (--withexpimageset) {
if (--remultiply) {
smoothedImage = smoothedImage * expMapImage;
}
}
smoothedImage = &restoreBlankBorder(smoothedImage, xyLimits);
write to --outset;
XMM-Newton SOC -- 2025-01-27