diff --git a/doc/news/DM-40956.feature.1.rst b/doc/news/DM-40956.feature.1.rst new file mode 100644 index 000000000..d406e9857 --- /dev/null +++ b/doc/news/DM-40956.feature.1.rst @@ -0,0 +1 @@ +Allow twilight flats to be taken at current pointing and allow tcs components to be ignored. \ No newline at end of file diff --git a/python/lsst/ts/externalscripts/auxtel/latiss_take_twilight_flats.py b/python/lsst/ts/externalscripts/auxtel/latiss_take_twilight_flats.py index 26d1558af..e745da668 100644 --- a/python/lsst/ts/externalscripts/auxtel/latiss_take_twilight_flats.py +++ b/python/lsst/ts/externalscripts/auxtel/latiss_take_twilight_flats.py @@ -209,3 +209,14 @@ async def slew_azel_and_setup_instrument(self, az, el): filter=self.config.filter, grating=self.config.grating, ) + + async def setup_instrument(self, az, el): + """Abstract method to set the instrument. Change the filter + and start tracking. + """ + await self.tcs.start_tracking() + + await self.latiss.setup_instrument( + filter=self.config.filter, + grating=self.config.grating, + ) diff --git a/python/lsst/ts/externalscripts/base_take_twilight_flats.py b/python/lsst/ts/externalscripts/base_take_twilight_flats.py index 66a39680a..70c41968e 100644 --- a/python/lsst/ts/externalscripts/base_take_twilight_flats.py +++ b/python/lsst/ts/externalscripts/base_take_twilight_flats.py @@ -177,6 +177,13 @@ async def slew_azel_and_setup_instrument(self, az, el): """ raise NotImplementedError() + @abc.abstractmethod + async def setup_instrument(self): + """Abstract method to set the instrument. Change the filter + and slew and track target. + """ + raise NotImplementedError() + @classmethod def get_schema(cls): schema_yaml = """ @@ -242,6 +249,11 @@ def get_schema(cls): description: If True, track sky. If False, keep az and el constant. type: boolean default: True + position_telescope: + description: If True, position telescope relative to the sun. \ + If False, assume the telescope is in correct position. + type: boolean + default: True ignore: description: >- CSCs from the camera group to ignore in status check. @@ -249,7 +261,6 @@ def get_schema(cls): type: array items: type: string - additionalProperties: false """ schema_dict = yaml.safe_load(schema_yaml) @@ -282,10 +293,13 @@ async def configure(self, config: types.SimpleNamespace): if comp in self.camera.components_attr: self.log.debug(f"Ignoring Camera component {comp}.") setattr(self.camera.check, comp, False) + elif comp in ["MTDome, MTDomeTrajectory"]: + self.log.debug(f"Ignoring component {comp}.") + setattr(self.tcs.check, comp, False) else: self.log.warning( f"Component {comp} not in CSC Group. " - f"Must be one of {self.camera.components_attr}. " + f"Must be one of {self.camera.components_attr} or MTDome, MTDomeTrajectory." f"Ignoring." ) @@ -456,6 +470,20 @@ def assert_sun_location(self): Must be above {self.config.min_sun_elevation} or below {self.config.max_sun_elevation}." ) + def assert_sun_distance(self): + sun_coordinates = self.tcs.get_sun_azel() + current_az = await getattr(self.remote, f"evt_{self.event}").next( + flush=False, timeout=self.config.event_timeout + ) + + min_sun_az_distance = 60 + + if np.abs(sun_coordinates[0] - current_az) < min_sun_az_distance: + raise RuntimeError( + f"Sun elevation {sun_coordinates} is outside appropriate elevation limits. \ + Must be above {self.config.min_sun_elevation} or below {self.config.max_sun_elevation}." + ) + async def take_twilight_flats(self): """Take the sequence of twilight flats twilight flats.""" self.assert_sun_location() @@ -465,16 +493,20 @@ async def take_twilight_flats(self): # get an empty field search_area_degrees = 0.05 - if self.config.tracking: - ra, dec = await self.get_twilight_flat_sky_coords( - target, radius=search_area_degrees - ) + if self.config.position_telescope: + if self.config.tracking: + ra, dec = await self.get_twilight_flat_sky_coords( + target, radius=search_area_degrees + ) - await self.track_radec_and_setup_instrument(ra, dec) - else: - az = self.get_target_az() + await self.track_radec_and_setup_instrument(ra, dec) + else: + az = self.get_target_az() - await self.slew_azel_and_setup_instrument(az, self.config.target_el) + await self.slew_azel_and_setup_instrument(az, self.config.target_el) + else: + self.assert_sun_distance() + await self.setup_instrument() # Take one 1s flat to calibrate the exposure time self.log.info("Taking 1s flat to calibrate exposure time.") diff --git a/python/lsst/ts/externalscripts/maintel/take_twilight_flats_comcam.py b/python/lsst/ts/externalscripts/maintel/take_twilight_flats_comcam.py index a5fe698f5..653854227 100644 --- a/python/lsst/ts/externalscripts/maintel/take_twilight_flats_comcam.py +++ b/python/lsst/ts/externalscripts/maintel/take_twilight_flats_comcam.py @@ -227,6 +227,24 @@ async def slew_azel_and_setup_instrument(self, az, el): el=el, ) + async def setup_instrument(self): + """Abstract method to set the instrument. Change the filter + and track target. + """ + current_filter = await self.comcam.get_current_filter() + + if current_filter != self.config.filter: + self.log.debug( + f"Filter change required: {current_filter} -> {self.config.filter}" + ) + await self.comcam.setup_filter(filter=self.config.filter) + else: + self.log.debug( + f"Already in the desired filter ({current_filter}). Starting tracking" + ) + + await self.mtcs.start_tracking() + async def configure(self, config): """Take the sequence of twilight flats twilight flats.""" self.configure_client() diff --git a/python/lsst/ts/externalscripts/maintel/take_twilight_flats_lsstcam.py b/python/lsst/ts/externalscripts/maintel/take_twilight_flats_lsstcam.py index bc72f7c41..fede31e47 100644 --- a/python/lsst/ts/externalscripts/maintel/take_twilight_flats_lsstcam.py +++ b/python/lsst/ts/externalscripts/maintel/take_twilight_flats_lsstcam.py @@ -223,3 +223,21 @@ async def slew_azel_and_setup_instrument(self, az, el): az=az, el=el, ) + + async def setup_instrument(self): + """Abstract method to set the instrument. Change the filter + and slew and track target. + """ + current_filter = await self.lsstcam.get_current_filter() + + if current_filter != self.config.filter: + self.log.debug( + f"Filter change required: {current_filter} -> {self.config.filter}" + ) + await self.lsstcam.setup_filter(filter=self.config.filter) + else: + self.log.debug( + f"Already in the desired filter ({current_filter}), slewing." + ) + + await self.mtcs.start_tracking()