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

Tickets/DM-40956 Take Twilight Flats #146

Merged
merged 5 commits into from
Oct 22, 2024
Merged

Tickets/DM-40956 Take Twilight Flats #146

merged 5 commits into from
Oct 22, 2024

Conversation

elanaku
Copy link
Contributor

@elanaku elanaku commented Sep 14, 2024

No description provided.

@elanaku elanaku requested a review from tribeiro September 14, 2024 13:13
Copy link
Member

@tribeiro tribeiro left a comment

Choose a reason for hiding this comment

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

Here is an initial round of comments.

else:
self.log.debug("ATCS already defined, skipping.")

@property
Copy link
Member

Choose a reason for hiding this comment

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

Please, move this property definition so it is close to the tcs one.

-------
instrument_filter: `string`
"""
filter = self.config.filter
Copy link
Member

Choose a reason for hiding this comment

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

filter is a valid python keyword:

In [1]: filter?
Init signature: filter(self, /, *args, **kwargs)
Docstring:
filter(function or None, iterable) --> filter object

Return an iterator yielding those items of iterable for which function(item)
is true. If function is None, return the items that are true.

Please, don't shadow it here. Just use self.config.filter directly, you are not really gaining anything by doing this.

Copy link
Member

@tribeiro tribeiro left a comment

Choose a reason for hiding this comment

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

Here some additional comments.

Also, it looks like the unit tests are failing because sumit_utils is not available in the container. You can make it available by adding lsst-sitcom/summit_utils to the list of extra_packages in the Jenkinsfile.


return schema_dict

@abc.abstractmethod
Copy link
Member

Choose a reason for hiding this comment

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

Consider having all the abstract method defined close together.

raise NotImplementedError()

async def offset_telescope(self):
"""Abstract method to dither the camera if desired."""
Copy link
Member

Choose a reason for hiding this comment

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

Fix docstring.


await super().configure(config)

self.client = self.make_consdb_client()
Copy link
Member

Choose a reason for hiding this comment

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

I don't see this method defined anywhere here. Also, you already defined self.client = ConsDbClient() during initialization.

raise NotImplementedError()

@abc.abstractmethod
def get_instrument_filter(self) -> str:
Copy link
Member

Choose a reason for hiding this comment

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

Please make sure all the abstract methods are defined together.

# Take one 1s flat to calibrate the exposure time
self.log.info("Taking 1s flat to calibrate exposure time.")
exp_time = 1
await self.camera.take_flats(
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this should be a take_acq instead? We probably don't want to use this image for flat field right?

exp_time = self.get_new_exptime(sky_counts, exp_time)

if exp_time > self.config.max_exp_time:
raise Exception(
Copy link
Member

Choose a reason for hiding this comment

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

Is this really a fail condition? it probably means the sky is too dark to take sky flats right?

I would suggest logging it as a warning and returning or break the loop. If you want to fail the script, please, raise RuntimeError instead of Exception.

if np.abs(self.config.dither) > 0:
self.offset_telescope()

await self.camera.take_flats(
Copy link
Member

Choose a reason for hiding this comment

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

I think we need to add support for sky flat type in the camera.

)

if (where_sun < self.config.min_sun) or (where_sun > self.config.max_sun):
raise Exception(
Copy link
Member

Choose a reason for hiding this comment

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

Please, don't raise Exception... either use RuntimeError or, in this case, an AssertionError.


return coords[arg]

def confirm_sun_location(self):
Copy link
Member

Choose a reason for hiding this comment

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

Consider renaming this method to assert_sun_location and then raise an AssertionError if the sun is not in the limits.

raise NotImplementedError()

@abc.abstractmethod
async def setup_instrument(self, ra, dec) -> str:
Copy link
Member

@tribeiro tribeiro Oct 3, 2024

Choose a reason for hiding this comment

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

Can you rename this method to something that reflects what it is supposed to do now? maybe track_radec_and_setup_instrument? Also, you are not passing the instrument configuration, so, consider using the same strategy for ra and dec, in which case, I would suggest a name like track_and_setup_instrument


@abc.abstractmethod
async def setup_instrument(self, ra, dec) -> str:
"""Abstract method to set the instrument filter.
Copy link
Member

Choose a reason for hiding this comment

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

It is also doing the slew/tracking now.


