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

get_aca_images() returns MaskedColumns only for data with masked values (except IMG) #182

Merged
merged 7 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
99 changes: 89 additions & 10 deletions chandra_aca/maude_decom.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"""

import copy
import itertools
from struct import Struct
from struct import unpack as _unpack

Expand Down Expand Up @@ -945,7 +946,7 @@ def _aca_packets_to_table(aca_packets, dtype=None):
if name in aca_packet:
array[name][i] = aca_packet[name]

table = Table(array, masked=True)
table = Table(array)
if img:
table["IMG"] = img
for i, aca_packet in enumerate(aca_packets):
Expand Down Expand Up @@ -1315,11 +1316,79 @@ def get_aca_images(start: CxoTimeLike, stop: CxoTimeLike, **kwargs):
"""
Fetch ACA image telemetry

Fetch ACA image telemetry from MAUDE and return it as an astropy Table. With the default
settings and no additional kwargs, this calls `get_aca_packets()` in a configuration that
uses MAUDE frames, combines image data, and sets the TIME associated with each image to the
midpoint of the integration time during which that pixel data was collected (matches CXC L0
times). See `get_aca_packets()`.
Fetch ACA image telemetry from MAUDE and return it as an astropy Table. With the
default settings and no additional kwargs, this calls `get_aca_packets()` in a
configuration that uses MAUDE frames, combines image data, and sets the TIME
associated with each image to the midpoint of the integration time during which that
pixel data was collected (matches CXC L0 times). See `get_aca_packets()`.

The 'IMG' column is always Nx8x8 and masked, where the mask is a per-pixel mask that
indicates missing data for 4x4 or 6x6 images. The units of 'IMG' are DN.

For queries including 4x4 data, the 'BGDRMS', 'TEMPCCD', 'TEMPHOUS', 'TEMPPRIM',
'TEMPSEC', and 'BGDSTAT' columns will be masked since they are not present in the
4x4 image data.

There are three different specifiers of the image row/col location:
- IMGROW0_8x8/IMGCOL0_8x8: the row/col of the lower-left pixel of the 8x8 masked
image. This is generally the most useful.
- IMGROW0/IMGCOL0: the row/col of the lower-left pixel of the actual 4x4, 6x6, or
8x8 image data. For 6x6 this corresponds to the mouse-bitten corner pixel.
- IMGROW_A1/IMGCOL_A1: the row/col of the A1 pixel in telemetry (see ACA EQ-spec).

The full list of columns is::

name dtype unit
--------------------- ------- -----------
TIME float64 CXC seconds
VCDUCTR uint32
MJF uint32
MNF uint32
IMGNUM uint32
COMMCNT uint8
COMMPROG uint8
GLBSTAT uint8
IMGFUNC uint32
IMGTYPE uint8
IMGSCALE uint16
IMGROW0 int16
IMGCOL0 int16
INTEG float64 s
BGDAVG uint16 DN
BGDRMS uint16 DN
TEMPCCD float32 degC
TEMPHOUS float32 degC
TEMPPRIM float32 degC
TEMPSEC float32 degC
BGDSTAT uint8
HIGH_BGD bool
RAM_FAIL bool
ROM_FAIL bool
POWER_FAIL bool
CAL_FAIL bool
COMM_CHECKSUM_FAIL bool
RESET bool
SYNTAX_ERROR bool
COMMCNT_SYNTAX_ERROR bool
COMMCNT_CHECKSUM_FAIL bool
COMMPROG_REPEAT uint8
IMGFID bool
IMGSTAT uint8
SAT_PIXEL bool
DEF_PIXEL bool
QUAD_BOUND bool
COMMON_COL bool
MULTI_STAR bool
ION_RAD bool
IMGROW_A1 int16
IMGCOL_A1 int16
IMGROW0_8X8 int16
IMGCOL0_8X8 int16
END_INTEG_TIME float64
AAPIXTLM str4
AABGDTYP str4
IMG float64 DN
IMG_VCDUCTR int64


Parameters
Expand All @@ -1335,6 +1404,9 @@ def get_aca_images(start: CxoTimeLike, stop: CxoTimeLike, **kwargs):
-------
astropy.table.Table
"""
# This is strictly for testing, hence undocumented.
set_times_metadata = kwargs.pop("set_times_metadata", False)

start = CxoTime(start)
stop = CxoTime(stop)
if (stop - start) > MAUDE_FETCH_LIMIT:
Expand All @@ -1352,12 +1424,19 @@ def get_aca_images(start: CxoTimeLike, stop: CxoTimeLike, **kwargs):
level0=True,
**kwargs,
)
for istart, istop in zip(
maude_fetch_times[:-1], maude_fetch_times[1:], strict=False
)
for istart, istop in itertools.pairwise(maude_fetch_times)
]
out = vstack(packet_stack)
out.meta["times"] = maude_fetch_times
if set_times_metadata:
out.meta["times"] = maude_fetch_times

# Remove mask from columns where no values are masked. IMG is excepted because
# the mask reflects the presence of 4x4 or 6x6 images, not entirely missing data
# per row.
for col in out.itercols():
if not np.any(col.mask) and col.name != "IMG":
out[col.name] = col.data.data

return out


Expand Down
47 changes: 46 additions & 1 deletion chandra_aca/tests/test_maude_decom.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ def test_aca_images_chunks_1():
tstart = CxoTime(start).secs
tstop = CxoTime(stop).secs
try:
imgs = maude_decom.get_aca_images(start, stop)
# Include the "times" metadata in the returned images table for testing
imgs = maude_decom.get_aca_images(start, stop, set_times_metadata=True)
finally:
maude_decom.MAUDE_SINGLE_FETCH_LIMIT = single_fetch_limit

Expand Down Expand Up @@ -1287,3 +1288,47 @@ def test_end_integ_time(combine):
rtol=0,
)
)


def test_get_aca_image_masked_columns_1():
"""Get images over a time covering end of maneuver and start of dwell

This has fids (8x8), guides (6x6) and null images (4x4).
"""
start = "2018:024:23:05:00"
stop = "2018:024:23:10:00"
imgs = maude_decom.get_aca_images(start, stop)
# 4x4, 6x6, and 8x8 images
assert set(imgs["IMGTYPE"]) == {0, 1, 4}
# Null, tracking, and search
assert set(imgs["IMGFUNC"]) == {0, 1, 3}
cols_masked = {col.info.name for col in imgs.itercols() if hasattr(col, "mask")}
assert cols_masked == {
"BGDRMS",
"TEMPCCD",
"TEMPHOUS",
"TEMPPRIM",
"TEMPSEC",
"BGDSTAT",
"IMG",
}


def test_get_aca_image_masked_columns_2():
"""Only 6x6 and 8x8 so only IMG is masked"""
start = "2018:024:23:15:00"
stop = "2018:024:23:20:00"
imgs = maude_decom.get_aca_images(start, stop)
assert set(imgs["IMGTYPE"]) == {1, 4}
cols_masked = {col.info.name for col in imgs.itercols() if hasattr(col, "mask")}
assert cols_masked == {"IMG"}


def test_get_aca_image_masked_columns_3():
"""Only 8x8 so only IMG masked"""
start = "2024:001:00:00:00"
stop = "2024:001:00:01:00"
imgs = maude_decom.get_aca_images(start, stop)
assert set(imgs["IMGTYPE"]) == {4}
cols_masked = {col.info.name for col in imgs.itercols() if hasattr(col, "mask")}
assert cols_masked == {"IMG"}
Loading