Skip to content

Commit

Permalink
Power on ATCalSys with white light.
Browse files Browse the repository at this point in the history
  • Loading branch information
isotuela committed Jun 7, 2023
1 parent 8164152 commit 6127f47
Show file tree
Hide file tree
Showing 3 changed files with 350 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
#
# You should have received a copy of the GNU General Public License

from .power_on_atcalsys import *
from .power_on_atcalsys import *
301 changes: 179 additions & 122 deletions python/lsst/ts/standardscripts/auxtel/calibrations/power_on_atcalsys.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,23 @@
__all__ = ["PowerOnATCalSys"]

import asyncio
import collections
import time as time

import numpy as np
import yaml

from lsst.ts.idl.enums.Script import ScriptState
from lsst.ts.idl.enums import ATMonochromator, ATWhiteLight
from lsst.ts.idl.enums import ATWhiteLight
from lsst.ts.observatory.control.remote_group import Usages


from lsst.ts import salobj

track_lamp_warmup = 60


class PowerOnATCalSys(salobj.BaseScript):
"""Powers on the ATCalSys dome flat illuminator (ATWhiteLight and ATMonochromator)
required to perform imaging white light calibrations.
"""Powers on the ATCalSys dome flat illuminator
(ATWhiteLight and ATMonochromator)
required to perform image calibrations over white light.
Parameters
----------
Expand All @@ -45,26 +48,43 @@ class PowerOnATCalSys(salobj.BaseScript):
-----
"""
def __init__(self, index):

def __init__(self, index, add_remotes: bool = True):
super().__init__(
index=index,
descr="Power On AT Calibration System ",
)
self.whitelightsource = salobj.Remote(
domain=self.domain, name="ATWhiteLight", log=self.log
)

self.monochromator = salobj.Remote(
domain=self.domain, name="ATMonochromator", log=self.log
)

# self.cmd_timeout = 10
self.change_grating_time = 60
self.open_shutter_time = 20
self.white_light_source = None
self.monochromator = None

# White lamp config
self.timeout_lamp_warm_up = 60 * 15
self.cmd_timeout = 30

# Chiller config
self.timeout_chiller_cool_down = 60 * 10
self.chiller_temp_tolerance_relative = 0.1
self.chiller_temp_time = 60 * 2
self.track_lamp_warmup = 60
self.lamp_warmup_time = 15 * 60

if self.white_light_source is None:
self.white_light_source = salobj.Remote(
domain=self.domain, name="ATWhiteLight",
intended_usage= None if add_remotes else Usages.DryTest,
log =self.log
)

if self.monochromator is None:
self.monochromator = salobj.Remote(
domain=self.domain, name="ATMonochromator",
intended_usage= None if add_remotes else Usages.DryTest,
log=self.log
)

asyncio.gather(
self.white_light_source.start_task,
self.monochromator.start_task,
)


@classmethod
def get_schema(cls):
Expand All @@ -76,44 +96,42 @@ def get_schema(cls):
Each attribute can be specified as a scalar or array.
All arrays must have the same length (one item per image).
type: object
properties:
chiller_temperature:
description:
description: Set temperature for the chiller
type: number
default: 20
- type: number
minimum: 0
minimum: 15
whitelight_power:
description: White light power.
whitelight_power:
description: White light power.
type: number
default: 910
- type: number
minimum: 0
minimum: 0
wavelength:
description: Wavelength (nm). 0 nm is for white light.
type: number
default: 0
- type: number
minimum: 0
minimum: 0
grating_type:
description: Grating type for each image. The choices are 0=blue, 1=red, 2=mirror.
type: integer
enum: [0, 1, 2]
default: 2
anyOf:
- type: integer
enum: [0, 1, 2]
entrance_slit_width:
description: Width of the monochrometer entrance slit (mm)
default: 5
- type: number
minimum: 0
type: number
minimum: 0
default: 7
exit_slit_width:
description: Width of the monochromator entrance slit (mm)
default: 5
- type: number
minimum: 0
type: number
minimum: 0
default: 7
additionalProperties: false
"""
Expand All @@ -134,17 +152,22 @@ async def configure(self, config):
"""
self.log.info("Configure started")

# self.chiller_temperature = config.chiller_temperature

# self.whitelight_power = config.whitelight_power

# self.wavelength = config.wavelength
self.chiller_temperature = config.chiller_temperature
self.whitelight_power = config.whitelight_power
self.wavelength = config.wavelength
self.grating_type = config.grating_type
self.entrance_slit_width = config.entrance_slit_width
self.exit_slit_width = config.exit_slit_width

# self.grating_type = config.grating_type
# if self.white_light_source is None:
# self.white_light_source = salobj.Remote(
# domain=self.domain, name="ATWhiteLight"
# )

# self.entrance_slit_width = config.entrance_slit_width

# self.exit_slit_width = config.exit_slit_width
# if self.monochromator is None:
# self.monochromator = salobj.Remote(
# domain=self.domain, name="ATMonochromator"
# )

self.config = config

Expand All @@ -157,99 +180,133 @@ def set_metadata(self, metadata):
----------
metadata : SAPY_Script.Script_logevent_metadataC
"""
metadata.duration = 60 * 15
metadata.duration = self.timeout_chiller_cool_down + self.timeout_lamp_warm_up

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

await self.checkpoint("Start the chiller")

await whitelightsource.cmd_setChillerTemperature.set_start(temperature=self.chiller_temperature)
await whitelightsource.cmd_startChiller.set_start()

# confirm the chiller is running at chiller_temperature within tolerance
try:
await asyncio.wait_for(
is_chiller_temp_within_tolerance(), self.chiller_temp_time
)
except asyncio.TimeoutError:
self.log.info(f"Gave up waiting after {self.chiller_temp_time} for the chiller to chill to {self.chiller_temperature}")
await self.checkpoint("Starting chiller")
await self.start_chiller()

await self.checkpoint("Open the shutter")
await self.checkpoint("Waiting for chiller to cool to set temperature")
await self.wait_for_chiller_temp_within_tolerance()

await whitelightsource.cmd_openShutter.set_start()
await self.checkpoint("Opening the shutter")
await self.open_white_light_shutter()

# Confirm shutter is open or sent an error message? Should we include an error message if it fails rather than the RunTimeError
## shutter_state = await whitelightsource.evt_shutterState.aget()

await self.checkpoint("Turning on lamp")
await whitelightsource.cmd_turnLampOn.set_start(power = self.whitelight_power)
await self.switch_lamp_on()

# Confirm lamp state turns on (It will go into a warm up period before it will turn on)
try:
await asyncio.wait_for(
has_lamp_finish_warm_up(), self.lamp_warm_up_time
),
except asyncio.TimeoutError:
self.log.info(f"Lamp didn't turn on after {self.lamp_warm_up_time} s")
await self.checkpoint("Waiting for lamp to warm up")
await self.wait_for_lamp_to_warm_up()

await self.checkpoint("Configuring ATMonochromator")
await self.configure_atmonochromator()

await self.checkpoint("Set the grating")

await monochromator.cmd_selectGrating.set_start(gratingType=self.grating, timeout = 180)
async def start_chiller(self):
await self.white_light_source.cmd_setChillerTemperature.set_start(
temperature=self.chiller_temperature, timeout=self.cmd_timeout
)
await self.white_light_source.cmd_startChiller.set(timeout=self.timeout_chiller_cool_down)

await self.checkpoint("Set wavelength")
async def wait_for_chiller_temp_within_tolerance(self):
start_time_chill_time = time.time()
while time.time() - start_time_chill_time < self.timeout_chiller_cool_down:
chiller_temps = await self.white_light_source.tel_chillerTemperatures.aget()
tel_chiller_temp = chiller_temps.supplyTemperature
if (
chiller_temps.setTemperature
* (1.0 - self.chiller_temp_tolerance_relative)
< tel_chiller_temp
< chiller_temps.setTemperature
* (1.0 + self.chiller_temp_tolerance_relative)
):
chill_time = time.time() - start_time_chill_time
self.log.info(
f"Chiller reached target temperature {tel_chiller_temp}"
f"within tolerance in {chill_time} s"
)
break
else:
continue
else:
raise TimeoutError(
f"Gave up waiting after {self.timeout_chiller_cool_down}"
f"for the chiller to chill to {self.chiller_temperature}."
f"Stayed at {tel_chiller_temp}"
)

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?

async def switch_lamp_on(self):
await self.white_light_source.cmd_turnLampOn.set_start(
power=self.whitelight_power, timeout=self.timeout_lamp_warm_up
)

await monochromator.cmd_changeWavelength.set_start(wavelength=self.wavelength)
async def wait_for_lamp_to_warm_up(self):
self.white_light_source.evt_lampState.flush()
start_time_lamp_warm_up = time.time()
while time.time() - start_time_lamp_warm_up < self.timeout_lamp_warm_up:
lamp_state = await self.white_light_source.evt_lampState.next(
flush=False, timeout=self.timeout_lamp_warm_up
)
if lamp_state.basicState == ATWhiteLight.LampBasicState.WARMUP:
warmup_time_left = (
lamp_state.warmupEndTime - lamp_state.private_sndStamp
)
self.log.info(f"Time Left for lamp warmup: {warmup_time_left} min.")
await asyncio.sleep(track_lamp_warmup)

