The golden rule for spatial region filtering is:
Each photon will be counted once, and no photon will be counted more than once.
This means that we must be careful about boundary conditions. For example, if a circle is contained in an annulus such that the inner radius of the annulus is the same as the radius of the circle, then photons on that boundary must always be assigned to one or the other region. That is, the number of photons in both regions must equal the sum of the number of photons in each region taken separately. With this in mind, the rules for determining whether a boundary image pixel or table row are assigned to a region are defined below.
Because row boundaries are calculated differently from image boundaries, certain programs will give different results when filtering the same region file. In particular, fundisp/funtable (which utilize analytic row filtering) perform differently from funcnts (which performs image filtering, even on tables).
You will sometimes notice a discrepancy between running funcnts on an binary table file and running fundisp on the same file with the same filter. For example, consider the following:
fundisp test1.fits"[box(4219,3887,6,6,0)]" | wc 8893 320148 3752846Since fundisp has a 2-line header, there are actually 8891 photons that pass the filter. But then run funtable and select only the rows that pass this filter, placing them in a new file:
./funtable test1.fits"[box(4219,3887,6,6,0)]" test2.fitsNow run funcnts using the original filter on the derived file:
./funcnts test2.fits "physical; box(4219,3887,6,6,0)" [... lot of processed output ...] # the following source and background components were used: source region(s) ---------------- physical; box(4219,3887,6,6,0) reg counts pixels ---- ------------ --------- 1 7847.000 36There are 1044 rows (events) that pass the row filter in fundisp (or funtable) but fail to make it through funcnts. Why?
The reason can be traced to how analytic row filtering (fundisp, funtable) differs from integerized pixel filtering(funcnts, funimage). Consider the region:
box(4219,3887,6,6,0)Analytically (i.e., using row filtering), positions will pass this filter successfully if:
4216 <= x <= 4222 3884 <= y <= 3890For example, photons with position values of x=4216.4 or y=3884.08 will pass.
Integerized image filtering is different in that the pixels that will pass this filter have centers at:
x = 4217, 4218, 4219, 4220, 4221, 4222 y = 3885, 3886, 3887, 3888, 3889, 3890Note that there are 6 pixels in each direction, as specified by the region. That means that positions will pass the filter successfully if:
4217 <= (int)x <= 4222 3885 <= (int)y <= 3890Photons with position values of x=4216.4 or y=3884.08 will NOT pass.
Note that the position values are integerized, in effect, binned into image values. This means that x=4222.4 will pass this filter, but not the analytic filter above. We do this to maintain the design goal that either all counts in a pixel are included in an integerized filter, or else none are included.
[It could be argued that the correct photon limits for floating point row data really should be:
4216.5 <= x <= 4222.5 3884.5 <= y <= 3890.5since each pixel extends for .5 on either side of the center. We chose to the maintain integerized algorithm for all image-style filtering so that funcnts would give the exact same results regardless of whether a table or a derived non-blocked binned image is used.]