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

DM-43436: Enable OBJECT and AZEL translations for LSSTCam #517

Merged
merged 8 commits into from
Mar 26, 2024
27 changes: 27 additions & 0 deletions python/lsst/obs/lsst/translators/comCamSim.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
__all__ = ("LsstComCamSimTranslator", )

import logging
import warnings

import astropy.utils.exceptions
from astropy.coordinates import AltAz
from astro_metadata_translator import cache_translation

from .lsstCam import LsstCamTranslator
from .lsst import SIMONYI_TELESCOPE
Expand Down Expand Up @@ -98,3 +103,25 @@ def _is_on_mountain(self):
Until then, ALL non-calib ComCam data will look like it is on sky.
"""
return True

@cache_translation
def to_altaz_begin(self):
# Tries to calculate the value. Simulated files for ops-rehearsal 3
# did not have the AZ/EL headers defined.
if self.are_keys_ok(["ELSTART", "AZSTART"]):
return super().to_altaz_begin()

# Calculate it from the RA/Dec and time.
# The time is not consistent with the HASTART/AMSTART values.
# This means that the elevation may well come out negative.
if self.are_keys_ok(["RA", "DEC"]):
# Derive from RADec in absence of any other information
radec = self.to_tracking_radec()
if radec is not None:
# This can trigger warnings because of the future dates
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=astropy.utils.exceptions.AstropyWarning)
altaz = radec.transform_to(AltAz())
return altaz

return None
34 changes: 25 additions & 9 deletions python/lsst/obs/lsst/translators/lsst.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,23 @@ def to_dark_time(self):
darktime = self.to_exposure_time()
return darktime

def _get_controller_code(self) -> str | None:
"""Return the controller code.

Returns
-------
code : `str`
Single character code representing the controller. Returns
`None` if no controller can be determined.
"""
key = "CONTRLLR"
if self.is_key_ok(key):
controller = self._header[key]
self._used_these_cards(key)
else:
controller = None
return controller

@cache_translation
def to_exposure_id(self):
"""Generate a unique exposure ID number
Expand All @@ -622,11 +639,7 @@ def to_exposure_id(self):
seqnum = self._header["SEQNUM"]
self._used_these_cards("DAYOBS", "SEQNUM")

if self.is_key_ok("CONTRLLR"):
controller = self._header["CONTRLLR"]
self._used_these_cards("CONTRLLR")
else:
controller = None
controller = self._get_controller_code()

return self.compute_exposure_id(dayobs, seqnum, controller=controller)

Expand Down Expand Up @@ -735,6 +748,11 @@ def to_altaz_begin(self):
if not self._is_on_mountain():
return None

# H controller data are sometimes science observations without
# having AZSTART header. The code lets those return nothing.
if self._get_controller_code() == "H" and not self.are_keys_ok(["ELSTART", "AZSTART"]):
return None

