Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
sbailey opened this issue Jan 11, 2025 · 0 comments

Comments

@sbailey
Copy link
Contributor

sbailey commented Jan 11, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant