39 Widget to simulate a closed loop
42 widget_ao.py [<parameters_filename>] [options]
44 with 'parameters_filename' the path to the parameters file
47 -h --help Show this help message and exit
48 --cacao Distribute data with cacao
49 --expert Display expert panel
50 -d, --devices devices Specify the devices
51 -i, --interactive keep the script interactive
59 import pyqtgraph
as pg
60 from pyqtgraph.dockarea
import Dock, DockArea
67 from PyQt5
import QtGui, QtWidgets
68 from PyQt5.uic
import loadUiType
69 from PyQt5.QtCore
import QThread, QTimer, Qt
71 from subprocess
import Popen, PIPE
73 from typing
import Any, Dict, Tuple, Callable, List
75 from docopt
import docopt
76 from collections
import deque
80 AOWindowTemplate, AOClassTemplate = uiLoader(
'widget_ao')
92 def __init__(self, config_file: Any =
None, cacao: bool =
False,
93 expert: bool =
False, devices: str =
None,
94 hide_histograms: bool =
False) ->
None:
95 WidgetBase.__init__(self, hide_histograms=hide_histograms)
96 AOClassTemplate.__init__(self)
107 self.
uiAO.setupUi(self)
117 self.
uiAO.wao_nbiters.setValue(1000)
127 self.
defaultParPath = os.environ[
"SHESHA_ROOT"] +
"/data/par/par4bench"
131 self.
uiAO.wao_run.setCheckable(
True)
133 self.
uiAO.wao_open_loop.setCheckable(
True)
136 self.
uiAO.wao_resetSR.clicked.connect(self.
resetSR)
144 self.
uiAO.wao_clearSR.clicked.connect(self.
clearSR)
147 self.
uiAO.wao_run.setDisabled(
True)
148 self.
uiAO.wao_next.setDisabled(
True)
149 self.
uiAO.wao_unzoom.setDisabled(
True)
150 self.
uiAO.wao_resetSR.setDisabled(
True)
152 p1 = self.
uiAO.wao_SRPlotWindow.addPlot(title=
'SR evolution')
153 self.
curveSRSE = p1.plot(pen=(255, 0, 0), symbolBrush=(255, 0, 0), name=
"SR SE")
154 self.
curveSRLE = p1.plot(pen=(0, 0, 255), symbolBrush=(0, 0, 255), name=
"SR LE")
168 self.
uiAO.wao_SRDock.setVisible(
False)
170 self.addDockWidget(Qt.DockWidgetArea(1), self.
uiBase.wao_ConfigDock)
171 self.addDockWidget(Qt.DockWidgetArea(1), self.
uiBase.wao_DisplayDock)
172 self.
uiBase.wao_ConfigDock.setFloating(
False)
173 self.
uiBase.wao_DisplayDock.setFloating(
False)
180 Qt.DockWidgetArea(1), self.
expertWidget.uiExpert.wao_expertDock)
181 self.
expertWidget.uiExpert.wao_expertDock.setFloating(
False)
185 if config_file
is not None:
186 self.
uiBase.wao_selectConfig.clear()
187 self.
uiBase.wao_selectConfig.addItem(config_file)
209 self.
uiAO.wao_resetSR_tarNum.setDisabled(state)
212 self.
uiAO.wao_nbiters.setDisabled(state)
218 if self.
uiAO.wao_allTarget.isChecked():
219 for t
in range(len(self.
config.p_targets)):
222 tarnum = self.
uiAO.wao_resetSR_tarNum.value()
223 print(
"Reset SR on target %d" % tarnum)
226 def add_dispDock(self, name: str, parent, type: str =
"pg_image") ->
None:
227 d = WidgetBase.add_dispDock(self, name, parent, type)
229 d.addWidget(self.
uiAO.wao_Strehl)
231 def load_config(self, *args, config_file=None, supervisor=None, **kwargs) -> None:
233 Callback when 'LOAD' button is hit
234 * required to catch positionals, as by default
235 if a positional is allowed the QPushButton will send a boolean value
236 and hence overwrite supervisor...
239 WidgetBase.load_config(self)
243 for key, pgpl
in self.
SRCrossX.items():
246 for key, pgpl
in self.
SRCrossY.items():
249 for key, pgpl
in self.
PyrEdgeX.items():
252 for key, pgpl
in self.
PyrEdgeY.items():
255 if config_file
is None:
256 config_file = str(self.
uiBase.wao_selectConfig.currentText())
259 if supervisor
is None:
260 self.
config = load_config_from_file(config_file)
266 self.
config.p_loop.set_devices([
282 for atm
in range(self.
natm):
283 name =
'atm_%d' % atm
287 for wfs
in range(self.
nwfs):
288 name =
'wfs_%d' % wfs
290 name =
'slpComp_%d' % wfs
292 name =
'slpGeom_%d' % wfs
294 if self.
config.p_wfss[wfs].type == scons.WFSType.SH:
298 wfs].type == scons.WFSType.PYRHR
or self.
config.p_wfss[
299 wfs].type == scons.WFSType.PYRLR:
300 name =
'pyrFocalPlane_%d' % wfs
302 name =
'pyrHR_%d' % wfs
304 name =
'pyrLR_%d' % wfs
307 raise "Analyser unknown"
310 for dm
in range(self.
ndm):
315 for tar
in range(self.
ntar):
316 name =
'tar_%d' % tar
318 for tar
in range(self.
ntar):
319 name =
'psfSE_%d' % tar
321 for tar
in range(self.
ntar):
322 name =
'psfLE_%d' % tar
327 self.
uiAO.wao_resetSR_tarNum.setValue(0)
328 self.
uiAO.wao_resetSR_tarNum.setMaximum(len(self.
config.p_targets) - 1)
330 self.
uiAO.wao_dispSR_tar.setValue(0)
331 self.
uiAO.wao_dispSR_tar.setMaximum(len(self.
config.p_targets) - 1)
333 self.
uiAO.wao_run.setDisabled(
True)
334 self.
uiAO.wao_next.setDisabled(
True)
335 self.
uiAO.wao_unzoom.setDisabled(
True)
336 self.
uiAO.wao_resetSR.setDisabled(
True)
338 self.
uiBase.wao_init.setDisabled(
False)
344 if (hasattr(self.
config,
"layout")):
346 self.
loadArea(filename=area_filename)
356 if self.
uiAO.wao_forever.isChecked():
357 print(
"LOOP STARTED")
359 print(
"LOOP STARTED FOR %d iterations" % self.
nbiter)
367 self.
uiAO.wao_open_loop.setText(
"Open Loop")
370 self.
uiAO.wao_open_loop.setText(
"Close Loop")
373 WidgetBase.init_config(self)
376 self.
uiAO.wao_deviceNumber.setDisabled(
True)
383 for i
in range(self.
natm):
385 data = self.
supervisor.atmos.get_atmos_layer(i)
387 data.shape[0], data.shape[1])
388 self.
SRcircles[key] = pg.ScatterPlotItem(cx, cy, pen=
'r', size=1)
392 for i
in range(self.
nwfs):
396 data.shape[0], data.shape[1])
397 self.
SRcircles[key] = pg.ScatterPlotItem(cx, cy, pen=
'r', size=1)
400 key =
'slpComp_%d' % i
401 key =
'slpGeom_%d' % i
408 for i
in range(self.
ndm):
410 dm_type = self.
config.p_dms[i].type
411 alt = self.
config.p_dms[i].alt
414 data.shape[0], data.shape[1])
415 self.
SRcircles[key] = pg.ScatterPlotItem(cx, cy, pen=
'r', size=1)
419 for i
in range(len(self.
config.p_targets)):
421 data = self.
supervisor.target.get_tar_phase(i)
423 data.shape[0], data.shape[1])
424 self.
SRcircles[key] = pg.ScatterPlotItem(cx, cy, pen=
'r', size=1)
428 data = self.
supervisor.target.get_tar_image(i)
429 for psf
in [
"psfSE_",
"psfLE_"]:
432 self.
SRCrossX[key] = pg.PlotCurveItem(
434 data.shape[0] / 2 + 0.5 - Delta,
435 data.shape[0] / 2 + 0.5 + Delta
436 ]), np.array([data.shape[1] / 2 + 0.5, data.shape[1] / 2 + 0.5]),
438 self.
SRCrossY[key] = pg.PlotCurveItem(
439 np.array([data.shape[0] / 2 + 0.5, data.shape[0] / 2 + 0.5]),
441 data.shape[1] / 2 + 0.5 - Delta,
442 data.shape[1] / 2 + 0.5 + Delta
449 for i
in range(len(self.
config.p_wfss)):
450 if (self.
config.p_wfss[i].type == scons.WFSType.PYRHR
or
451 self.
config.p_wfss[i].type == scons.WFSType.PYRLR):
452 key =
"pyrFocalPlane_%d" % i
453 data = self.
supervisor.wfs.get_pyr_focal_plane(i)
454 Delta = len(data) / 2
455 self.
PyrEdgeX[key] = pg.PlotCurveItem(
457 data.shape[0] / 2 + 0.5 - Delta,
458 data.shape[0] / 2 + 0.5 + Delta
459 ]), np.array([data.shape[1] / 2 + 0.5, data.shape[1] / 2 + 0.5]),
461 self.
PyrEdgeY[key] = pg.PlotCurveItem(
462 np.array([data.shape[0] / 2 + 0.5, data.shape[0] / 2 + 0.5]),
464 data.shape[1] / 2 + 0.5 - Delta,
465 data.shape[1] / 2 + 0.5 + Delta
479 self.
uiAO.wao_run.setDisabled(
False)
480 self.
uiAO.wao_next.setDisabled(
False)
481 self.
uiAO.wao_open_loop.setDisabled(
False)
482 self.
uiAO.wao_unzoom.setDisabled(
False)
483 self.
uiAO.wao_resetSR.setDisabled(
False)
485 WidgetBase.init_configFinished(self)
488 datashape1: int) -> Tuple[float, float]:
489 cx = ampli * np.sin((np.arange(npts) + 1) * 2. * np.pi / npts) + datashape0 / 2
490 cy = ampli * np.cos((np.arange(npts) + 1) * 2. * np.pi / npts) + datashape1 / 2
494 self.
SRLE = deque(maxlen=20)
495 self.
SRSE = deque(maxlen=20)
496 self.
numiter = deque(maxlen=20)
499 self.
SRLE.append(SRLE)
500 self.
SRSE.append(SRSE)
509 if not self.
loopLock.acquire(
False):
513 for key, dock
in self.
docks.items():
516 elif dock.isVisible():
517 index = int(key.split(
"_")[-1])
520 data = self.
supervisor.atmos.get_atmos_layer(index)
522 data = self.
supervisor.wfs.get_wfs_phase(index)
524 dm_type = self.
config.p_dms[index].type
525 alt = self.
config.p_dms[index].alt
526 data = self.
supervisor.dms.get_dm_shape(index)
528 data = self.
supervisor.target.get_tar_phase(index)
530 data = self.
supervisor.target.get_tar_image(index, expo_type=
"le")
532 data = self.
supervisor.target.get_tar_image(index, expo_type=
"se")
535 if (self.
uiAO.actionPSF_Log_Scale.isChecked()):
536 if np.any(data <= 0):
538 data[data <= 0] = np.min(data[data > 0])
539 data = np.log10(data)
540 if (self.
supervisor.get_frame_counter() < 10):
542 xRange=(data.shape[0] / 2 + 0.5 - self.
PSFzoom,
543 data.shape[0] / 2 + 0.5 + self.
PSFzoom),
544 yRange=(data.shape[1] / 2 + 0.5 - self.
PSFzoom,
545 data.shape[1] / 2 + 0.5 + self.
PSFzoom),
549 data = self.
supervisor.wfs.get_wfs_image(index)
551 data = self.
supervisor.wfs.get_wfs_image(index)
553 data = self.
supervisor.wfs.get_pyrhr_image(index)
554 if "pyrFocalPlane" in key:
555 data = self.
supervisor.wfs.get_pyr_focal_plane(index)
557 if (data
is not None):
562 self.
imgs[key].setImage(data, autoLevels=autoscale)
565 self.
imgs[key].canvas.axes.clear()
567 slopes = self.
supervisor.rtc.get_slopes_geom()
569 slopes, self.
config.p_wfss[index].nxsub,
570 self.
config.p_tel.cobs, returnquiver=
True
575 2 * p_wfs._nvalid
for p_wfs
in self.
config.p_wfss
577 first_ind = np.sum(nmes[:index], dtype=np.int32)
578 if (self.
config.p_wfss[index].type == scons.WFSType.PYRHR
579 or self.
config.p_wfss[index].type == scons.
583 centroids[first_ind:first_ind + nmes[index]],
585 wao.config.p_wfss[index]._validsubsx,
586 wao.config.p_wfss[index]._validsubsy
590 centroids[first_ind:first_ind + nmes[index]],
591 self.
config.p_wfss[index].nxsub,
592 self.
config.p_tel.cobs, returnquiver=
True
594 self.
imgs[key].canvas.axes.quiver(x, y, vx, vy)
595 self.
imgs[key].canvas.draw()
601 self.
uiAO.wao_strehlSE.setText(SRSE)
604 self.
uiAO.wao_strehlLE.setText(SRLE)
607 self.
uiAO.wao_currentFreq.setValue(freq)
610 if not self.
loopLock.acquire(
False):
611 print(
"Display locked")
617 for t
in range(len(self.
supervisor.config.p_targets)):
619 loopTime = time.time() - start
621 refreshDisplayTime = 1. / self.
uiBase.wao_frameRate.value()
623 if (time.time() - self.
refreshTime > refreshDisplayTime):
626 for t
in range(len(self.
config.p_targets)):
629 if (t == self.
uiAO.wao_dispSR_tar.value()
633 signal_se +=
"%1.2f " % SR[0]
634 signal_le +=
"%1.2f " % SR[1]
636 currentFreq = 1 / loopTime
645 "iter #%d SR: (L.E, S.E.)= (%s, %s) running at %4.1fHz (real %4.1fHz)"
646 % (self.
supervisor.get_frame_counter(), signal_le,
647 signal_se, refreshFreq, currentFreq))
650 except Exception
as e:
658 if not self.
uiAO.wao_forever.isChecked():
663 self.
uiAO.wao_run.setChecked(
False)
666 if __name__ ==
'__main__':
667 arguments = docopt(__doc__)
668 app = QtWidgets.QApplication(sys.argv)
669 app.setStyle(
'cleanlooks')
670 wao =
widgetAOWindow(arguments[
"<parameters_filename>"], cacao=arguments[
"--cacao"],
671 expert=arguments[
"--expert"], devices=arguments[
"--devices"])
673 if arguments[
"--interactive"]:
675 embed(os.path.basename(__file__), locals())