fitsio icon indicating copy to clipboard operation
fitsio copied to clipboard

filtering by integer bitwise mask when reading bintable not working for large ints

Open sbailey opened this issue 11 months ago • 0 comments

I'm trying to filter on a bitmask while reading a binary table, e.g. following https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/node102.html .

It appears that (c)fitsio is treating my integer mask as a float, requiring it to be cast back as an int, which then loses information for the lowest bits when high bits are set because of the int -> float -> int round trip.

Example:

import numpy as np
import fitsio

# create a mask where all bits up to bit n are set
mask = np.array([2**n-1 for n in range(1,64)])
x = np.arange(len(mask))

data = np.core.records.fromarrays([mask,x], names=('mask', 'x'))

filename = 'blat.fits'
fitsio.write(filename, data, clobber=True)

with fitsio.FITS(filename) as fx:

    # Trying to use 'mask' directly results in
    #   OSError: FITSIO status = 431: syntax error in expression
    #   Bitwise operations with incompatible types; only (bit OP bit) and (int OP int)
    # w = fx[1].where('(mask & 1) == 1')

    # Cast to (int) avoids error, but misses largest entries
    w1 = fx[1].where('((int)mask & 1) == 1')

w2 = np.where((mask & 1) == 1)[0]   # w1 should be the same as this but isn't
w3 = np.where((mask.astype(float).astype(int) & 1) == 1)[0]  # w1 matches this instead

print(f'{w1=}')
print(f'{w2=}')
print(f'{w3=}')

Results:

w1=array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
       34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
       51, 52])
w2=array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
       34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
       51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62])
w3=array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
       34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
       51, 52])

Note that w1 (derived with fitsio.FITS.where) is missing the largest masks, but it matches w3 which is derived by casting mask to float and back to int before doing the bitwise masking operation.

I'm using fitsio 1.2.1.

sbailey avatar Jan 11 '25 00:01 sbailey