# Always attempt to find the alt/az values regardless of observation
# type.
return altaz_from_degree_headers(self, (("ELSTART", "AZSTART"),),
Expand Down Expand Up @@ -953,10 +971,8 @@ def to_has_simulated_content(self):
return True

# If the controller is H, P, or Q then the data are simulated.
ctrlr_key = "CONTRLLR"
if self.is_key_ok(ctrlr_key):
controller = self._header[ctrlr_key]
self._used_these_cards(ctrlr_key)
controller = self._get_controller_code()
if controller:
if controller in "HPQ":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this test also include controller "S"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jchiang87 I fixed this but I also added some header fixups for things like RASTART/RAEND and fixed an age-old ComCam translator bug from #167. It's quite a lot of code so I've asked for a re-review.

return True

Expand Down
5 changes: 1 addition & 4 deletions python/lsst/obs/lsst/translators/lsstCam.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ class LsstCamTranslator(LsstBaseTranslator):
_const_map = {
"instrument": LSST_CAM,
"telescope": SIMONYI_TELESCOPE,
# Migrate these to full translations once test data appears that
# includes them
"altaz_begin": None,
"object": "UNKNOWN",
}

_trivial_map = {
Expand All @@ -82,6 +78,7 @@ class LsstCamTranslator(LsstBaseTranslator):
"observation_id": "OBSID",
"exposure_time": ("EXPTIME", dict(unit=u.s)),
"detector_serial": "LSST_NUM",
"object": ("OBJECT", dict(default="UNKNOWN")),
"science_program": (["PROGRAM", "RUNNUM"], dict(default="unknown")),
"boresight_rotation_angle": (["ROTPA", "ROTANGLE"], dict(checker=is_non_science_or_lab,
default=0.0, unit=u.deg)),
Expand Down
246 changes: 246 additions & 0 deletions tests/headers/comCamSim-CC_S_20240321_000093_R22_S22.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
SIMPLE: true
EXTEND: true
BINX: 1
BINY: 1
CCDGAIN: 1.0
CCDNOISE: 10.0
COMMENT: '---- Checksums ----'
DATE: '2024-03-22T03:43:14.140'
MJD: 60391.15502476832
IMGTYPE: OBJECT
DATE-OBS: '2024-03-22T03:42:41.086'
MJD-OBS: 60391.154642199166
DATE-TRG: '2024-03-22T03:43:14.138'
MJD-TRG: 60391.1550247455
OBSID: CC_S_20240321_000093
DATE-BEG: '2024-03-22T03:42:41.086'
MJD-BEG: 60391.154642199166
DATE-END: '2024-03-22T03:43:14.140'
MJD-END: 60391.15502476832
GROUPID: '2024-03-22T03:41:54.994'
BUNIT: adu
TIMESYS: TAI
INSTRUME: ComCamSim
TELESCOP: Simonyi Survey Telescope
OBS-LONG: -70.749417
OBS-LAT: -30.244639
OBS-ELEV: 2663.0
OBSGEO-X: 1818938.94
OBSGEO-Y: -5208470.95
OBSGEO-Z: -3195172.08
RA: 124.82881462031425
DEC: -14.893919091079661
RASTART: null
DECSTART: null
RAEND: null
DECEND: null
ROTPA: 116.0158594226007
ROTCOORD: sky
HASTART: -10.490392243587635
ELSTART: null
AZSTART: null
AMSTART: 1.0522574903781972
HAEND: -10.36504999786186
ELEND: null
AZEND: null
AMEND: 1.0522574903781972
TRACKSYS: null
RADESYS: null
FOCUSZ: 0.0
OBJECT: TEST
TESTTYPE: OBJECT
CAMCODE: CC
CONTRLLR: S
DAYOBS: '20240321'
SEQNUM: 93
EMUIMAGE: CC_S_20240402_000919
PROGRAM: null
REASON: null
CURINDEX: 1
MAXINDEX: 1
TSTAND: EOCCv2_SUM
IMAGETAG: 318d7d781d5dbc78
OBSANNOT: Rubin_SV_125_-15
CCD_MANU: ITL
CCD_TYPE: 3800C
CCDSLOT: S22
RAFTBAY: R22
FIRMWARE: 302c5003
PLATFORM: comcam
CONTNUM: '0'
DAQVERS: R5-V8.1 2023-12-05T02:49:12Z (5acbb461)
DAQPART: emu
DAQFOLD: raw
SEQFILE: FP_ITL_2s_ir2_v26.seq
SEQNAME: FP_ITL_2s_ir2_v26.seq
SEQCKSUM: '980618532'
LSST_NUM: ITL-3800C-206
CCD_SERN: '22689'
REBNAME: LCA-13574-094
RAFTNAME: LCA-11021_RTM-031
FPVERS: 1.2.5
IHVERS: 1.1.5
FILTBAND: r
FILTER: r_03
FILTPOS: 1.0
FILTSLOT: 1
EXPTIME: 30.0
DARKTIME: 33.0546
SHUTTIME: null
AIRTEMP: null
PRESSURE: null
HUMIDITY: null
WINDSPD: null
WINDDIR: null
SEEING: null
FILENAME: CC_S_20240321_000093_R22_S22.fits
HEADVER: 2
SIMULATE MTMOUNT: 1
SIMULATE MTM1M3: 1
SIMULATE MTM2: 1
SIMULATE CAMHEXAPOD: 1
SIMULATE M2HEXAPOD: 1
SIMULATE MTROTATOR: 1
SIMULATE MTDOME: 1
SIMULATE MTDOMETRAJECTORY: 1
SIMULATED MJD-OBS: 60402.98136007414
SIMULATED DATE-OBS: '2024-04-02T23:33:09.510'
SIMULATED DATE-END: '2024-04-02T23:33:39.510'
STUTTER ROWS: 0
STUTTER DELAY: 0.0
STUTTER NSHIFTS: 0
XTENSION: BINTABLE
BITPIX: 8
NAXIS: 2
NAXIS1: 8
NAXIS2: 2048
PCOUNT: 1135695
GCOUNT: 1
TFIELDS: 1
TTYPE1: COMPRESSED_DATA
TFORM1: 1PB(613)
ZIMAGE: true
ZTILE1: 576
ZTILE2: 1
ZCMPTYPE: RICE_1
ZNAME1: BLOCKSIZE
ZVAL1: 32
ZNAME2: BYTEPIX
ZVAL2: 4
ZTENSION: IMAGE
ZBITPIX: 32
ZNAXIS: 2
ZNAXIS1: 576
ZNAXIS2: 2048
ZPCOUNT: 0
ZGCOUNT: 1
ZHECKSUM: 3L864K553K553K55
CHANNEL: 1
EXTNAME: Segment10
CCDSUM: 1 1
DATASEC: '[4:512,1:2000]'
DETSEC: '[509:1,1:2000]'
DETSIZE: '[1:4072,1:4000]'
DTV1: 513
DTV2: 0
DTM1_1: -1.0
DTM2_2: 1.0
DTM1_2: 0.0
DTM2_1: 0.0
WCSNAMEA: AMPLIFIER
CTYPE1A: Seg_X
CTYPE2A: Seg_Y
PC1_1A: 0.0
PC1_2A: -1.0
PC2_1A: -1.0
PC2_2A: 0.0
CDELT1A: 1.0
CDELT2A: 1.0
CRPIX1A: 0.0
CRPIX2A: 0.0
CRVAL1A: 2001.0
CRVAL2A: 513.0
WCSNAMEC: CCD
CTYPE1C: CCD_X
CTYPE2C: CCD_Y
PC1_1C: 0.0
PC1_2C: -1.0
PC2_1C: -1.0
PC2_2C: 0.0
CDELT1C: 1.0
CDELT2C: 1.0
CRPIX1C: 0.0
CRPIX2C: 0.0
CRVAL1C: 4001.0
CRVAL2C: 513.0
WCSNAMER: RAFT
CTYPE1R: RAFT_X
CTYPE2R: RAFT_Y
PC1_1R: 0.0
PC1_2R: -1.0
PC2_1R: -1.0
PC2_2R: 0.0
CDELT1R: 1.0
CDELT2R: 1.0
CRPIX1R: 0.0
CRPIX2R: 0.0
CRVAL1R: 12576.0
CRVAL2R: 9052.0
WCSNAMEF: FOCAL_PLANE
CTYPE1F: FP_X
CTYPE2F: FP_Y
PC1_1F: 0.0
PC1_2F: -1.0
PC2_1F: -1.0
PC2_2F: 0.0
CDELT1F: 1.0
CDELT2F: 1.0
CRPIX1F: 0.0
CRPIX2F: 0.0
CRVAL1F: 37976.0
CRVAL2F: 34452.0
WCSNAMEE: FP_SERPAR
CTYPE1E: FP_S
CTYPE2E: FP_P
PC1_1E: -1.0
PC1_2E: 0.0
PC2_1E: 0.0
PC2_2E: -1.0
CDELT1E: 1.0
CDELT2E: 1.0
CRPIX1E: 0.0
CRPIX2E: 0.0
CRVAL1E: 34452.0
CRVAL2E: 37976.0
WCSNAMEB: CCD_SERPAR
CTYPE1B: CCD_S
CTYPE2B: CCD_P
PC1_1B: -1.0
PC1_2B: 0.0
PC2_1B: 0.0
PC2_2B: -1.0
CDELT1B: 1.0
CDELT2B: 1.0
CRPIX1B: 0.0
CRPIX2B: 0.0
CRVAL1B: 513.0
CRVAL2B: 4001.0
WCSNAMEQ: RAFT_SERPAR
CTYPE1Q: RAFT_S
CTYPE2Q: RAFT_P
PC1_1Q: -1.0
PC1_2Q: 0.0
PC2_1Q: 0.0
PC2_2Q: -1.0
CDELT1Q: 1.0
CDELT2Q: 1.0
CRPIX1Q: 0.0
CRPIX2Q: 0.0
CRVAL1Q: 9052.0
CRVAL2Q: 12576.0
BSCALE: 1.0
BZERO: 0.0
INHERIT: true
ZDATASUM: '2562456853'
CHECKSUM: ZZTabZRYZZRabZRW
DATASUM: '3697423506'