async def offset_telescope(self):
"""Dither the camera between exposures if desired."""
await self.atcs.offset_azel(
Copy link
Member

Choose a reason for hiding this comment

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

atcs?

Copy link
Member

@tribeiro tribeiro left a comment

Choose a reason for hiding this comment

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

Here is another round of comments..

timeout = 30
query = f"SELECT * from cbd_latiss.visit1_quicklook where exposure_id = {self.latest_exposure_id}"
item = "post_isr_pixel_median"
sky_counts = self.client.wait_for_item_in_row(query, item, timeout)
Copy link
Member

Choose a reason for hiding this comment

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

Since this is a regular method and not a coroutine, you will need to run this in an executor. It should be something like this:

First, at the top:

import functools

then here you would do:

get_sky_counts = functools.partial(self.client.wait_for_item_in_row, query, item, timeout)
sky_counts = await asyncio.get_running_loop().run_in_executor(
    None, get_sky_counts
)

you might want to find the name of the parameters you are passing to wait_for_item_in_row and use them instead of relying on their ordering, e.g.:

get_sky_counts = functools.partial(self.client.wait_for_item_in_row, query=query, item=item, timeout=timeout)

note that I don't know if the names are correct, I just guessing.


return schema_dict

async def offset_telescope(self):
Copy link
Member

Choose a reason for hiding this comment

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

I feel like you can remove this method and just use the call inline.

f" The elevation of the Sun is {sun_coordinates[1]:.2f} deg"
)

if (sun_coordinates[1] < self.config.min_sun_elevation) or (
Copy link
Member

Choose a reason for hiding this comment

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

minor detail, but you can make this in a single statement with:

assert (sun_coordinates[1] < self.config.min_sun_elevation) or (sun_coordinates[1] > self.config.max_sun_elevation), f"Sun elevation {sun_coordinates} is outside appropriate elvation limits. Aborting."

sun_coordinates[1] > self.config.max_sun_elevation
):
raise AssertionError(
f"Sun elevation {sun_coordinates} is outside appropriate elvation limits. Aborting."
Copy link
Member

Choose a reason for hiding this comment

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

There is a typo in "elvation" -> "elevation". But also, consider removing "Aborting" at the end and also logging what are the conditions. Something like:

f"Sun elevation {sun_coordinates[1]} is outside appropriate limits. "
f"Must be below {self.config.min_sun_elevation} or above {self.config.max_sun_elevation}."


return target_radec

def get_empty_field(self, target, radius=5):
Copy link
Member

Choose a reason for hiding this comment

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

You need to convert this method to a coroutine and run the query in an executor (see below).

Otherwise calling this will block the async event loop and will look like the script has died.

dec=self.config.dec,
)
),
asyncio.create_task(self._wait_rotator_reach_filter_change_angle()),
Copy link
Member

Choose a reason for hiding this comment

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

you don't need this.

asyncio.create_task(
self.mtcs.slew_icrs(
ra=self.config.ra,
dec=self.config.dec,
Copy link
Member

Choose a reason for hiding this comment

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

you need to pass rot_type=RotType.Physical.


await self.lsstcam.setup_filter(filter=self.config.band_filter)

async def _wait_rotator_reach_filter_change_angle(self):
Copy link
Member

Choose a reason for hiding this comment

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

You don't need this.

try:
from lsst.summit.utils import ConsDbClient

CONSDB_AVAILABLE = True
Copy link
Member

Choose a reason for hiding this comment

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

Instead of doing this, consider mocking the behavior. For example, take a look at: https://github.com/lsst-ts/ts_standardscripts/blob/65fd9b9e57cdb0ef93a658f99f89975708767c32/tests/test_base_block_script.py#L76-L78

You can mock the behavior of method calls by patching them.

self.mtcs.slew_icrs(
ra=self.config.ra,
dec=self.config.dec,
rot_type=RotType.PhysicalSky,
Copy link
Member

Choose a reason for hiding this comment

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

This one needs to be RotType.Physical instead. this will ensure the rotator is kept at the fixed position.

@edennihy edennihy self-requested a review October 22, 2024 19:22
Copy link
Contributor

@edennihy edennihy left a comment

Choose a reason for hiding this comment

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

Changes approved in the interest of getting these merged. Expect some improvement after on-sky testing with ComCam.

@elanaku elanaku merged commit f75e885 into develop Oct 22, 2024
2 checks passed
@elanaku elanaku deleted the tickets/DM-40956 branch October 22, 2024 19:38
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

Successfully merging this pull request may close these issues.

3 participants