COMPASS  5.0.0
End-to-end AO simulation tool using GPU acceleration
shesha.util.dm_util Namespace Reference

Utilities function for DM geometry initialization. More...

Functions

def dim_dm_support (float cent, int extent, int ssize)
 Compute the DM support dimensions. More...
 
def dim_dm_patch (int pupdiam, float diam, bytes type, float alt, List[float] xpos_wfs, List[float] ypos_wfs)
 compute patchDiam for DM More...
 
def createSquarePattern (float pitch, int nxact)
 
def createHexaPattern (float pitch, int supportSize)
 
def createDoubleHexaPattern (float pitch, int supportSize, float pupAngleDegree)
 
np.ndarray filterActuWithPupil (np.ndarray actuPos, np.ndarray pupil, float threshold)
 
def select_actuators (np.ndarray xc, np.ndarray yc, int nxact, int pitch, float cobs, float margin_in, float margin_out, N=None)
 Select the "valid" actuators according to the system geometry. More...
 
def make_zernike (int nzer, int size, int diameter, xc=-1., yc=-1., ext=0)
 Compute the zernike modes. More...
 
def zernumero (int zn)
 

Detailed Description

Utilities function for DM geometry initialization.

Author
COMPASS Team https://github.com/ANR-COMPASS
Version
5.0.0
Date
2020/05/18

This file is part of COMPASS https://anr-compass.github.io/compass/

Copyright (C) 2011-2019 COMPASS Team https://github.com/ANR-COMPASS All rights reserved. Distributed under GNU - LGPL

COMPASS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.

COMPASS: End-to-end AO simulation tool using GPU acceleration The COMPASS platform was designed to meet the need of high-performance for the simulation of AO systems.

The final product includes a software package for simulating all the critical subcomponents of AO, particularly in the context of the ELT and a real-time core based on several control approaches, with performances consistent with its integration into an instrument. Taking advantage of the specific hardware architecture of the GPU, the COMPASS tool allows to achieve adequate execution speeds to conduct large simulation campaigns called to the ELT.

The COMPASS platform can be used to carry a wide variety of simulations to both testspecific components of AO of the E-ELT (such as wavefront analysis device with a pyramid or elongated Laser star), and various systems configurations such as multi-conjugate AO.

COMPASS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with COMPASS. If not, see https://www.gnu.org/licenses/lgpl-3.0.txt.

Function Documentation

◆ createDoubleHexaPattern()

def shesha.util.dm_util.createDoubleHexaPattern ( float  pitch,
int  supportSize,
float  pupAngleDegree 
)

Definition at line 179 of file dm_util.py.

