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-39206 - Power on ATCalSys #116

Closed
wants to merge 0 commits into from
Closed

DM-39206 - Power on ATCalSys #116

wants to merge 0 commits into from

Conversation

isotuela
Copy link
Contributor

No description provided.

@isotuela isotuela marked this pull request as draft May 19, 2023 19:40
@isotuela isotuela requested a review from tribeiro May 19, 2023 19:40
@isotuela isotuela force-pushed the tickets/DM-39206 branch 3 times, most recently from 6f1c821 to bb330bd Compare May 19, 2023 21:42
@isotuela isotuela changed the title DM-39206 - First draft DM-39206 - Power on ATCalSys Jun 5, 2023
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 initial comments.

# self.log.info(f"Lamp didn't turn on after {self.lamp_warm_up_time} s")

async def wait_for_lamp_to_warm_up(self):
await self.white_light_source.evt_lampState.flush()
Copy link
Member

Choose a reason for hiding this comment

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

flush is a regular method not a coroutine. You should drop the await.

)
if lamp_state.basicState == ATWhiteLight.LampBasicState.WARMUP:
warmup_time_left = (
lamp_state.warmupEndTime - lamp_state.private_rcvStamp
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 you probably want to use private_sndStamp instead of private_rcvStamp. Difference should be small but still.

self.log.info(
f"White Light Lamp is on after a warm up of {warm_up_elapsed_time} s"
)
else:
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 correct? if the status is not WARMUP nor ON it will fail?

Also, if it is a fail, shouldn't you raise an exception or something?

"Time Left for lamp warmup: {} min.".format(warmup_time_left / 60.0)
)
await asyncio.sleep(self.track_lamp_warmup)
elif lamp_state.basicState == ATWhiteLight.LampBasicState.ON:
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 you could drop this elif and just do this after the while loop has ended (it saves you from doing a comparison).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have changed the code a little more.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, not sure I understand the logic here. Do you need to break in this condition? it seems like it is going to continue in the loop until is time out.

However, see my suggestion for simplifying this loop.

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 comments for you to consider... I haven't been able to read through it all yet, sorry..

# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License

Copy link
Member

Choose a reason for hiding this comment

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

Missing the final phrase:

# along with this program.  If not, see <https://www.gnu.org/licenses/>.


from lsst.ts import salobj

track_lamp_warmup = 60
Copy link
Member

Choose a reason for hiding this comment

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

If this is supposed to be a constant, please, make is all caps,

TRACK_LAMP_WARMUP = 60

But maybe best to have this as a class attribute instead, e.g.,. move it to the __init__ method and make it self.track_lamp_warmup.

index : `int`
Index of Script SAL component.

Notes
Copy link
Member

Choose a reason for hiding this comment

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

If you don't have any Notes, you can remove this session.

self.timeout_chiller_cool_down = 60 * 10
self.chiller_temp_tolerance_relative = 0.1

if self.white_light_source is None:
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 you need to move all this code from here until line 86 to the configure method. Or maybe make a setup_remotes coroutine and await it in configure.

Copy link
Contributor Author

@isotuela isotuela Jun 9, 2023

Choose a reason for hiding this comment

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

I tried moving it to __init__ because it didn't configure properly if it was in the configure method, and all unittest were failing quickly.

log=self.log
)

