COMPASS  5.4.4
End-to-end AO simulation tool using GPU acceleration
widget_ao.py
1 #!/usr/bin/env python
2 
38 """
39 Widget to simulate a closed loop
40 
41 Usage:
42  widget_ao.py [<parameters_filename>] [options]
43 
44 with 'parameters_filename' the path to the parameters file
45 
46 Options:
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
52 """
53 
54 import os, sys
55 
56 import numpy as np
57 import time
58 
59 import pyqtgraph as pg
60 
61 from shesha.util.tools import plsh, plpyr
62 from shesha.config import ParamConfig
63 
64 try:
65  from PyQt5 import QtWidgets
66  from PyQt5.QtCore import Qt
67 except ModuleNotFoundError as e:
68  try:
69  from PySide2 import QtWidgets
70  from PySide2.QtCore import Qt
71  except ModuleNotFoundError as e:
72  raise ModuleNotFoundError("No module named 'PyQt5' or PySide2', please install one of them\nException raised: "+e.msg)
73 
74 from typing import Any, Dict, Tuple
75 
76 from docopt import docopt
77 from collections import deque
78 
79 from shesha.widgets.widget_base import WidgetBase, uiLoader
80 
81 AOWindowTemplate, AOClassTemplate = uiLoader('widget_ao')
82 
83 from shesha.supervisor.compassSupervisor import CompassSupervisor, scons
84 
85 # For debug
86 # from IPython.core.debugger import Pdb
87 # then add this line to create a breakpoint
88 # Pdb().set_trace()
89 
90 
92 
93  def __init__(self, config_file: Any = None, cacao: bool = False,
94  expert: bool = False, devices: str = None,
95  hide_histograms: bool = False, twoStages: bool = False) -> None:
96  WidgetBase.__init__(self, hide_histograms=hide_histograms)
97  AOClassTemplate.__init__(self)
98  self.twoStagestwoStages = twoStages
99  self.cacaocacao = cacao
100  self.rollingWindowrollingWindow = 100
101  self.SRLESRLE = deque(maxlen=self.rollingWindowrollingWindow)
102  self.SRSESRSE = deque(maxlen=self.rollingWindowrollingWindow)
103  self.numiternumiter = deque(maxlen=self.rollingWindowrollingWindow)
104  self.expertexpert = expert
105  self.devicesdevices = devices
106 
107  self.uiAOuiAO = AOWindowTemplate()
108  self.uiAOuiAO.setupUi(self)
109 
110 
113 
114  self.supervisorsupervisor = None
115  self.configconfig = None
116  self.stopstop = False # type: bool # Request quit
117 
118  self.uiAOuiAO.wao_nbiters.setValue(1000) # Default GUI nIter box value
119  self.nbiternbiter = self.uiAOuiAO.wao_nbiters.value()
120  self.refreshTimerefreshTime = 0 # type: float # System time at last display refresh
121  self.assistantassistant = None # type: Any
122 
123 
126 
127  # Default path for config files
128  self.defaultParPathdefaultParPathdefaultParPath = os.environ["SHESHA_ROOT"] + "/data/par/par4bench"
129  self.defaultAreaPathdefaultAreaPathdefaultAreaPath = os.environ["SHESHA_ROOT"] + "/data/layouts"
130  self.loadDefaultConfigloadDefaultConfig()
131 
132  self.uiAOuiAO.wao_run.setCheckable(True)
133  self.uiAOuiAO.wao_run.clicked[bool].connect(self.aoLoopClickedaoLoopClicked)
134  self.uiAOuiAO.wao_open_loop.setCheckable(True)
135  self.uiAOuiAO.wao_open_loop.clicked[bool].connect(self.aoLoopOpenaoLoopOpen)
136  self.uiAOuiAO.wao_next.clicked.connect(self.loop_onceloop_once)
137  self.uiAOuiAO.wao_resetSR.clicked.connect(self.resetSRresetSR)
138  self.uiAOuiAO.wao_resetCoro.clicked.connect(self.resetCororesetCoro)
139  # self.uiAO.wao_actionHelp_Contents.triggered.connect(self.on_help_triggered)
140 
141  self.uiAOuiAO.wao_allTarget.stateChanged.connect(self.updateAllTargetupdateAllTarget)
142  self.uiAOuiAO.wao_allCoro.stateChanged.connect(self.updateAllCoroupdateAllCoro)
143  self.uiAOuiAO.wao_forever.stateChanged.connect(self.updateForeverupdateForever)
144 
145  self.uiAOuiAO.wao_atmosphere.clicked[bool].connect(self.enable_atmosenable_atmos)
146  self.dispStatsInTerminaldispStatsInTerminal = False
147  self.uiAOuiAO.wao_clearSR.clicked.connect(self.clearSRclearSR)
148  # self.uiAO.actionStats_in_Terminal.toggled.connect(self.updateStatsInTerminal)
149 
150  self.uiAOuiAO.wao_run.setDisabled(True)
151  self.uiAOuiAO.wao_next.setDisabled(True)
152  self.uiAOuiAO.wao_unzoom.setDisabled(True)
153  self.uiAOuiAO.wao_resetSR.setDisabled(True)
154  self.uiAOuiAO.wao_resetCoro.setDisabled(True)
155  self.uiAOuiAO.wao_allCoro.setDisabled(True)
156 
157  p1 = self.uiAOuiAO.wao_SRPlotWindow.addPlot(title='SR evolution')
158  self.curveSRSEcurveSRSE = p1.plot(pen=(255, 0, 0), symbolBrush=(255, 0, 0), name="SR SE")
159  self.curveSRLEcurveSRLE = p1.plot(pen=(0, 0, 255), symbolBrush=(0, 0, 255), name="SR LE")
160 
161  self.SRCrossXSRCrossX = {} # type: Dict[str, pg.ScatterPlotItem]
162  self.SRCrossYSRCrossY = {} # type: Dict[str, pg.ScatterPlotItem]
163  self.SRcirclesSRcircles = {} # type: Dict[str, pg.ScatterPlotItem]
164  self.PyrEdgeXPyrEdgeX = {} # type: Dict[str, pg.ScatterPlotItem]
165  self.PyrEdgeYPyrEdgeY = {} # type: Dict[str, pg.ScatterPlotItem]
166 
167  self.natmnatm = 0
168  self.nwfsnwfs = 0
169  self.ndmndm = 0
170  self.ntarntar = 0
171  self.PSFzoomPSFzoom = 50
172  self.firstTimefirstTime = 1
173  self.uiAOuiAO.wao_SRDock.setVisible(False)
174 
175  self.addDockWidget(Qt.DockWidgetArea(1), self.uiBaseuiBase.wao_ConfigDock)
176  self.addDockWidget(Qt.DockWidgetArea(1), self.uiBaseuiBase.wao_DisplayDock)
177  self.uiBaseuiBase.wao_ConfigDock.setFloating(False)
178  self.uiBaseuiBase.wao_DisplayDock.setFloating(False)
179 
180  if expert:
181  from shesha.widgets.widget_ao_expert import WidgetAOExpert
182  self.expertWidgetexpertWidget = WidgetAOExpert()
183  # self.expertWidget.setupUi(self)
184  self.addDockWidget(
185  Qt.DockWidgetArea(1), self.expertWidgetexpertWidget.uiExpert.wao_expertDock)
186  self.expertWidgetexpertWidget.uiExpert.wao_expertDock.setFloating(False)
187 
188  self.adjustSize()
189 
190  if config_file is not None:
191  self.uiBaseuiBase.wao_selectConfig.clear()
192  self.uiBaseuiBase.wao_selectConfig.addItem(config_file)
193  self.load_configload_configload_config(config_file=config_file)
194  self.init_configinit_configinit_config()
195 
196  # def on_help_triggered(self, i: Any=None) -> None:
197  # if i is None:
198  # return
199  # if not self.assistant or \
200  # not self.assistant.poll():
201 
202  # helpcoll = os.environ["COMPASS_ROOT"] + "/doc/COMPASS.qhc"
203  # cmd = "assistant -enableRemoteControl -collectionFile %s" % helpcoll
204  # self.assistant = Popen(cmd, shell=True, stdin=PIPE)
205 
206 
209 
210  # def updateStatsInTerminal(self, state):
211  # self.dispStatsInTerminal = state
212 
213  def updateAllTarget(self, state):
214  self.uiAOuiAO.wao_resetSR_tarNum.setDisabled(state)
215 
216  def updateAllCoro(self, state):
217  self.uiAOuiAO.wao_resetCoro_coroNum.setDisabled(state)
218 
219  def updateForever(self, state):
220  self.uiAOuiAO.wao_nbiters.setDisabled(state)
221 
222  def enable_atmos(self, atmos):
223  self.supervisorsupervisor.atmos.enable_atmos(atmos)
224 
225  def resetSR(self) -> None:
226  if self.uiAOuiAO.wao_allTarget.isChecked():
227  for t in range(len(self.configconfig.p_targets)):
228  self.supervisorsupervisor.target.reset_strehl(t)
229  else:
230  tarnum = self.uiAOuiAO.wao_resetSR_tarNum.value()
231  print("Reset SR on target %d" % tarnum)
232  self.supervisorsupervisor.target.reset_strehl(tarnum)
233 
234  def resetCoro(self) -> None:
235  # TODO Adapt for multiple corono
236  if self.uiAOuiAO.wao_allCoro.isChecked():
237  for c in range(self.ncoroncoro):
238  self.supervisorsupervisor.corono.reset()
239  else:
240  coroNum = self.uiAOuiAO.wao_resetCoro_coroNum.value()
241  print("Reset Coro %d" % coroNum)
242  self.supervisorsupervisor.corono.reset()
243 
244  def add_dispDock(self, name: str, parent, type: str = "pg_image") -> None:
245  d = WidgetBase.add_dispDock(self, name, parent, type)
246  if type == "SR":
247  d.addWidget(self.uiAOuiAO.wao_Strehl)
248 
249  def load_config(self, *args, config_file=None, supervisor=None, **kwargs) -> None:
250  '''
251  Callback when 'LOAD' button is hit
252  * required to catch positionals, as by default
253  if a positional is allowed the QPushButton will send a boolean value
254  and hence overwrite supervisor...
255  '''
256 
257  WidgetBase.load_config(self)
258  for key, pgpl in self.SRcirclesSRcircles.items():
259  self.viewboxesviewboxes[key].removeItem(pgpl)
260 
261  for key, pgpl in self.SRCrossXSRCrossX.items():
262  self.viewboxesviewboxes[key].removeItem(pgpl)
263 
264  for key, pgpl in self.SRCrossYSRCrossY.items():
265  self.viewboxesviewboxes[key].removeItem(pgpl)
266 
267  for key, pgpl in self.PyrEdgeXPyrEdgeX.items():
268  self.viewboxesviewboxes[key].removeItem(pgpl)
269 
270  for key, pgpl in self.PyrEdgeYPyrEdgeY.items():
271  self.viewboxesviewboxes[key].removeItem(pgpl)
272 
273  if config_file is None:
274  config_file = str(self.uiBaseuiBase.wao_selectConfig.currentText())
275  sys.path.insert(0, self.defaultParPathdefaultParPathdefaultParPath)
276 
277  if supervisor is None:
278  self.configconfig = ParamConfig(config_file)
279  else:
280  self.configconfig = supervisor.get_config()
281 
282  if self.devicesdevices:
283  self.configconfig.p_loop.set_devices([
284  int(device) for device in self.devicesdevices.split(",")
285  ])
286 
287  try:
288  sys.path.remove(self.defaultParPathdefaultParPathdefaultParPath)
289  except:
290  pass
291 
292  self.SRcirclesSRcircles.clear()
293  self.SRCrossXSRCrossX.clear()
294  self.SRCrossYSRCrossY.clear()
295  self.PyrEdgeXPyrEdgeX.clear()
296  self.PyrEdgeYPyrEdgeY.clear()
297  self.nctrlnctrl = len(self.configconfig.p_controllers)
298  for ctrl in range(self.nctrlnctrl):
299  self.add_dispDockadd_dispDockadd_dispDock("modalGains_"+str(ctrl), self.wao_graphgroup_cbwao_graphgroup_cb, "MPL")
300 
301  self.natmnatm = len(self.configconfig.p_atmos.alt)
302  for atm in range(self.natmnatm):
303  name = 'atm_%d' % atm
304  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_phasesgroup_cbwao_phasesgroup_cb)
305 
306  self.nwfsnwfs = len(self.configconfig.p_wfss)
307  for wfs in range(self.nwfsnwfs):
308  name = 'wfs_%d' % wfs
309  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_phasesgroup_cbwao_phasesgroup_cb)
310  name = 'slpComp_%d' % wfs
311  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_graphgroup_cbwao_graphgroup_cb, "MPL")
312  name = 'slpGeom_%d' % wfs
313  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_graphgroup_cbwao_graphgroup_cb, "MPL")
314  if self.configconfig.p_wfss[wfs].type == scons.WFSType.SH:
315  name = 'SH_%d' % wfs
316  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
317  elif self.configconfig.p_wfss[
318  wfs].type == scons.WFSType.PYRHR or self.configconfig.p_wfss[
319  wfs].type == scons.WFSType.PYRLR:
320  name = 'pyrFocalPlane_%d' % wfs
321  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
322  name = 'pyrHR_%d' % wfs
323  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
324  name = 'pyrLR_%d' % wfs
325  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
326  else:
327  raise "Analyser unknown"
328 
329  self.ndmndm = len(self.configconfig.p_dms)
330  for dm in range(self.ndmndm):
331  name = 'dm_%d' % dm
332  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_phasesgroup_cbwao_phasesgroup_cb)
333 
334  self.ntarntar = len(self.configconfig.p_targets)
335  for tar in range(self.ntarntar):
336  name = 'tar_%d' % tar
337  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_phasesgroup_cbwao_phasesgroup_cb)
338  for tar in range(self.ntarntar):
339  name = 'psfSE_%d' % tar
340  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
341  for tar in range(self.ntarntar):
342  name = 'psfLE_%d' % tar
343  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
344  if(self.configconfig.p_coronos) is not None:
345  self.ncoroncoro = len(self.configconfig.p_coronos)
346  else:
347  self.ncoroncoro = 0
348  for coro in range(self.ncoroncoro):
349  name = 'coroImageLE_%d' % coro
350  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
351  for coro in range(self.ncoroncoro):
352  name = 'coroImageSE_%d' % coro
353  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
354  for coro in range(self.ncoroncoro):
355  name = 'coroPSFLE_%d' % coro
356  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
357  for coro in range(self.ncoroncoro):
358  name = 'coroPSFSE_%d' % coro
359  self.add_dispDockadd_dispDockadd_dispDock(name, self.wao_imagesgroup_cbwao_imagesgroup_cb)
360 
361  self.add_dispDockadd_dispDockadd_dispDock("Strehl", self.wao_graphgroup_cbwao_graphgroup_cb, "SR")
362  for coro in range(self.ncoroncoro):
363  self.add_dispDockadd_dispDockadd_dispDock(f"ContrastLE_{coro}", self.wao_graphgroup_cbwao_graphgroup_cb, "MPL")
364  self.add_dispDockadd_dispDockadd_dispDock(f"ContrastSE_{coro}", self.wao_graphgroup_cbwao_graphgroup_cb, "MPL")
365 
366  self.uiAOuiAO.wao_resetSR_tarNum.setValue(0)
367  self.uiAOuiAO.wao_resetSR_tarNum.setMaximum(len(self.configconfig.p_targets) - 1)
368 
369  self.uiAOuiAO.wao_resetCoro_coroNum.setValue(0)
370  self.uiAOuiAO.wao_resetCoro_coroNum.setMaximum(self.ncoroncoro - 1)
371 
372  self.uiAOuiAO.wao_dispSR_tar.setValue(0)
373  self.uiAOuiAO.wao_dispSR_tar.setMaximum(len(self.configconfig.p_targets) - 1)
374 
375  self.uiAOuiAO.wao_run.setDisabled(True)
376  self.uiAOuiAO.wao_next.setDisabled(True)
377  self.uiAOuiAO.wao_unzoom.setDisabled(True)
378  self.uiAOuiAO.wao_resetSR.setDisabled(True)
379  self.uiAOuiAO.wao_resetCoro.setDisabled(True)
380  self.uiAOuiAO.wao_allCoro.setDisabled(True)
381 
382  self.uiBaseuiBase.wao_init.setDisabled(False)
383 
384  if self.expertexpert:
385  self.expertWidgetexpertWidget.setSupervisor(self.supervisorsupervisor)
386  self.expertWidgetexpertWidget.updatePanels()
387 
388  if (hasattr(self.configconfig._config, "layout")):
389  area_filename = self.defaultAreaPathdefaultAreaPathdefaultAreaPath + "/" + self.configconfig._config.layout + ".area"
390  self.loadArealoadArea(filename=area_filename)
391 
392  self.adjustSize()
393 
394  def aoLoopClicked(self, pressed: bool) -> None:
395  if pressed:
396  self.stopstop = False
397  self.refreshTimerefreshTime = time.time()
398  self.nbiternbiter = self.uiAOuiAO.wao_nbiters.value()
399  if self.dispStatsInTerminaldispStatsInTerminal:
400  if self.uiAOuiAO.wao_forever.isChecked():
401  print("LOOP STARTED")
402  else:
403  print("LOOP STARTED FOR %d iterations" % self.nbiternbiter)
404  self.runrunrun()
405  else:
406  self.stopstop = True
407 
408  def aoLoopOpen(self, pressed: bool) -> None:
409  if (pressed):
410  self.supervisorsupervisor.rtc.close_loop()
411  self.uiAOuiAO.wao_open_loop.setText("Open Loop")
412  else:
413  self.supervisorsupervisor.rtc.open_loop()
414  self.uiAOuiAO.wao_open_loop.setText("Close Loop")
415 
416  def init_config(self) -> None:
417  if(self.twoStagestwoStages):
418  from shesha.supervisor.stageSupervisor import StageSupervisor, scons
419  self.supervisorsupervisor = StageSupervisor(self.configconfig, cacao=self.cacaocacao)
420  else:
421  self.supervisorsupervisor = CompassSupervisor(self.configconfig, cacao=self.cacaocacao)
422  WidgetBase.init_config(self)
423 
424  def init_configThread(self) -> None:
425  self.uiAOuiAO.wao_deviceNumber.setDisabled(True)
426 
427  def init_configFinished(self) -> None:
428  # Thread carmaWrap context reload:
429  self.supervisorsupervisor.force_context()
430 
431  for i in range(self.natmnatm):
432  key = "atm_%d" % i
433  data = self.supervisorsupervisor.atmos.get_atmos_layer(i)
434  cx, cy = self.circleCoordscircleCoords(self.configconfig.p_geom.pupdiam / 2, 1000,
435  data.shape[0], data.shape[1])
436  self.SRcirclesSRcircles[key] = pg.ScatterPlotItem(cx, cy, pen='r', size=1)
437  self.viewboxesviewboxes[key].addItem(self.SRcirclesSRcircles[key])
438  self.SRcirclesSRcircles[key].setData(cx, cy)
439 
440  for i in range(self.nwfsnwfs):
441  key = "wfs_%d" % i
442  data = self.supervisorsupervisor.wfs.get_wfs_phase(i)
443  cx, cy = self.circleCoordscircleCoords(self.configconfig.p_geom.pupdiam / 2, 1000,
444  data.shape[0], data.shape[1])
445  self.SRcirclesSRcircles[key] = pg.ScatterPlotItem(cx, cy, pen='r', size=1)
446  self.viewboxesviewboxes[key].addItem(self.SRcirclesSRcircles[key])
447  self.SRcirclesSRcircles[key].setData(cx, cy)
448  key = 'slpComp_%d' % i
449  key = 'slpGeom_%d' % i
450 
451  # if self.config.p_wfss[i].type == scons.WFSType.SH:
452  # key = "SH_%d" % i
453  # self.addSHGrid(self.docks[key].widgets[0],
454  # self.config.p_wfss[i].get_validsub(), 8, 8)
455 
456  for i in range(self.ndmndm):
457  key = "dm_%d" % i
458  dm_type = self.configconfig.p_dms[i].type
459  alt = self.configconfig.p_dms[i].alt
460  data = self.supervisorsupervisor.dms.get_dm_shape(i)
461  cx, cy = self.circleCoordscircleCoords(self.configconfig.p_geom.pupdiam / 2, 1000,
462  data.shape[0], data.shape[1])
463  self.SRcirclesSRcircles[key] = pg.ScatterPlotItem(cx, cy, pen='r', size=1)
464  self.viewboxesviewboxes[key].addItem(self.SRcirclesSRcircles[key])
465  self.SRcirclesSRcircles[key].setData(cx, cy)
466 
467  for i in range(len(self.configconfig.p_targets)):
468  key = "tar_%d" % i
469  data = self.supervisorsupervisor.target.get_tar_phase(i)
470  cx, cy = self.circleCoordscircleCoords(self.configconfig.p_geom.pupdiam / 2, 1000,
471  data.shape[0], data.shape[1])
472  self.SRcirclesSRcircles[key] = pg.ScatterPlotItem(cx, cy, pen='r', size=1)
473  self.viewboxesviewboxes[key].addItem(self.SRcirclesSRcircles[key])
474  self.SRcirclesSRcircles[key].setData(cx, cy)
475 
476  data = self.supervisorsupervisor.target.get_tar_image(i)
477  for psf in ["psfSE_", "psfLE_"]:
478  key = psf + str(i)
479  Delta = 5
480  self.SRCrossXSRCrossX[key] = pg.PlotCurveItem(
481  np.array([
482  data.shape[0] / 2 + 0.5 - Delta,
483  data.shape[0] / 2 + 0.5 + Delta
484  ]), np.array([data.shape[1] / 2 + 0.5, data.shape[1] / 2 + 0.5]),
485  pen='r')
486  self.SRCrossYSRCrossY[key] = pg.PlotCurveItem(
487  np.array([data.shape[0] / 2 + 0.5, data.shape[0] / 2 + 0.5]),
488  np.array([
489  data.shape[1] / 2 + 0.5 - Delta,
490  data.shape[1] / 2 + 0.5 + Delta
491  ]), pen='r')
492  # Put image in plot area
493  self.viewboxesviewboxes[key].addItem(self.SRCrossXSRCrossX[key])
494  # Put image in plot area
495  self.viewboxesviewboxes[key].addItem(self.SRCrossYSRCrossY[key])
496 
497 
498  for i in range(self.ncoroncoro):
499  data = self.supervisorsupervisor.corono.get_image(i, expo_type="se")
500  for psf in ["coroImageSE_", "coroImageLE_", "coroPSFSE_", "coroPSFLE_"]:
501  key = psf + str(i)
502  Delta = 5
503  if("Image" in key):
504  center = 0.
505  else:
506  center = 0.5
507  self.SRCrossXSRCrossX[key] = pg.PlotCurveItem(
508  np.array([
509  data.shape[0] / 2 + center - Delta,
510  data.shape[0] / 2 + center + Delta
511  ]), np.array([data.shape[1] / 2 + center, data.shape[1] / 2 + center]),
512  pen='r')
513  self.SRCrossYSRCrossY[key] = pg.PlotCurveItem(
514  np.array([data.shape[0] / 2 + center, data.shape[0] / 2 + center]),
515  np.array([
516  data.shape[1] / 2 + center - Delta,
517  data.shape[1] / 2 + center + Delta
518  ]), pen='r')
519  # Put image in plot area
520  self.viewboxesviewboxes[key].addItem(self.SRCrossXSRCrossX[key])
521  # Put image in plot area
522  self.viewboxesviewboxes[key].addItem(self.SRCrossYSRCrossY[key])
523 
524 
525 
526  for i in range(len(self.configconfig.p_wfss)):
527  if (self.configconfig.p_wfss[i].type == scons.WFSType.PYRHR or
528  self.configconfig.p_wfss[i].type == scons.WFSType.PYRLR):
529  key = "pyrFocalPlane_%d" % i
530  data = self.supervisorsupervisor.wfs.get_pyr_focal_plane(i)
531  Delta = len(data) / 2
532  self.PyrEdgeXPyrEdgeX[key] = pg.PlotCurveItem(
533  np.array([
534  data.shape[0] / 2 + 0.5 - Delta,
535  data.shape[0] / 2 + 0.5 + Delta
536  ]), np.array([data.shape[1] / 2 + 0.5, data.shape[1] / 2 + 0.5]),
537  pen='b')
538  self.PyrEdgeYPyrEdgeY[key] = pg.PlotCurveItem(
539  np.array([data.shape[0] / 2 + 0.5, data.shape[0] / 2 + 0.5]),
540  np.array([
541  data.shape[1] / 2 + 0.5 - Delta,
542  data.shape[1] / 2 + 0.5 + Delta
543  ]), pen='b')
544  # Put image in plot area
545  self.viewboxesviewboxes[key].addItem(self.PyrEdgeXPyrEdgeX[key])
546  # Put image in plot area
547  self.viewboxesviewboxes[key].addItem(self.PyrEdgeYPyrEdgeY[key])
548 
549  print(self.supervisorsupervisor)
550 
551  if self.expertexpert:
552  self.expertWidgetexpertWidget.displayRtcMatrix()
553 
554  self.updateDisplayupdateDisplayupdateDisplay()
555 
556  self.uiAOuiAO.wao_run.setDisabled(False)
557  self.uiAOuiAO.wao_next.setDisabled(False)
558  self.uiAOuiAO.wao_open_loop.setDisabled(False)
559  self.uiAOuiAO.wao_unzoom.setDisabled(False)
560  self.uiAOuiAO.wao_resetSR.setDisabled(False)
561  if(self.ncoroncoro):
562  self.uiAOuiAO.wao_resetCoro.setDisabled(False)
563  self.uiAOuiAO.wao_allCoro.setDisabled(False)
564 
565  WidgetBase.init_configFinished(self)
566 
567  def circleCoords(self, ampli: float, npts: int, datashape0: int,
568  datashape1: int) -> Tuple[float, float]:
569  cx = ampli * np.sin((np.arange(npts) + 1) * 2. * np.pi / npts) + datashape0 / 2
570  cy = ampli * np.cos((np.arange(npts) + 1) * 2. * np.pi / npts) + datashape1 / 2
571  return cx, cy
572 
573  def clearSR(self):
574  self.SRLESRLE = deque(maxlen=20)
575  self.SRSESRSE = deque(maxlen=20)
576  self.numiternumiter = deque(maxlen=20)
577 
578  def updateSRDisplay(self, SRLE, SRSE, numiter):
579  self.SRLESRLE.append(SRLE)
580  self.SRSESRSE.append(SRSE)
581  self.numiternumiter.append(numiter)
582  self.curveSRSEcurveSRSE.setData(self.numiternumiter, self.SRSESRSE)
583  self.curveSRLEcurveSRLE.setData(self.numiternumiter, self.SRLESRLE)
584 
585  def updateDisplay(self) -> None:
586  if (self.supervisorsupervisor is None or self.supervisorsupervisor.is_init is False):
587  # print("Widget not fully initialized")
588  return
589  if not self.loopLockloopLock.acquire(False):
590  return
591  else:
592  try:
593  for key, dock in self.docksdocks.items():
594  if key in ["Strehl"]:
595  continue
596  elif dock.isVisible():
597  index = int(key.split("_")[-1])
598  data = None
599  if "atm" in key:
600  data = self.supervisorsupervisor.atmos.get_atmos_layer(index)
601  if "wfs" in key:
602  data = self.supervisorsupervisor.wfs.get_wfs_phase(index)
603  if "dm" in key:
604  dm_type = self.configconfig.p_dms[index].type
605  alt = self.configconfig.p_dms[index].alt
606  data = self.supervisorsupervisor.dms.get_dm_shape(index)
607  if "tar" in key:
608  data = self.supervisorsupervisor.target.get_tar_phase(index)
609  if "psfLE" in key:
610  data = self.supervisorsupervisor.target.get_tar_image(
611  index, expo_type="le")
612  if "psfSE" in key:
613  data = self.supervisorsupervisor.target.get_tar_image(
614  index, expo_type="se")
615  if "coroImageLE" in key:
616  data = self.supervisorsupervisor.corono.get_image(index, expo_type="le")
617  if "coroImageSE" in key:
618  data = self.supervisorsupervisor.corono.get_image(index, expo_type="se")
619  if "coroPSFLE" in key:
620  data = self.supervisorsupervisor.corono.get_psf(index, expo_type="le")
621  if "coroPSFSE" in key:
622  data = self.supervisorsupervisor.corono.get_psf(index, expo_type="se")
623 
624  if "psf" in key or "coro" in key:
625  if (self.uiAOuiAO.actionPSF_Log_Scale.isChecked()):
626  if np.any(data <= 0):
627  # warnings.warn("\nZeros founds, filling with min nonzero value.\n")
628  data[data <= 0] = np.min(data[data > 0])
629  data = np.log10(data)
630  if (self.supervisorsupervisor.get_frame_counter() < 10):
631  self.viewboxesviewboxes[key].setRange(
632  xRange=(data.shape[0] / 2 + 0.5 - self.PSFzoomPSFzoom,
633  data.shape[0] / 2 + 0.5 + self.PSFzoomPSFzoom),
634  yRange=(data.shape[1] / 2 + 0.5 - self.PSFzoomPSFzoom,
635  data.shape[1] / 2 + 0.5 + self.PSFzoomPSFzoom),
636  )
637 
638  if "SH" in key:
639  data = self.supervisorsupervisor.wfs.get_wfs_image(index)
640  if "pyrLR" in key:
641  data = self.supervisorsupervisor.wfs.get_wfs_image(index)
642  if "pyrHR" in key:
643  data = self.supervisorsupervisor.wfs.get_pyrhr_image(index)
644  if "pyrFocalPlane" in key:
645  data = self.supervisorsupervisor.wfs.get_pyr_focal_plane(index)
646 
647  if (data is not None):
648  autoscale = True # self.uiAO.actionAuto_Scale.isChecked()
649  # if (autoscale):
650  # # inits levels
651  # self.hist.setLevels(data.min(), data.max())
652  self.imgsimgs[key].setImage(data, autoLevels=autoscale)
653  # self.p1.autoRange()
654  elif "slp" in key: # Slope display
655  self.imgsimgs[key].canvas.axes.clear()
656  if "Geom" in key:
657  slopes = self.supervisorsupervisor.rtc.get_slopes_geom()
658  x, y, vx, vy = plsh(
659  slopes, self.configconfig.p_wfss[index].nxsub,
660  self.configconfig.p_tel.cobs, returnquiver=True
661  ) # Preparing mesh and vector for display
662  if "Comp" in key:
663  centroids = self.supervisorsupervisor.rtc.get_slopes(index)
664  nmes = [
665  2 * p_wfs._nvalid for p_wfs in self.configconfig.p_wfss
666  ]
667  first_ind = np.sum(nmes[:index], dtype=np.int32)
668  if (self.configconfig.p_wfss[index].type == scons.WFSType.PYRHR
669  or self.configconfig.p_wfss[index].type == scons.
670  WFSType.PYRLR):
671  #TODO: DEBUG... with full pixels (only works with classic slopes method)
672  plpyr(
673  centroids[first_ind:first_ind + nmes[index]],
674  np.stack([
675  self.configconfig.p_wfss[index]._validsubsx,
676  self.configconfig.p_wfss[index]._validsubsy
677  ]))
678  else:
679  x, y, vx, vy = plsh(
680  centroids[first_ind:first_ind + nmes[index]],
681  self.configconfig.p_wfss[index].nxsub,
682  self.configconfig.p_tel.cobs, returnquiver=True
683  ) # Preparing mesh and vector for display
684  self.imgsimgs[key].canvas.axes.quiver(x, y, vx, vy)
685  self.imgsimgs[key].canvas.draw()
686  elif "modalGains" in key:
687  data = self.supervisorsupervisor.rtc.get_modal_gains(index)
688  self.imgsimgs[key].canvas.axes.clear()
689  self.imgsimgs[key].canvas.axes.plot(data)
690  self.imgsimgs[key].canvas.draw()
691  elif "ContrastLE" in key:
692  distances, mean, std, mini, maxi = self.supervisorsupervisor.corono.get_contrast(index, expo_type='le')
693  if(np.all(mean)):
694  self.imgsimgs[key].canvas.axes.clear()
695  self.imgsimgs[key].canvas.axes.plot(distances, mean)
696  self.imgsimgs[key].canvas.axes.set_yscale('log')
697  self.imgsimgs[key].canvas.axes.set_xlabel("angular distance (Lambda/D)")
698  self.imgsimgs[key].canvas.axes.set_ylabel("Raw contrast")
699 
700  self.imgsimgs[key].canvas.axes.grid()
701  self.imgsimgs[key].canvas.draw()
702  elif "ContrastSE" in key:
703  distances, mean, std, mini, maxi = self.supervisorsupervisor.corono.get_contrast(index, expo_type='se')
704  if(np.all(mean)):
705  self.imgsimgs[key].canvas.axes.clear()
706  self.imgsimgs[key].canvas.axes.plot(distances, mean)
707  self.imgsimgs[key].canvas.axes.set_yscale('log')
708  self.imgsimgs[key].canvas.axes.set_xlabel("angular distance (Lambda/D)")
709  self.imgsimgs[key].canvas.axes.set_ylabel("Raw contrast")
710  self.imgsimgs[key].canvas.axes.grid()
711  self.imgsimgs[key].canvas.draw()
712  self.firstTimefirstTime = 1
713 
714  finally:
715  self.loopLockloopLock.release()
716 
717  def updateSRSE(self, SRSE):
718  self.uiAOuiAO.wao_strehlSE.setText(SRSE)
719 
720  def updateSRLE(self, SRLE):
721  self.uiAOuiAO.wao_strehlLE.setText(SRLE)
722 
723  def updateCurrentLoopFrequency(self, freq):
724  self.uiAOuiAO.wao_currentFreq.setValue(freq)
725 
726  def loop_once(self) -> None:
727  if not self.loopLockloopLock.acquire(False):
728  print("Display locked")
729  return
730  else:
731  try:
732  start = time.time()
733  self.supervisorsupervisor.next()
734  for t in range(len(self.supervisorsupervisor.config.p_targets)):
735  self.supervisorsupervisor.target.comp_tar_image(t)
736  loopTime = time.time() - start
737 
738  refreshDisplayTime = 1. / self.uiBaseuiBase.wao_frameRate.value()
739 
740  if (time.time() - self.refreshTimerefreshTime > refreshDisplayTime):
741  signal_le = ""
742  signal_se = ""
743  for t in range(len(self.configconfig.p_targets)):
744  SR = self.supervisorsupervisor.target.get_strehl(t)
745  # TODO: handle that !
746  if (t == self.uiAOuiAO.wao_dispSR_tar.value()
747  ): # Plot on the wfs selected
748  self.updateSRDisplayupdateSRDisplay(SR[1], SR[0],
749  self.supervisorsupervisor.get_frame_counter())
750  signal_se += "%1.2f " % SR[0]
751  signal_le += "%1.2f " % SR[1]
752 
753  currentFreq = 1 / loopTime
754  refreshFreq = 1 / (time.time() - self.refreshTimerefreshTime)
755 
756  self.updateSRSEupdateSRSE(signal_se)
757  self.updateSRLEupdateSRLE(signal_le)
758  self.updateCurrentLoopFrequencyupdateCurrentLoopFrequency(currentFreq)
759 
760  if (self.dispStatsInTerminaldispStatsInTerminal):
761  self.printInPlaceprintInPlace(
762  "iter #%d SR: (L.E, S.E.)= (%s, %s) running at %4.1fHz (real %4.1fHz)"
763  % (self.supervisorsupervisor.get_frame_counter(), signal_le,
764  signal_se, refreshFreq, currentFreq))
765 
766  self.refreshTimerefreshTime = start
767  except Exception as e:
768  print(e)
769  print("error!!")
770  raise e
771  finally:
772  self.loopLockloopLock.release()
773 
774  def run(self):
775  WidgetBase.run(self)
776  if not self.uiAOuiAO.wao_forever.isChecked():
777  self.nbiternbiter -= 1
778 
779  if self.nbiternbiter <= 0:
780  self.stopstop = True
781  self.uiAOuiAO.wao_run.setChecked(False)
782 
783 import os
784 import socket
785 
787  # get the display from the environment
788  display_env = os.environ['DISPLAY']
789 
790  # parse the display string
791  display_host, display_num = display_env.split(':')
792  display_num_major = display_num.split('.')[0]
793 
794  # calculate the port number
795  display_port = 6000 + int(display_num_major)
796 
797  # attempt a TCP connection
798  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
799  try:
800  sock.connect((display_host, display_port))
801  except socket.error:
802  return False
803  finally:
804  sock.close()
805  return True
806 
807 if __name__ == '__main__':
808  # if(not tcp_connect_to_display()):
809  # raise RuntimeError("Cannot connect to display")
810 
811  arguments = docopt(__doc__)
812  app = QtWidgets.QApplication(sys.argv)
813  app.setStyle('cleanlooks')
814  wao = widgetAOWindow(arguments["<parameters_filename>"], cacao=arguments["--cacao"],
815  expert=arguments["--expert"], devices=arguments["--devices"])
816  wao.show()
817 
818  print("")
819  print("If the GUI is black, you can:")
820  print(" type %gui qt5 to unlock GUI")
821  print(" or launch ipython with the option '--gui=qt' or '--matplotlib=qt'")
822  print(" or edit ~/.ipython/profile_default/ipython_config.py to set c.TerminalIPythonApp.matplotlib = 'qt'")
823 
824  if arguments["--interactive"]:
825  from shesha.util.ipython_embed import embed
826  embed(os.path.basename(__file__), locals())
Shesha parameters configuration class.
Definition: pconfig.py:51
This class implements generic supervisor to handle compass simulation.
None aoLoopOpen(self, bool pressed)
Definition: widget_ao.py:408
def updateSRDisplay(self, SRLE, SRSE, numiter)
Definition: widget_ao.py:578
None load_config(self, *args, config_file=None, supervisor=None, **kwargs)
Callback when 'LOAD' button is hit.
Definition: widget_ao.py:255
None __init__(self, Any config_file=None, bool cacao=False, bool expert=False, str devices=None, bool hide_histograms=False, bool twoStages=False)
Definition: widget_ao.py:95
Tuple[float, float] circleCoords(self, float ampli, int npts, int datashape0, int datashape1)
Definition: widget_ao.py:568
None add_dispDock(self, str name, parent, str type="pg_image")
Definition: widget_ao.py:244
def updateAllTarget(self, state)
METHODS #.
Definition: widget_ao.py:213
None aoLoopClicked(self, bool pressed)
Definition: widget_ao.py:394
def loadArea(self, widget=None, filename=None)
Definition: widget_base.py:207
None load_config(self, *args, **kwargs)
Callback when 'LOAD' button is hit.
Definition: widget_base.py:311
Dock add_dispDock(self, str name, parent, str type="pg_image")
Definition: widget_base.py:262
void split(std::vector< std::string > &tokens, const std::string &text, char sep)
Definition: carma_utils.h:71
Parameter classes for COMPASS.
Initialization and execution of a COMPASS supervisor.
Initialization and execution of a single stage supervisor for cascaded AO systems.
Imported from CANARY.
Definition: tools.py:1
Abstract Widget base.
Definition: widget_base.py:1