179  """
180  # ici on cree le pattern hexa. Par simplicite on replique le meme code
181  # que dans createHexaPattern(). On a donc un reseau "pointe selon X"
182  V3 = np.sqrt(3)
183  pi = np.pi
184  ny = int(np.ceil((supportSize / 2.0) / pitch) + 1)
185  y = pitch * (np.arange(2 * ny + 1, dtype=np.float32) - ny)
186  nx = int(np.ceil((supportSize / 2.0) / pitch / V3) + 1)
187  x = (V3 * pitch) * (np.arange(2 * nx + 1, dtype=np.float32) - nx)
188  # LA ligne de code qui change tout: on shifte le reseau de 1 pitch en X.
189  x = x + pitch
190  x, y = np.meshgrid(x, y, indexing='ij')
191  x = x.flatten()
192  y = y.flatten()
193  x = np.append(x, x + pitch * V3 / 2.)
194  y = np.append(y, y + pitch / 2.)
195 
196  # classement dans l'ordre kivabien
197  u = x + 1e-3 * y
198  idx = np.argsort(u)
199  x = x[idx]
200  y = y[idx]
201 
202  # on selection 1/6ieme du reseau, entre -30 et 30 degres
203  th = np.arctan2(y, x)
204  nn = np.where(((th < pi / 6) & (th > -pi / 6)))
205  x = x[nn]
206  y = y[nn]
207 
208  # on va maintenant repliquer ce reseau 6 fois, et le rotationnant a chaque
209  # fois de 60°. Note:
210  X = np.array([])
211  Y = np.array([])
212  for k in range(6):
213  xx = np.cos(k * pi / 3) * x + np.sin(k * pi / 3) * y
214  yy = -np.sin(k * pi / 3) * x + np.cos(k * pi / 3) * y
215  X = np.r_[X, xx]
216  Y = np.r_[Y, yy]
217 
218  # Rotation matrices pour suivre l'angle pupille
219  rot = pupAngleDegree * np.pi / 180.0
220  mrot = np.array([[np.cos(rot), -np.sin(rot)], [np.sin(rot), np.cos(rot)]])
221  XY = np.dot(mrot, [X, Y])
222  return np.float32(XY)
223 
224 
225 def filterActuWithPupil(actuPos: np.ndarray, pupil: np.ndarray,
226  threshold: float) -> np.ndarray:
227  '''
228  Select actuators based on their distance to the nearest pupil pixel
229  The implementation proposed here is easy but limits it precision to
230  an integer roundoff of the threshold
231 
232  actuPos: 2 x nActu np.array[float]: actuator position list - pupil pixel units
233  pupil: nPup x nPup np.ndarray[bool]: pupil mask

◆ createHexaPattern()

def shesha.util.dm_util.createHexaPattern ( float  pitch,
int  supportSize 
)

Definition at line 145 of file dm_util.py.

145  """
146  V3 = np.sqrt(3)
147  nx = int(np.ceil((supportSize / 2.0) / pitch) + 1)
148  x = pitch * (np.arange(2 * nx + 1, dtype=np.float32) - nx)
149  Nx = x.shape[0]
150  ny = int(np.ceil((supportSize / 2.0) / pitch / V3) + 1)
151  y = (V3 * pitch) * (np.arange(2 * ny + 1, dtype=np.float32) - ny)
152  Ny = y.shape[0]
153  x = np.tile(x, (Ny, 1)).flatten()
154  y = np.tile(y, (Nx, 1)).T.flatten()
155  x = np.append(x, x + pitch / 2.)
156  y = np.append(y, y + pitch * V3 / 2.)
157  xy = np.float32(np.array([y, x]))
158  return xy
159 
160 
161 def createDoubleHexaPattern(pitch: float, supportSize: int, pupAngleDegree: float):
162  """
163  Creates a list of M actuator positions spread over an hexagonal grid.
164  The number M is the number of points of this grid, it cannot be
165  known before the procedure is called.
166  Coordinates are centred around (0,0).
167  The support of the grid is a square [-supportSize/2,vsupportSize/2].
168 
169  :parameters:
170 
171  pitch: (float) : distance in pixels between 2 adjacent actus
172  supportSize: (int) : size in pixels of the support over which the coordinate list
173  should be returned.
174  pupAngleDegree: (float) : Rotation angle of the DM
175 
176  :return:
177 
178  xy: (np.ndarray(dims=2,dtype=np.float32)) : xy[2,M] list of coodinates

◆ createSquarePattern()

def shesha.util.dm_util.createSquarePattern ( float  pitch,
int  nxact 
)

Definition at line 119 of file dm_util.py.

119  """
120 
121  xy = np.tile(np.arange(nxact) - (nxact - 1.) / 2., (nxact, 1)).astype(np.float32)
122  xy = np.array([xy.flatten(), xy.T.flatten()]) * pitch
123  xy = np.float32(xy)
124  return xy
125 
126 
127 def createHexaPattern(pitch: float, supportSize: int):
128  """
129  Creates a list of M actuator positions spread over an hexagonal grid.
130  The number M is the number of points of this grid, it cannot be
131  known before the procedure is called.
132  Coordinates are centred around (0,0).
133  The support that limits the grid is a square [-supportSize/2, supportSize/2].
134 
135  :parameters:
136 
137  pitch: (float) : distance in pixels between 2 adjacent actus
138 
139  supportSize: (int) : size in pixels of the support over which the coordinate list
140  should be returned.
141 
142  :return:
143 
144  xy: (np.ndarray(dims=2,dtype=np.float32)) : xy[2,M] list of coordinates

◆ dim_dm_patch()

def shesha.util.dm_util.dim_dm_patch ( int  pupdiam,
float  diam,
bytes  type,
float  alt,
List[float]  xpos_wfs,
List[float]  ypos_wfs 
)

compute patchDiam for DM

:parameters:

pupdiam (int) : pupil diameter

diam (float) : telescope diameter

type (bytes) : type of dm

alt (float) : altitude of dm

xpos_wfs (list) : list of wfs xpos

ypos_wfs (list) : list of wfs ypos

Definition at line 85 of file dm_util.py.

85  ypos_wfs: (list) : list of wfs ypos
86  """
87 
88  if len(xpos_wfs) == 0:
89  norms = 0. # type: Union[float, List[float]]
90  else:
91  norms = [
92  np.linalg.norm([xpos_wfs[w], ypos_wfs[w]]) for w in range(len(xpos_wfs))
93  ]
94  if ((type == scons.DmType.PZT) or (type == scons.DmType.TT)):
95  pp = (diam / pupdiam)
96  elif (type == scons.DmType.KL):
97  pp = (pupdiam)
98  else:
99  raise TypeError("This type of DM doesn't exist ")
100 
101  patchDiam = int(pupdiam + 2 * np.max(norms) * CONST.ARCSEC2RAD * np.abs(alt) / (pp))
102  return patchDiam
103 
104 
105 def createSquarePattern(pitch: float, nxact: int):
106  """
107  Creates a list of M=nxact^2 actuator positions spread over an square grid.
108  Coordinates are centred around (0,0).
109 
110  :parameters:
111 
112  pitch: (float) : distance in pixels between 2 adjacent actus
113 
114  nxact: (int) : number of actu across the pupil diameter
115 
116  :return:
117 
118  xy: (np.ndarray(dims=2,dtype=np.float32)) : xy[M,2] list of coodinates

◆ dim_dm_support()

def shesha.util.dm_util.dim_dm_support ( float  cent,
int  extent,
int  ssize 
)

Compute the DM support dimensions.

:parameters:

cent (float): center of the pupil

extent (float): size of the DM support

ssize (int): size of ipupil support

Definition at line 58 of file dm_util.py.

58  """
59  n1 = np.floor(cent - extent / 2)
60  n2 = np.ceil(cent + extent / 2)
61  if (n1 < 1):
62  n1 = 1
63  if (n2 > ssize):
64  n2 = ssize
65 
66  return int(n1), int(n2)
67 
68 

