COMPASS  5.0.0
End-to-end AO simulation tool using GPU acceleration
genericSupervisor.py
1 
37 
38 from abc import abstractmethod
39 import numpy as np
40 import time
41 from shesha.sutra_wrap import carmaWrap_context
42 from typing import Iterable
43 
44 
45 
46 class GenericSupervisor(object):
47  """ This class defines generic methods and behavior of a supervisor
48  It is not intended to be instantiated as it is : prefer to build
49  a supervisor class inheriting from it. This approach allows to build multiple
50  supervisors with various components and less effort
51 
52  Attributes:
53  context : (CarmaContext) : a CarmaContext instance
54 
55  config : (config) : Parameters structure
56 
57  telescope : (TelescopeComponent) : a TelescopeComponent instance
58 
59  atmos : (AtmosComponent) : An AtmosComponent instance
60 
61  target : (targetComponent) : A TargetComponent instance
62 
63  wfs : (WfsComponent) : A WfsComponent instance
64 
65  dms : (DmComponent) : A DmComponent instance
66 
67  rtc : (RtcComponent) : A Rtc component instance
68 
69  is_init : (bool) : Flag equals to True if the supervisor has already been initialized
70 
71  iter : (int) : Frame counter
72  """
73  def __init__(self, config):
74  """ Init the a supervisor
75 
76  Parameters:
77  config : (config module) : Configuration module
78  """
79  self.context = None
80  self.config = config
81  self.telescope = None
82  self.atmos = None
83  self.target = None
84  self.wfs = None
85  self.dms = None
86  self.rtc = None
87  self.is_init = False
88  self.iter = 0
89  self._init_components()
90 
91  def get_config(self):
92  """ Returns the configuration in use, in a supervisor specific format ?
93 
94  Return:
95  config : (config module) : Current supervisor configuration
96  """
97  return self.config
98 
99  def get_frame_counter(self) -> int:
100  """Return the current iteration number of the loop
101 
102  Return:
103  framecounter : (int) : Number of iteration already performed
104  """
105  return self.iter
106 
107  def force_context(self) -> None:
108  """ Active all the GPU devices specified in the parameters file
109  """
110  if self.context is not None:
111  current_device = self.context.active_device
112  for device in range(len(self.config.p_loop.devices)):
114  self.context.set_active_device(current_device)
115 
116  def _init_components(self) -> None:
117  """ Initialize all the components
118  """
119  if (self.config.p_loop.devices.size > 1):
120  self.context = carmaWrap_context.get_instance_ngpu(
121  self.config.p_loop.devices.size, self.config.p_loop.devices)
122  else:
123  self.context = carmaWrap_context.get_instance_1gpu(
124  self.config.p_loop.devices[0])
126 
127  if self.config.p_tel is None or self.config.p_geom is None:
128  raise ValueError("Telescope geometry must be defined (p_geom and p_tel)")
129  self._init_tel()
130 
131  if self.config.p_atmos is not None:
132  self._init_atmos()
133  if self.config.p_dms is not None:
134  self._init_dms()
135  if self.config.p_targets is not None:
136  self._init_target()
137  if self.config.p_wfss is not None:
138  self._init_wfs()
139  if self.config.p_controllers is not None or self.config.p_centroiders is not None:
140  self._init_rtc()
141 
142  self.is_init = True
143 
144  @abstractmethod
145  def _init_tel(self):
146  """ Initialize the telescope component of the supervisor
147  """
148  pass
149 
150  @abstractmethod
151  def _init_atmos(self):
152  """ Initialize the atmos component of the supervisor
153  """
154  pass
155 
156  @abstractmethod
157  def _init_dms(self):
158  """ Initialize the dms component of the supervisor
159  """
160  pass
161 
162  @abstractmethod
163  def _init_target(self):
164  """ Initialize the target component of the supervisor
165  """
166  pass
167 
168  @abstractmethod
169  def _init_wfs(self):
170  """ Initialize the wfs component of the supervisor
171  """
172  pass
173 
174  @abstractmethod
175  def _init_rtc(self):
176  """ Initialize the rtc component of the supervisor
177  """
178  pass
179 
180  def next(self, *, move_atmos: bool = True, nControl: int = 0,
181  tar_trace: Iterable[int] = None, wfs_trace: Iterable[int] = None,
182  do_control: bool = True, apply_control: bool = True,
183  compute_tar_psf: bool = True) -> None:
184  """Iterates the AO loop, with optional parameters
185 
186  Parameters :
187  move_atmos: (bool), optional: move the atmosphere for this iteration. Default is True
188 
189  nControl: (int, optional): Controller number to use. Default is 0 (single control configuration)
190 
191  tar_trace: (List, optional): list of targets to trace. None is equivalent to all (default)
192 
193  wfs_trace: (List, optional): list of WFS to trace. None is equivalent to all (default)
194 
195  do_control : (bool, optional) : Performs RTC operations if True (Default)
196 
197  apply_control: (bool): (optional) if True (default), apply control on DMs
198 
199  compute_tar_psf : (bool, optional) : If True (default), computes the PSF at the end of the iteration
200  """
201  if tar_trace is None and self.target is not None:
202  tar_trace = range(len(self.config.p_targets))
203  if wfs_trace is None and self.wfs is not None:
204  wfs_trace = range(len(self.config.p_wfss))
205 
206  if move_atmos and self.atmos is not None:
207  self.atmos.move_atmos()
208 
209  if tar_trace is not None:
210  for t in tar_trace:
211  if self.atmos.is_enable:
212  self.target.raytrace(t, tel=self.tel, atm=self.atmos, dms=self.dms)
213  else:
214  self.target.raytrace(t, tel=self.tel, dms=self.dms)
215 
216  if wfs_trace is not None:
217  for w in wfs_trace:
218  if self.atmos.is_enable:
219  self.wfs.raytrace(w, tel=self.tel, atm=self.atmos)
220  else:
221  self.wfs.raytrace(w, tel=self.tel)
222 
223  if not self.config.p_wfss[w].open_loop and self.dms is not None:
224  self.wfs.raytrace(w, dms=self.dms, reset=False)
225  self.wfs.compute_wfs_image(w)
226  if do_control and self.rtc is not None:
227  for ncontrol in range(len(self.config.p_controllers)):
228  self.rtc.do_centroids(ncontrol)
229  self.rtc.do_control(ncontrol)
230  self.rtc.do_clipping(ncontrol)
231 
232  if apply_control:
233  self.rtc.apply_control(ncontrol)
234 
235  if compute_tar_psf:
236  for tar_index in tar_trace:
237  self.target.comp_tar_image(tar_index)
238  self.target.comp_strehl(tar_index)
239 
240  self.iter += 1
241 
242  def _print_strehl(self, monitoring_freq: int, iters_time: float, total_iters: int,
243  *, tar_index: int=0):
244  """ Print the Strehl ratio SE and LE from a target on the terminal, the estimated remaining time and framerate
245 
246  Parameters:
247  monitoring_freq : (int) : Number of frames between two prints
248 
249  iters_time : (float) : time elapsed between two prints
250 
251  total_iters : (int) : Total number of iterations
252 
253  tar_index : (int, optional) : Index of the target. Default is 0
254  """
255  framerate = monitoring_freq / iters_time
256  strehl = self.target.get_strehl(tar_index)
257  etr = (total_iters - self.iter) / framerate
258  print("%d \t %.3f \t %.3f\t %.1f \t %.1f" % (self.iter + 1, strehl[0], strehl[1],
259  etr, framerate))
260 
261  def loop(self, number_of_iter: int, *, monitoring_freq: int = 100, compute_tar_psf: bool = True,
262  **kwargs):
263  """ Perform the AO loop for <number_of_iter> iterations
264 
265  Parameters :
266  number_of_iter: (int) : Number of iteration that will be done
267 
268  monitoring_freq: (int, optional) : Monitoring frequency [frames]. Default is 100
269 
270  compute_tar_psf : (bool, optional) : If True (default), computes the PSF at each iteration
271  Else, only computes it each <monitoring_freq> frames
272  """
273  if not compute_tar_psf:
274  print("WARNING: Target PSF will be computed (& accumulated) only during monitoring"
275  )
276 
277  print("----------------------------------------------------")
278  print("iter# | S.E. SR | L.E. SR | ETR (s) | Framerate (Hz)")
279  print("----------------------------------------------------")
280  # self.next(**kwargs)
281  t0 = time.time()
282  t1 = time.time()
283  if number_of_iter == -1: # Infinite loop
284  while (True):
285  self.next(compute_tar_psf=compute_tar_psf, **kwargs)
286  if ((self.iter + 1) % monitoring_freq == 0):
287  if not compute_tar_psf:
288  self.comp_tar_image(0)
289  self.comp_strehl(0)
290  self._print_strehl(monitoring_freq, time.time() - t1, number_of_iter)
291  t1 = time.time()
292 
293  for _ in range(number_of_iter):
294  self.next(compute_tar_psf=compute_tar_psf, **kwargs)
295  if ((self.iter + 1) % monitoring_freq == 0):
296  if not compute_tar_psf:
297  self.target.comp_tar_image(0)
298  self.target.comp_strehl(0)
299  self._print_strehl(monitoring_freq, time.time() - t1, number_of_iter)
300  t1 = time.time()
301  t1 = time.time()
302  print(" loop execution time:", t1 - t0, " (", number_of_iter, "iterations), ", (t1 - t0) / number_of_iter,
303  "(mean) ", number_of_iter / (t1 - t0), "Hz")
304 
305  def reset(self):
306  """ Reset the simulation to return to its original state
307  """
308  self.atmos.reset_turbu()
309  self.wfs.reset_noise()
310  for tar_index in range(len(self.config.p_targets)):
311  self.target.reset_strehl(tar_index)
312  self.dms.reset_dm()
313  self.rtc.open_loop()
314  self.rtc.close_loop()
315 
shesha.supervisor.genericSupervisor.GenericSupervisor.target
target
Definition: genericSupervisor.py:112
shesha.supervisor.genericSupervisor.GenericSupervisor.force_context
None force_context(self)
Active all the GPU devices specified in the parameters file.
Definition: genericSupervisor.py:138
shesha.sutra_wrap
Definition: sutra_wrap.py:1
set_active_device
#define set_active_device(new_device, silent)
Definition: carma_context.h:97
shesha.supervisor.genericSupervisor.GenericSupervisor.config
config
Definition: genericSupervisor.py:109
shesha.supervisor.genericSupervisor.GenericSupervisor._init_atmos
def _init_atmos(self)
Initialize the atmos component of the supervisor.
Definition: genericSupervisor.py:188
shesha.supervisor.genericSupervisor.GenericSupervisor._init_dms
def _init_dms(self)
Initialize the dms component of the supervisor.
Definition: genericSupervisor.py:196
shesha.supervisor.genericSupervisor.GenericSupervisor._init_rtc
def _init_rtc(self)
Initialize the rtc component of the supervisor.
Definition: genericSupervisor.py:220
shesha.supervisor.genericSupervisor.GenericSupervisor._init_tel
def _init_tel(self)
Initialize the telescope component of the supervisor.
Definition: genericSupervisor.py:180
shesha.supervisor.genericSupervisor.GenericSupervisor.context
context
Definition: genericSupervisor.py:108
shesha.supervisor.genericSupervisor.GenericSupervisor.telescope
telescope
Definition: genericSupervisor.py:110
shesha.supervisor.genericSupervisor.GenericSupervisor.loop
def loop(self, int number_of_iter, *int monitoring_freq=100, bool compute_tar_psf=True, **kwargs)
Perform the AO loop for <number_of_iter> iterations.
Definition: genericSupervisor.py:316
shesha.supervisor.genericSupervisor.GenericSupervisor.wfs
wfs
Definition: genericSupervisor.py:113
shesha.supervisor.genericSupervisor.GenericSupervisor.reset
def reset(self)
Reset the simulation to return to its original state.
Definition: genericSupervisor.py:352
shesha.supervisor.genericSupervisor.GenericSupervisor.__init__
def __init__(self, config)
Definition: genericSupervisor.py:107
shesha.supervisor.genericSupervisor.GenericSupervisor.is_init
is_init
Definition: genericSupervisor.py:116
open_loop
Definition: open_loop.py:1
shesha.supervisor.genericSupervisor.GenericSupervisor
This class defines generic methods and behavior of a supervisor It is not intended to be instantiated...
Definition: genericSupervisor.py:53
shesha.supervisor.genericSupervisor.GenericSupervisor.next
None next(self, *bool move_atmos=True, int nControl=0, Iterable[int] tar_trace=None, Iterable[int] wfs_trace=None, bool do_control=True, bool apply_control=True, bool compute_tar_psf=True)
Iterates the AO loop, with optional parameters.
Definition: genericSupervisor.py:240
shesha.supervisor.genericSupervisor.GenericSupervisor.iter
iter
Init the a supervisor.
Definition: genericSupervisor.py:117
shesha.supervisor.genericSupervisor.GenericSupervisor.get_config
def get_config(self)
Returns the configuration in use, in a supervisor specific format ?
Definition: genericSupervisor.py:125
shesha.supervisor.genericSupervisor.GenericSupervisor.get_frame_counter
int get_frame_counter(self)
Return the current iteration number of the loop.
Definition: genericSupervisor.py:133
shesha.supervisor.genericSupervisor.GenericSupervisor._init_components
None _init_components(self)
Initialize all the components.
Definition: genericSupervisor.py:149
shesha.supervisor.genericSupervisor.GenericSupervisor.rtc
rtc
Definition: genericSupervisor.py:115
shesha.supervisor.genericSupervisor.GenericSupervisor.dms
dms
Definition: genericSupervisor.py:114
shesha.supervisor.genericSupervisor.GenericSupervisor.atmos
atmos
Definition: genericSupervisor.py:111
shesha.supervisor.genericSupervisor.GenericSupervisor._init_wfs
def _init_wfs(self)
Initialize the wfs component of the supervisor.
Definition: genericSupervisor.py:212
set_active_device_force
#define set_active_device_force(new_device, silent)
Definition: carma_context.h:99
shesha.supervisor.genericSupervisor.GenericSupervisor._init_target
def _init_target(self)
Initialize the target component of the supervisor.
Definition: genericSupervisor.py:204
shesha.supervisor.genericSupervisor.GenericSupervisor._print_strehl
def _print_strehl(self, int monitoring_freq, float iters_time, int total_iters, *int tar_index=0)
Print the Strehl ratio SE and LE from a target on the terminal, the estimated remaining time and fram...
Definition: genericSupervisor.py:298