asyncio.gather(
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 await this otherwise nothing happens.. Once you move this to the configure method, you will be able to do:

await asyncio.gather(...)

# domain=self.domain, name="ATMonochromator"
# )

self.config = config
Copy link
Member

Choose a reason for hiding this comment

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

Above you are creating individual attributes to get the values from config and then here you just store the entire thing. I think pick one method. Either set them up individually or get the full thing, but not both.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!!


async def run(self):
"""Run script."""
#await self.assert_components_enabled()
Copy link
Member

Choose a reason for hiding this comment

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

Please, remove commented code or uncomment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Uncommented.

await self.white_light_source.cmd_startChiller.set(timeout=self.timeout_chiller_cool_down)

async def wait_for_chiller_temp_within_tolerance(self):
start_time_chill_time = time.time()
Copy link
Member

Choose a reason for hiding this comment

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

time is repeated here.. maybe rename it start_chill_time?

@isotuela isotuela force-pushed the tickets/DM-39206 branch 2 times, most recently from c7cff59 to e35a0d3 Compare June 12, 2023 13:20
@isotuela isotuela requested a review from tribeiro June 12, 2023 13:22

Raises
------
salobj.ExpectedError :
Copy link
Member

Choose a reason for hiding this comment

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

Usually we only document the exceptions that the method itself raises. This one in particular is raised by another method that does the configuration validation before calling configure. You should probably remove this here.

@isotuela isotuela force-pushed the tickets/DM-39206 branch 3 times, most recently from d1feb7b to 1930f20 Compare June 14, 2023 02:51
@isotuela isotuela marked this pull request as ready for review June 14, 2023 02:59
@isotuela isotuela requested a review from tribeiro June 14, 2023 02:59
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 another round of comments..

self.white_light_source = salobj.Remote(
domain=self.domain,
name="ATWhiteLight",
log=self.log,
Copy link
Member

Choose a reason for hiding this comment

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

Remote does not take log as a parameter.

self.monochromator = salobj.Remote(
domain=self.domain,
name="ATMonochromator",
log=self.log,
Copy link
Member

Choose a reason for hiding this comment

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

Remote does not take log as a parameter.

@@ -32,6 +32,8 @@ v1.22.0

* Add new ``MoveP2P`` maintel script.

* Add new ``auxtel/calibrations/power_on_atcalsys.py`` script, unit test and executable to set up and turn on the ATCalSys white light.
Copy link
Member

Choose a reason for hiding this comment

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

Version 1.22.0 was already released, please make this a new release 1.25.0

)

async def open_white_light_shutter(self):
await self.white_light_source.cmd_openShutter.set_start()
Copy link
Member

Choose a reason for hiding this comment

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

Please, add a timeout to the command, otherwise it can stop here forever. Also, since you are not passing in any parameter, use, start instead, e.g,:

        await self.white_light_source.cmd_openShutter.start(timeout=self.timeout_open_shutter)

and you need to define self.timeout_open_shutter in the __init__ method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have put 5 minutes timeout, does that sound right?


async def open_white_light_shutter(self):
await self.white_light_source.cmd_openShutter.set_start()
# Q? Should we include a check that the shutter is open?
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 this command only finishes when the shutter is open, and fails if the shutter doesn't open.. So think it is ok to leave it as is, e.g., no need to check.

"Time Left for lamp warmup: {} min.".format(warmup_time_left / 60.0)
)
await asyncio.sleep(self.track_lamp_warmup)
elif lamp_state.basicState == ATWhiteLight.LampBasicState.ON:
Copy link
Member

Choose a reason for hiding this comment

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

Sorry, not sure I understand the logic here. Do you need to break in this condition? it seems like it is going to continue in the loop until is time out.

However, see my suggestion for simplifying this loop.

)

async def wait_for_lamp_to_warm_up(self):
self.white_light_source.evt_lampState.flush()
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 it is best to flush just before you send the command. Flushing here can create a race condition where the event is published between the time the command is sent and the time to get here, in which case you loose the event.

I would actually suggest changing the loop a little bit.

Consider something like this:

lamp_state = await self.white_light_source.evt_lampState.aget(
    timeout=self.timeout_lamp_warm_up
) # gets the most recent data

# Now enters the loop with the stop condition being that the lamp is ON

while lamp_state.basicState != ATWhiteLight.LampBasicState.ON:
    lamp_state = await self.white_light_source.evt_lampState.next(
        flush=False, timeout=self.timeout_lamp_warm_up
    )
    self.log.info(f"Lamp state: {ATWhiteLight.LampBasicState(lamp_state.basicState)!r}.")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good suggestion.

)

async def get_monochromator_parameters(self):
tmp1 = await self.monochromator.evt_selectedGrating.aget()
Copy link
Member

Choose a reason for hiding this comment

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

Please, add a timeout for all these aget statements, otherwise it can block here for ever.

Also you can probably do this in "in parallel" using asyncio.gather:

return await asyncio.gather(
    self.monochromator.evt_selectedGrating.aget(timeout=self.std_timeout),
    self.monochromator.evt_wavelength.aget(timeout=self.std_timeout),
    self.monochromator.evt_entrySlitWidth.aget(timeout=self.std_timeout),
    self.monochromator.evt_exitSlitWidth.aget(timeout=self.std_timeout),
)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion with the asynctio.gather

if salobj.State(summary_state.summaryState) != salobj.State(
salobj.State.ENABLED
):
raise Exception(f"{comp} is not ENABLED")
Copy link
Member

Choose a reason for hiding this comment

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

Please, raise RuntimeError instead of a bare exception.

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.

2 participants