await self.checkpoint("Set slits wide open")
elif lamp_state.basicState == ATWhiteLight.LampBasicState.ON:
self.log.info(
f"White Light Lamp is on after a warm up of {time.time() - start_time_lamp_warm_up} s"
)
else:
raise TimeoutError(
f"White Light Lamp failed to turn on after {self.timeout_lamp_warm_up} s"
)

async def configure_atmonochromator(self):
await self.monochromator.cmd_selectGrating.set_start(
gratingType=self.grating, timeout=self.cmd_timeout
)

await monochromator.cmd_changeSlitWidth.set_start(slit=1, slitWidth= self.entrance_slit_width)
await monochromator.cmd_changeSlitWidth.set_start(slit=2, slitWidth= self.exit_slit_width)
await self.monochromator.cmd_changeWavelength.set_start(
wavelength=self.wavelength, timeout=self.cmd_timeout
)

params = await get_monochromator_parameters()
await self.monochromator.cmd_changeSlitWidth.set_start(
slit=1, slitWidth=self.entrance_slit_width, timeout=self.cmd_timeout
)

script.log.info(f"ATMonochromator grating is {params[0]}, wavelength is {params[1]} nm with entry slit width {param[2]} and exit slit width {param[3]}")

async def get_monochromator_parameters():
tmp1 = await monochromator.evt_selectedGrating.aget()
tmp2 = await monochromator.evt_wavelength.aget()
tmp3 = await monochromator.evt_entrySlitWidth.aget()
tmp4 = await monochromator.evt_exitSlitWidth.aget()
return (tmp1.gratingType, tmp2.wavelength, tmp3.width, tmp4.width )
await self.monochromator.cmd_changeSlitWidth.set_start(
slit=2, slitWidth=self.exit_slit_width, timeout=self.cmd_timeout
)

params = await self.get_monochromator_parameters()

async def has_lamp_finish_warm_up():
lamp_done_warm_up = False
start_time_lamp_warm_up = time.time()
while not lamp_done_warm_up:
lamp_state = await whitelightsource.evt_lampState.aget()
if lamp_state.basicState == ATWhiteLight.LampBasicState.WARMUP:
warmup_time_left = lamp_state.warmupEndTime - lamp_state.private_rcvStamp
script.log.info("Time Left for lamp warmup: {} min.".format(warmup_time_left/60.))
await asyncio.sleep(self.track_lamp_warmup)
lamp_done_warm_up = False
elif lamp_state.basicState == ATWhiteLight.LampBasicState.ON:
lamp_done_warm_up = True
warm_up_elapsed_time = time.time() - start_time_lamp_warm_up
script.log.info(f"White Light Lamp is on after {warm_up_elapsed_time} s")
else:
continue
self.log.info(
f"ATMonochromator grating is {params[0]}, "
f"wavelength is {params[1]} nm "
f"with entry slit width {params[2]} "
f"and exit slit width {params[3]}"
)

async def is_chiller_temp_within_tolerance():
chiller_temp_within_tolerance = False
start_time_chill_time = time.time()
while not chiller_temp_within_tolerance:
chiller_temps = await whitelightsource.tel_chillerTemperatures.aget()
if (
chiller_temps.setTemperature * (1.0 - self.chiller_temp_tolerance_relative)
< chiller_temps.supplyTemperature
< chiller_temps.setTemperature * (1.0 + self.chiller_temp_tolerance_relative)
async def get_monochromator_parameters(self):
tmp1 = await self.monochromator.evt_selectedGrating.aget()
tmp2 = await self.monochromator.evt_wavelength.aget()
tmp3 = await self.monochromator.evt_entrySlitWidth.aget()
tmp4 = await self.monochromator.evt_exitSlitWidth.aget()
return (tmp1.gratingType, tmp2.wavelength, tmp3.width, tmp4.width)

async def assert_components_enabled(self):
"""Check if ATWhiteLight and ATMonochromator are ENABLED"""
for comp in [self.white_light_source, self.monochromator]:
summary_state = await comp.evt_summaryState.aget()
if salobj.State(summary_state.summaryState) != salobj.State(
salobj.State.ENABLED
):
chiller_temp_within_tolerance = True
chill_time = time.time() - start_time_chill_time
script.log.info(f"Chiller reached target temperature within tolerance in {chill_time} s")
else:
continue

raise Exception(f"{comp} is not ENABLED")
Loading

0 comments on commit 6127f47

Please sign in to comment.