◆ filterActuWithPupil()

np.ndarray shesha.util.dm_util.filterActuWithPupil ( np.ndarray  actuPos,
np.ndarray  pupil,
float  threshold 
)

Definition at line 234 of file dm_util.py.

234  threshold: float: max allowed distance - pupil pixel units
235  '''
236 
237  # Gen a dilation mask of expected size
238  from scipy.ndimage.morphology import binary_dilation
239  k = np.ceil(threshold)
240  i, j = np.meshgrid(np.arange(2 * k + 1), np.arange(2 * k + 1), indexing='ij')
241  disk = ((i - k)**2 + (j - k)**2)**.5 <= k
242  dilatedPupil = binary_dilation(pupil, disk)
243  actuIsIn = dilatedPupil[(np.round(actuPos[0]).astype(np.int32),
244  np.round(actuPos[1]).astype(np.int32))]
245  return actuPos[:, actuIsIn]
246 
247 

◆ make_zernike()

def shesha.util.dm_util.make_zernike ( int  nzer,
int  size,
int  diameter,
  xc = -1.,
  yc = -1.,
  ext = 0 
)

Compute the zernike modes.

:parameters:

nzer (int) : number of modes

size (int) : size of the screen

diameter (int) : pupil diameter

xc (float) : (optional) x-position of the center

yc (float) : (optional) y-position of the center

ext (int) : (optional) extension

:return:

z (np.ndarray(ndims=3,dtype=np.float64)) : zernikes modes

Definition at line 323 of file dm_util.py.

323  """
324  m = 0
325  n = 0
326 
327  if (xc == -1):
328  xc = size / 2
329  if (yc == -1):
330  yc = size / 2
331 
332  radius = (diameter + 1.) / 2.
333  zr = util.dist(size, xc, yc).astype(np.float32).T / radius
334  zmask = np.zeros((zr.shape[0], zr.shape[1], nzer), dtype=np.float32)
335  zmaskmod = np.zeros((zr.shape[0], zr.shape[1], nzer), dtype=np.float32)
336 
337  zmask[:, :, 0] = (zr <= 1).astype(np.float32)
338  zmaskmod[:, :, 0] = (zr <= 1.2).astype(np.float32)
339 
340  for i in range(1, nzer):
341  zmask[:, :, i] = zmask[:, :, 0]
342  zmaskmod[:, :, i] = zmaskmod[:, :, 0]
343 
344  zrmod = zr * zmaskmod[:, :, 0]
345 
346  zr = zr * zmask[:, :, 0]
347 
348  x = np.tile(np.linspace(1, size, size).astype(np.float32), (size, 1))
349  zteta = np.arctan2(x - yc, x.T - xc).astype(np.float32)
350 
351  z = np.zeros((size, size, nzer), dtype=np.float32)
352 
353  for zn in range(nzer):
354  n, m = zernumero(zn + 1)
355 
356  if ext:
357  for i in range((n - m) // 2 + 1):
358  z[:, :, zn] = z[:, :, zn] + (-1.) ** i * zrmod ** (n - 2. * i) * float(np.math.factorial(n - i)) / \
359  float(np.math.factorial(i) * np.math.factorial((n + m) / 2 - i) *
360  np.math.factorial((n - m) / 2 - i))
361  else:
362  for i in range((n - m) // 2 + 1):
363  z[:, :, zn] = z[:, :, zn] + (-1.) ** i * zr ** (n - 2. * i) * float(np.math.factorial(n - i)) / \
364  float(np.math.factorial(i) * np.math.factorial((n + m) / 2 - i) *
365  np.math.factorial((n - m) / 2 - i))
366 
367  if ((zn + 1) % 2 == 1):
368  if (m == 0):
369  z[:, :, zn] = z[:, :, zn] * np.sqrt(n + 1.)
370  else:
371  z[:, :, zn] = z[:, :, zn] * \
372  np.sqrt(2. * (n + 1)) * np.sin(m * zteta)
373  else:
374  if (m == 0):
375  z[:, :, zn] = z[:, :, zn] * np.sqrt(n + 1.)
376  else:
377  z[:, :, zn] = z[:, :, zn] * \
378  np.sqrt(2. * (n + 1)) * np.cos(m * zteta)
379 
380  if (ext):
381  return z * zmaskmod
382  else:
383  return z * zmask
384 
385 
386 def zernumero(zn: int):
387  """
388  Returns the radial degree and the azimuthal number of zernike
389  number zn, according to Noll numbering (Noll, JOSA, 1976)
390 
391  :parameters:
392 
393  zn: (int) : zernike number
394 
395  :returns:
396 
397  rd: (int) : radial degrees
398 
399  an: (int) : azimuthal numbers
400 
Here is the call graph for this function:

◆ select_actuators()

def shesha.util.dm_util.select_actuators ( np.ndarray  xc,
np.ndarray  yc,
int  nxact,
int  pitch,
float  cobs,
float  margin_in,
float  margin_out,
  N = None 
)

Select the "valid" actuators according to the system geometry.

:parameters:

xc actuators x positions (origine in center of mirror)

yc actuators y positions (origine in center of mirror)

nxact:

pitch:

cobs:

margin_in:

margin_out:
N

:return:

liste_fin actuator indice selection for xpos/ypos

Definition at line 275 of file dm_util.py.

275 
276  """
277  # the following determine if an actuator is to be considered or not
278  # relative to the pitchmargin parameter.
279  dis = np.sqrt(xc**2 + yc**2)
280 
281  # test Margin_in
282  rad_in = (((nxact - 1) / 2) * cobs - margin_in) * pitch
283 
284  if N is None:
285  if (margin_out is None):
286  margin_out = 1.44
287  rad_out = ((nxact - 1.) / 2. + margin_out) * pitch
288 
289  valid_actus = np.where((dis <= rad_out) * (dis >= rad_in))[0]
290 
291  else:
292  valid_actus = np.where(dis >= rad_in)[0]
293  indsort = np.argsort(dis[valid_actus])
294 
295  if (N > valid_actus.size):
296  print('Too many actuators wanted, restricted to ', valid_actus.size)
297  else:
298  valid_actus = np.sort(indsort[:N])
299 
300  return valid_actus
301 
302 

◆ zernumero()

def shesha.util.dm_util.zernumero ( int  zn)

Definition at line 401 of file dm_util.py.

401  """
402  j = 0
403  for n in range(101):
404  for m in range(n + 1):
405  if ((n - m) % 2 == 0):
406  j = j + 1
407  if (j == zn):
408  return n, m
409  if (m != 0):
410  j = j + 1
411  if (j == zn):
412  return n, m
Here is the caller graph for this function: