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

Fix/data cube #291

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions banzai/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ def __init__(self, data: Union[np.array, Table], meta: Union[dict, fits.Header],

def _validate_mask(self, mask):
if mask is not None:
if mask.shape != self.data.shape:
raise ValueError('Mask must have the same dimensions as the data')
if len(mask.shape) != len(self.data.shape):
raise ValueError('Mask has different number of dimensions from the data.')

def _init_array(self, array: np.array = None, dtype: Type = None):
if not self.memmap:
if not self.memmap and array is not None:
return array
file_handle = tempfile.NamedTemporaryFile('w+b')
if array is None:
shape = self.data.shape
shape = np.array(self.data).shape
if dtype is None:
dtype = self.data.dtype
array = np.zeros(shape, dtype=dtype)
if array.size > 0:
if array.size > 0 and self.memmap:
file_handle = tempfile.NamedTemporaryFile('w+b')
memory_mapped_array = np.memmap(file_handle, shape=array.shape, dtype=array.dtype, mode='readwrite')
memory_mapped_array.ravel()[:] = array.ravel()[:]
self._file_handles.append(file_handle)
Expand All @@ -49,7 +49,10 @@ def _init_array(self, array: np.array = None, dtype: Type = None):

def add_mask(self, mask: np.array):
self._validate_mask(mask)
self.mask = self._init_array(mask)
self.mask = self._init_array(dtype=np.uint8)
overlap_region = tuple(slice(None, min(mask_shape, data_shape), 1)
for mask_shape, data_shape in zip(mask.shape, self.data.shape))
self.mask[overlap_region] = mask[overlap_region]

def __del__(self):
for handle in self._file_handles:
Expand Down
28 changes: 20 additions & 8 deletions banzai/lco.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ def open(self, file_info, runtime_context) -> Optional[ObservationFrame]:
for hdu in fits_hdu_list:
if hdu.data is None:
hdu_list.append(HeaderOnly(meta=hdu.header))
elif len(hdu.data.shape) > 2:
for munged_hdu in self._munge_data_cube(hdu):
hdu_list.append(munged_hdu)
else:
hdu_list.append(self.data_class(data=hdu.data, meta=hdu.header, name=hdu.header.get('EXTNAME')))
else:
Expand Down Expand Up @@ -401,6 +404,7 @@ def open(self, file_info, runtime_context) -> Optional[ObservationFrame]:
associated_data[associated_extension['NAME']] = None
if len(hdu.data.shape) > 2:
hdu_list += self._munge_data_cube(hdu)
break
# update datasec/trimsec for fs01
if hdu.header.get('INSTRUME') == 'fs01':
self._update_fs01_sections(hdu)
Expand Down Expand Up @@ -553,8 +557,10 @@ def _munge_data_cube(hdu):
:return: List CCDData objects
"""
# The first extension gets to be a header only object
primary_hdu_gain = hdu.header['GAIN']
gain_comment = hdu.header.comments['GAIN']
hdu.header.remove('GAIN')
hdu_list = [HeaderOnly(meta=hdu.header)]

# We need to properly set the datasec and detsec keywords in case we didn't read out the
# middle row (the "Missing Row Problem").
sinistro_datasecs = {'missing': ['[1:2048,1:2048]', '[1:2048,1:2048]',
Expand All @@ -566,18 +572,24 @@ def _munge_data_cube(hdu):
'full': ['[1:2048,1:2048]', '[4096:2049,1:2048]',
'[4096:2049,4096:2049]', '[1:2048,4096:2049]']}
for i in range(hdu.data.shape[0]):
gain = eval(hdu.header['GAIN'])[i]
if isinstance(primary_hdu_gain, str):
gain = eval(primary_hdu_gain)[i]
else:
gain = primary_hdu_gain
if hdu.data.shape[1] > 2048:
mode = 'full'
else:
mode = 'missing'
datasec = sinistro_datasecs[mode][i]
detsec = sinistro_detsecs[mode][i]
header = {'BIASSEC': ('[2055:2080,1:2048]', '[binned pixel] Overscan Region'),
'GAIN': (gain, hdu.header.comments['GAIN']),
'DATASEC': (datasec, '[binned pixel] Data section'),
'DETSEC': (detsec, '[unbinned pixel] Detector section'),
'CCDSUM': (hdu.header['CCDSUM'], hdu.header.comments['CCDSUM'])}
header = fits.Header()
if hdu.data is not None and hdu.data.dtype == np.uint16:
hdu.data = hdu.data.astype(np.float64)
for keyword, value in {'BIASSEC': ('[2055:2080,1:2048]', '[binned pixel] Overscan Region'),
'GAIN': (gain, gain_comment),
'DATASEC': (datasec, '[binned pixel] Data section'),
'DETSEC': (detsec, '[unbinned pixel] Detector section'),
'CCDSUM': (hdu.header['CCDSUM'], hdu.header.comments['CCDSUM'])}.items():
header[keyword] = value
hdu_list.append(CCDData(data=hdu.data[i], meta=fits.Header(header)))
# We have to split the gain keyword for each extension
return hdu_list
6 changes: 3 additions & 3 deletions banzai/tests/test_bpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_null_input_imags():
@mock.patch('banzai.calibrations.CalibrationUser.get_calibration_file_info', return_value={'filename': 'test.fits'})
def test_adds_good_bpm(mock_bpm_name, mock_bpm, set_random_seed):
image = FakeLCOObservationFrame(hdu_list=[FakeCCDData(memmap=False)])
master_image = FakeLCOObservationFrame(hdu_list=[FakeCCDData(data=make_test_bpm(101,103), memmap=False)],
master_image = FakeLCOObservationFrame(hdu_list=[FakeCCDData(data=make_test_bpm(101, 103), memmap=False)],
file_path='test.fits')
mock_bpm.return_value = master_image
tester = BadPixelMaskLoader(FakeContext())
Expand Down Expand Up @@ -84,7 +84,7 @@ def test_uses_fallback_if_bpm_missing_and_no_bpm_set(mock_get_bpm_filename):
def test_removes_image_if_wrong_shape(mock_get_bpm_filename, mock_bpm, set_random_seed):
image = FakeLCOObservationFrame(hdu_list=[FakeCCDData(memmap=False)])
mock_bpm.return_value = FakeLCOObservationFrame(hdu_list=[FakeCCDData(data=make_test_bpm(image.data.shape[1] + 1,
image.data.shape[0]))])
image.data.shape[0], make_3d=True))])
tester = BadPixelMaskLoader(FakeContext())
assert tester.do_stage(image) is None

Expand All @@ -95,7 +95,7 @@ def test_removes_image_wrong_shape_3d(mock_get_bpm_filename, mock_bpm, set_rando
image = FakeLCOObservationFrame(hdu_list=[FakeCCDData(memmap=False)])
master_image = FakeLCOObservationFrame(
hdu_list=[FakeCCDData(data=bpm_data, memmap=False) for bpm_data in make_test_bpm(image.data.shape[1] + 1,
image.data.shape[0], make_3d=True)],
image.data.shape[0], make_3d=False)],
file_path='test.fits')
mock_bpm.return_value = master_image
tester = BadPixelMaskLoader(FakeContext())
Expand Down