COMPASS  5.4.4
End-to-end AO simulation tool using GPU acceleration
pconfig.py
1 
36 import importlib
37 import sys, os
38 from collections import OrderedDict
39 import numpy as np
40 import shesha.constants as scons
41 from typing import NoReturn, Dict
42 
43 class ParamConfig(object):
44  """ Shesha parameters configuration class. It embeds all the
45  parameters classes instances needed for the simulation run.
46 
47  This class also exposes most useful getters from its components
48  to allow an easier access and exposition through Pyro
49 
50  Attributes:
51  simul_name : (str) : Simulation run name
52 
53  p_atmos : (Param_atmos) : A Param_atmos instance
54 
55  p_geom : (Param_geom) : A Param_geom instance
56 
57  p_tel : (Param_tel) : A Param_tel instance
58 
59  p_dms : (List of Param_dm) : List of Param_dm instance
60 
61  p_wfss : (List of Param_wfs) : List of Param_wfs instance
62 
63  p_targets : (List of Param_target) : List of Param_target instance
64 
65  p_loop : (Param_loop) : A Param_loop instance
66 
67  p_centroiders : (List of Param_centroider) : List of Param_centroider instance
68 
69  p_controllers : (List of Param_controller) : List of Param controller instance
70 
71  _config : (configuration module from parfile) : Raw parameter file module
72  """
73  def __init__(self, param_file : str):
74  self._load_config_from_file_load_config_from_file(param_file)
75  self.simul_namesimul_name = self._config_config.simul_name
76  self.p_atmosp_atmos = self._config_config.p_atmos
77  self.p_telp_tel = self._config_config.p_tel
78  self.p_geomp_geom = self._config_config.p_geom
79  self.p_wfssp_wfss = self._config_config.p_wfss
80  self.p_dmsp_dms = self._config_config.p_dms
81  self.p_targetsp_targets = self._config_config.p_targets
82  self.p_loopp_loop = self._config_config.p_loop
83  self.p_centroidersp_centroiders = self._config_config.p_centroiders
84  self.p_controllersp_controllers = self._config_config.p_controllers
85  self.p_coronosp_coronos = self._config_config.p_coronos
86 
87  def _load_config_from_file(self, filename_path: str) -> NoReturn:
88  """ Load the parameters from the parameters file
89 
90  Args:
91  filename_path: (str): path to the parameters file
92  """
93  path = os.path.dirname(os.path.abspath(filename_path))
94  filename = os.path.basename(filename_path)
95  name, ext = os.path.splitext(filename)
96 
97  if (ext == ".py"):
98  if (path not in sys.path):
99  sys.path.insert(0, path)
100 
101  return self._load_config_from_module_load_config_from_module(name)
102 
103  # exec("import %s as wao_config" % filename)
104  sys.path.remove(path)
105  elif importlib.util.find_spec(filename_path) is not None:
106  return self._load_config_from_module_load_config_from_module(filename_path)
107  else:
108  raise ValueError("Config file must be .py or a module")
109 
110 
111  def _load_config_from_module(self, filepath: str) -> NoReturn:
112  """
113  Load the parameters from the parameters module
114 
115  Args:
116  filename_path: (str): path to the parameters file
117 
118  Returns:
119  config : (config) : a config module
120  """
121  filename = filepath.split('.')[-1]
122  print("loading: %s" % filename)
123 
124  config = importlib.import_module(filepath)
125  del sys.modules[config.__name__] # Forced reload
126  self._config_config = importlib.import_module(filepath)
127 
128  if hasattr(config, 'par'):
129  self._config_config = getattr("config.par.par4bench", filename)
130 
131  # Set missing config attributes to None
132  if not hasattr(self._config_config, 'p_loop'):
133  self._config_config.p_loop = None
134  if not hasattr(self._config_config, 'p_geom'):
135  self._config_config.p_geom = None
136  if not hasattr(self._config_config, 'p_tel'):
137  self._config_config.p_tel = None
138  if not hasattr(self._config_config, 'p_atmos'):
139  self._config_config.p_atmos = None
140  if not hasattr(self._config_config, 'p_dms'):
141  self._config_config.p_dms = None
142  if not hasattr(self._config_config, 'p_targets'):
143  self._config_config.p_targets = None
144  if not hasattr(self._config_config, 'p_wfss'):
145  self._config_config.p_wfss = None
146  if not hasattr(self._config_config, 'p_centroiders'):
147  self._config_config.p_centroiders = None
148  if not hasattr(self._config_config, 'p_controllers'):
149  self._config_config.p_controllers = None
150  if not hasattr(self._config_config, 'p_coronos'):
151  self._config_config.p_coronos = None
152 
153  if not hasattr(self._config_config, 'simul_name'):
154  self._config_config.simul_name = None
155 
156  def get_pupil(self, pupil_type) -> np.ndarray:
157  """ Returns the specified pupil of COMPASS.
158 
159  Possible args value are :
160  - "i" or "ipupil" : returns the biggest pupil of size (Nfft x Nfft)
161  - "m" or "mpupil" : returns the medium pupil, used for WFS computation
162  - "s" or "spupil" : returns the smallest pupil of size (p_geom.pupdiam x p_geom.pupdiam)
163 
164  Returns:
165  pupil : (np.ndarray) : pupil
166  """
167  if scons.PupilType(pupil_type) is scons.PupilType.SPUPIL:
168  return self.p_geomp_geom.get_spupil()
169  if scons.PupilType(pupil_type) is scons.PupilType.MPUPIL:
170  return self.p_geomp_geom.get_mpupil()
171  if scons.PupilType(pupil_type) is scons.PupilType.IPUPIL:
172  return self.p_geomp_geom.get_ipupil()
173 
174  def export_config(self) -> [Dict, Dict]:
175  """
176  Extract and convert compass supervisor configuration parameters
177  into 2 dictionnaries containing relevant AO parameters
178 
179  Returns : 2 dictionnaries
180  """
181  aodict = OrderedDict()
182  dataDict = {}
183 
184  if (self.p_telp_tel is not None):
185  aodict.update({"teldiam": self.p_telp_tel.diam})
186  aodict.update({"telobs": self.p_telp_tel.cobs})
187  aodict.update({"pixsize": self.p_geomp_geom._pixsize})
188  # TURBU
189  aodict.update({"r0": self.p_atmosp_atmos.r0})
190  aodict.update({"Fe": 1 / self.p_loopp_loop.ittime})
191  aodict.update({"nbTargets": len(self.p_targetsp_targets)})
192  else:
193  aodict.update({"nbTargets": 1})
194 
195  # WFS
196  aodict.update({"nbWfs": len(self.p_wfssp_wfss)})
197  aodict.update({"nbCam": aodict["nbWfs"]})
198  aodict.update({"nbOffaxis": 0})
199  aodict.update({"nbNgsWFS": 1})
200  aodict.update({"nbLgsWFS": 0})
201  aodict.update({"nbFigSensor": 0})
202  aodict.update({"nbSkyWfs": aodict["nbWfs"]})
203  aodict.update({"nbOffNgs": 0})
204 
205  # DMS
206  aodict.update({"nbDms": len(self.p_dmsp_dms)})
207  aodict.update({"Nactu": self.p_controllersp_controllers[0].nactu})
208  # List of things
209  aodict.update({"list_NgsOffAxis": []})
210  aodict.update({"list_Fig": []})
211  aodict.update({"list_Cam": [0]})
212  aodict.update({"list_SkyWfs": [0]})
213  aodict.update({"list_ITS": []})
214  aodict.update({"list_Woofer": []})
215  aodict.update({"list_Tweeter": []})
216  aodict.update({"list_Steering": []})
217 
218  listOfNstatesPerController = []
219  listOfcommandLawTypePerController = []
220  for control in self.p_controllersp_controllers:
221  listOfNstatesPerController.append(control.nstates)
222  listOfcommandLawTypePerController.append(control.type)
223  aodict.update({"list_nstatesPerController": listOfNstatesPerController})
224  aodict.update({"list_controllerType": listOfcommandLawTypePerController})
225 
226  # fct of Nb of wfss
227  NslopesList = []
228  NsubapList = []
229  listWfsType = []
230  listCentroType = []
231 
232  pyrModulationList = []
233  pyr_npts = []
234  pyr_pupsep = []
235  pixsize = []
236  xPosList = []
237  yPosList = []
238  fstopsize = []
239  fstoptype = []
240  npixPerSub = []
241  nxsubList = []
242  nysubList = []
243  lambdaList = []
244  dms_seen = []
245  colTmpList = []
246  noise = []
247  #new_hduwfsl = pfits.HDUList()
248  #new_hduwfsSubapXY = pfits.HDUList()
249  for i in range(aodict["nbWfs"]):
250  #new_hduwfsl.append(pfits.ImageHDU(self.p_wfss[i]._isvalid)) # Valid subap array
251  #new_hduwfsl[i].header["DATATYPE"] = "valid_wfs%d" % i
252  dataDict["wfsValid_" + str(i)] = self.p_wfssp_wfss[i]._isvalid
253 
254  xytab = np.zeros((2, self.p_wfssp_wfss[i]._validsubsx.shape[0]))
255  xytab[0, :] = self.p_wfssp_wfss[i]._validsubsx
256  xytab[1, :] = self.p_wfssp_wfss[i]._validsubsy
257  dataDict["wfsValidXY_" + str(i)] = xytab
258 
259  #new_hduwfsSubapXY.append(pfits.ImageHDU(xytab)) # Valid subap array inXx Y on the detector
260  #new_hduwfsSubapXY[i].header["DATATYPE"] = "validXY_wfs%d" % i
261  pixsize.append(self.p_wfssp_wfss[i].pixsize)
262  """
263  if (self.p_centroiders[i].type == "maskedpix"):
264  factor = 4
265  else:
266  factor = 2
267  NslopesList.append(
268  self.p_wfss[i]._nvalid * factor) # slopes per wfs
269  """
270  listCentroType.append(
271  self.p_centroidersp_centroiders[i].
272  type) # assumes that there is the same number of centroiders and wfs
273  NsubapList.append(self.p_wfssp_wfss[i]._nvalid) # subap per wfs
274  listWfsType.append(self.p_wfssp_wfss[i].type)
275  xPosList.append(self.p_wfssp_wfss[i].xpos)
276  yPosList.append(self.p_wfssp_wfss[i].ypos)
277  fstopsize.append(self.p_wfssp_wfss[i].fssize)
278  fstoptype.append(self.p_wfssp_wfss[i].fstop)
279  nxsubList.append(self.p_wfssp_wfss[i].nxsub)
280  nysubList.append(self.p_wfssp_wfss[i].nxsub)
281  lambdaList.append(self.p_wfssp_wfss[i].Lambda)
282  if (self.p_wfssp_wfss[i].dms_seen is not None):
283  dms_seen.append(list(self.p_wfssp_wfss[i].dms_seen))
284  noise.append(self.p_wfssp_wfss[i].noise)
285 
286  if (self.p_centroidersp_centroiders[i].type == scons.CentroiderType.MASKEDPIX):
287  NslopesList.append(self.p_wfssp_wfss[i]._nvalid * 4) # slopes per wfs
288  else:
289  NslopesList.append(self.p_wfssp_wfss[i]._nvalid * 2) # slopes per wfs
290 
291  if (self.p_wfssp_wfss[i].type == "pyrhr"):
292  pyrModulationList.append(self.p_wfssp_wfss[i].pyr_ampl)
293  pyr_npts.append(self.p_wfssp_wfss[i].pyr_npts)
294  pyr_pupsep.append(self.p_wfssp_wfss[i].pyr_pup_sep)
295  npixPerSub.append(1)
296  else:
297  pyrModulationList.append(0)
298  pyr_npts.append(0)
299  pyr_pupsep.append(0)
300  npixPerSub.append(self.p_wfssp_wfss[i].npix)
301  """
302  confname = filepath.split("/")[-1].split('.conf')[0]
303  print(filepath.split(".conf")[0] + '_wfsConfig.fits')
304  new_hduwfsl.writeto(
305  filepath.split(".conf")[0] + '_wfsConfig.fits', overwrite=True)
306  new_hduwfsSubapXY.writeto(
307  filepath.split(".conf")[0] + '_wfsValidXYConfig.fits', overwrite=True)
308  """
309  if (len(dms_seen) != 0):
310  aodict.update({"listWFS_dms_seen": dms_seen})
311 
312  aodict.update({"listWFS_NslopesList": NslopesList})
313  aodict.update({"listWFS_NsubapList": NsubapList})
314  aodict.update({"listWFS_CentroType": listCentroType})
315  aodict.update({"listWFS_WfsType": listWfsType})
316  aodict.update({"listWFS_pixarc": pixsize})
317  aodict.update({"listWFS_pyrModRadius": pyrModulationList})
318  aodict.update({"listWFS_pyrModNPts": pyr_npts})
319  aodict.update({"listWFS_pyrPupSep": pyr_pupsep})
320  aodict.update({"listWFS_fstopsize": fstopsize})
321  aodict.update({"listWFS_fstoptype": fstoptype})
322  aodict.update({"listWFS_NsubX": nxsubList})
323  aodict.update({"listWFS_NsubY": nysubList})
324  aodict.update({"listWFS_Nsub": nysubList})
325  aodict.update({"listWFS_NpixPerSub": npixPerSub})
326  aodict.update({"listWFS_Lambda": lambdaList})
327  if (len(noise) != 0):
328  aodict.update({"listWFS_noise": noise})
329 
330  listDmsType = []
331  NactuX = []
332  Nactu = []
333  unitPerVolt = []
334  push4imat = []
335  coupling = []
336  push4iMatArcSec = []
337  #new_hdudmsl = pfits.HDUList()
338 
339  for j in range(aodict["nbDms"]):
340  listDmsType.append(self.p_dmsp_dms[j].type)
341  NactuX.append(
342  self.p_dmsp_dms[j].nact) # nb of actuators across the diameter !!
343  Nactu.append(self.p_dmsp_dms[j]._ntotact) # nb of actuators in total
344  unitPerVolt.append(self.p_dmsp_dms[j].unitpervolt)
345  push4imat.append(self.p_dmsp_dms[j].push4imat)
346  coupling.append(self.p_dmsp_dms[j].coupling)
347  tmp = []
348  if (self.p_dmsp_dms[j]._i1 is
349  not None): # Simu Case where i1 j1 is known (simulated)
350  if (self.p_dmsp_dms[j].type != 'tt'):
351  tmpdata = np.zeros((4, len(self.p_dmsp_dms[j]._i1)))
352  tmpdata[0, :] = self.p_dmsp_dms[j]._j1
353  tmpdata[1, :] = self.p_dmsp_dms[j]._i1
354  tmpdata[2, :] = self.p_dmsp_dms[j]._xpos
355  tmpdata[3, :] = self.p_dmsp_dms[j]._ypos
356  else:
357  tmpdata = np.zeros((4, 2))
358 
359  dataDict["dmData" + str(j)] = tmpdata
360  """
361  new_hdudmsl.append(pfits.ImageHDU(tmpdata)) # Valid subap array
362  new_hdudmsl[j].header["DATATYPE"] = "valid_dm%d" % j
363  """
364  #for k in range(aodict["nbWfs"]):
365  # tmp.append(supervisor.computeDMrange(j, k))
366 
367  push4iMatArcSec.append(tmp)
368 
369  # new_hdudmsl.writeto(filepath.split(".conf")[0] + '_dmsConfig.fits', overwrite=True)
370  if (len(push4iMatArcSec) != 0):
371  aodict.update({"listDMS_push4iMat": push4imat})
372  aodict.update({"listDMS_unitPerVolt": unitPerVolt})
373  aodict.update({"listDMS_Nxactu": NactuX})
374  aodict.update({"listDMS_Nyactu": NactuX})
375  aodict.update({"listDMS_Nactu": Nactu})
376 
377  aodict.update({"listDMS_type": listDmsType})
378  aodict.update({"listDMS_coupling": coupling})
379 
380  if (self.p_targetsp_targets is not None): # simu case
381  listTargetsLambda = []
382  listTargetsXpos = []
383  listTargetsYpos = []
384  listTargetsDmsSeen = []
385  listTargetsMag = []
386  listTARGETS_pixsize = []
387  for k in range(aodict["nbTargets"]):
388  listTargetsLambda.append(self.p_targetsp_targets[k].Lambda)
389  listTargetsXpos.append(self.p_targetsp_targets[k].xpos)
390  listTargetsYpos.append(self.p_targetsp_targets[k].ypos)
391  listTargetsMag.append(self.p_targetsp_targets[k].mag)
392  listTargetsDmsSeen.append(list(self.p_targetsp_targets[k].dms_seen))
393  PSFPixsize = (self.p_targetsp_targets[k].Lambda * 1e-6) / (
394  self.p_geomp_geom._pixsize *
395  self.p_geomp_geom.get_ipupil().shape[0]) * 206265.
396  listTARGETS_pixsize.append(PSFPixsize)
397 
398  aodict.update({"listTARGETS_Lambda": listTargetsLambda})
399  aodict.update({"listTARGETS_Xpos": listTargetsXpos})
400  aodict.update({"listTARGETS_Ypos": listTargetsYpos})
401  aodict.update({"listTARGETS_Mag": listTargetsMag})
402  aodict.update({"listTARGETS_DmsSeen": listTargetsDmsSeen})
403  aodict.update({"listTARGETS_pixsize": listTARGETS_pixsize})
404 
405  listDmsType = []
406  Nslopes = sum(NslopesList)
407  Nsubap = sum(NsubapList)
408  aodict.update({"Nslopes": Nslopes})
409  aodict.update({"Nsubap": Nsubap})
410  return aodict, dataDict
Shesha parameters configuration class.
Definition: pconfig.py:51
[Dict, Dict] export_config(self)
Extract and convert compass supervisor configuration parameters into 2 dictionnaries containing relev...
Definition: pconfig.py:216
p_targets
(List of Param_target) : List of Param_target instance
Definition: pconfig.py:113
p_controllers
(List of Param_controller) : List of Param controller instance
Definition: pconfig.py:116
p_wfss
(List of Param_wfs) : List of Param_wfs instance
Definition: pconfig.py:111
simul_name
(str) : Simulation run name
Definition: pconfig.py:107
p_tel
(Param_tel) : A Param_tel instance
Definition: pconfig.py:109
NoReturn _load_config_from_module(self, str filepath)
Definition: pconfig.py:156
p_centroiders
(List of Param_centroider) : List of Param_centroider instance
Definition: pconfig.py:115
p_geom
(Param_geom) : A Param_geom instance
Definition: pconfig.py:110
NoReturn _load_config_from_file(self, str filename_path)
Definition: pconfig.py:126
p_loop
(Param_loop) : A Param_loop instance
Definition: pconfig.py:114
def __init__(self, str param_file)
Definition: pconfig.py:105
p_atmos
(Param_atmos) : A Param_atmos instance
Definition: pconfig.py:108
np.ndarray get_pupil(self, pupil_type)
Returns the specified pupil of COMPASS.
Definition: pconfig.py:202
p_dms
(List of Param_dm) : List of Param_dm instance
Definition: pconfig.py:112
Numerical constants for shesha and config enumerations for safe-typing.
Definition: constants.py:1