GNU Astronomy Utilities

2.8.6 Accounting for non-exposed pixels

At the end of Pointings that account for sky curvature we were able to maximize the region of same depth in our stack. But we noticed that issues like strong vignetting can create discontinuity in our final stacked data product. In this section, we’ll review the steps to account for such effects. Generally, the full area of a detector is not usually used in the final stack. Vignetting is one cause, it can be due to other problems also. For example due to baffles in the optical path (to block stray light), or large regions of bad (unusable or “dead”) pixels that may be in any place on the detector77.

Without accounting for these pixels that do not receive any light, the deep area we measured in the sections above will be over-estimated. In this sub-section, let’s review the necessary additions to account for such artifacts. Therefore, before continuing, please make sure that you have already read and applied the steps of the previous sections (this sub-section builds upon that section).

Vignetting strongly depends on the optical design of the instrument you are using. It can be a constant number of pixels on all the edges the detector, or it can have a more complex shape. For example on cameras that have multiple detectors on the field of view, in this case, the regions to exclude on each detector can be very different and will not be symmetric!

Therefore, within Gnuastro’s astscript-pointing-simulate script there is no parameter for pre-defined vignetting shapes. Instead, you should define a mask that you can apply on each exposure through the provided hook (--hook-warp-before; recall that we previously used another hook in Larger steps sizes for better calibration). Through the mask, you are free to set any vignetted or bad pixel to NaN (thus ignoring them in the stack) and applying it in any way that best suites your instrument and detector.

The mask image should be same size as the reference image, but only containing two values: 0 or 1. Pixels in each exposure that have a value of 1 in the mask will be set to NaN before the stacking process and will not contribute to the final stack. Ideally, you can use the master flat field image of the previous reductions to create this mask: any pixel that has a low sensitivity in the master flat (for any reason) can be set to 1, and the rest of the pixels to 0.

Let’s build a simple mask by assuming that we only have strong vignetting that is affecting the outer 30 arc seconds of the individual exposures. To mask the outer edges of an image we can use Gnuastro’s Arithmetic program; and in particular, the indexonly operator. To learn more about this operator, see Size and position operators.

But before doing that, we need convert this angular distance to pixels on the detector. In Pointing pattern design, we used an undersampled version of the input image, so we should do this conversion on that image:

$ margin_arcsec=30
$ margin_pix=$(astfits input/ref.fits --pixelscale --quiet \
                     | awk '{print int('$margin_arcsec'/($1*3600))}')
$ echo $margin_pix

To build the mask, we can now follow the recipe under “Image: masking margins” of the index operator in Arithmetic (for a full description of what this command is doing78, see Size and position operators). Finally, in the last command, let’s look at the mask image in the “red” color map of DS9 (which will shows the thin 1-valued pixels to mask on the border more clearly).

$ width=$(astfits  input/ref.fits --keyvalue=NAXIS1 -q)
$ height=$(astfits input/ref.fits --keyvalue=NAXIS2 -q)

$ astarithmetic input/ref.fits indexonly     set-i \
                $width         uint16        set-w \
                $height        uint16        set-h \
                $margin_pix    uint16        set-m \
                i w %          uint16        set-X \
                i w /          uint16        set-Y \
                X m lt         X w m - gt       or \
                Y m lt         Y h m - gt       or \
                or --output=build/mask.fits

$ astscript-fits-view build/mask.fits --ds9extra="-cmap red"

We are now ready to run the main pointing simulate script. With the command below, we will use the --hook-warp-before to apply this mask on the image of each exposure just before warping. The concept of this hook is very similar to that of --hook-warp-after in Pointing pattern design. As the name suggests, this hook is applied “before” the warping. The input to the command given to this hook should be called with $EXPOSURE and the output should be called with $TOWARP. With the second command, let’s compare the two outputs:

$ astscript-pointing-simulate build/pointing-on-sky.fits \
           --output=build/stack-with-trim.fits --img=input/ref.fits \
           --center=$center_ra,$center_dec --width=2 \
           --hook-warp-before='astarithmetic $EXPOSURE build/mask.fits \
                                             nan where -g1 -o$TOWARP'

$ astscript-fits-view build/stack.fits build/stack-with-trim.fits

As expected, due to the smaller area of the detector that is exposed to photons, the regions with 4 exposures have become much thinner and on the bottom, it has been removed. To have contiguous depth in the deeper region, use this new call in your script and decrease the step_arcmin=41.

You can use the same command on a mask that is created in any way and as realistic as possible. More generically, you can use the before and after hooks for any other operation; for example to insert objects from a catalog using MakeProfiles as well as adding noise as we did in Pointing pattern design.

Therefore it is also good to add the mask and its application in your script. This should be pretty easy by now (following Script with pointing simulation steps so far and the “Script update 1” box of Pointings that account for sky curvature). So we will leave this as an exercise.



For an example of bad pixels over the detector, see Figures 4 and 6 of Instrument Science Report WFC3 2019-03 by the Space Telescope Science Institute.


By learning how this command works, you can customize it. For example, to mask different widths along each separate edge: it often happens that the left/right or top/bottom edges are affected differently by vignetting.