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

Functions for DM KL initialization. More...

Functions

float make_radii (float cobs, int nr)
 TODO docstring. More...
 
np.ndarray make_kernels (float cobs, int nr, np.ndarray radp, bytes kl_type, float outscl=3.)
 
np.ndarray piston_orth (int nr)
 TODO docstring. More...
 
np.ndarray make_azimuth (int nord, int npp)
 TODO docstring. More...
 
np.ndarray radii (int nr, int npp, float cobs)
 
np.ndarray polang (np.ndarray r)
 
Tuple[np.ndarray, np.ndarray, np.ndarray] setpincs (np.ndarray ax, np.ndarray ay, np.ndarray px, np.ndarray py, float cobs)
 
def pcgeom (nr, npp, cobs, ncp, ncmar)
 
def set_pctr (int dim, nr, npp, int nkl, float cobs, nord, ncmar=None, ncp=None)
 
def gkl_fcom (np.ndarray kers, float cobs, int nf)
 
def gkl_sfi (p_dm, i)
 
def pol2car (pol, p_dm, mask=0)
 
def kl_view (p_dm, mask=1)
 

Detailed Description

Functions for DM KL 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

◆ gkl_fcom()

def shesha.util.kl_util.gkl_fcom ( np.ndarray  kers,
float  cobs,
int  nf 
)

Definition at line 458 of file kl_util.py.

458  """
459  nkl = nf
460  st = kers.shape
461  nr = st[1]
462  nt = st[0]
463  nxt = 0
464  fktom = (1. - cobs**2) / nr
465 
466  evs = np.zeros((nr, nt), dtype=np.float32)
467  # ff isnt used - the normalisation for
468  # the eigenvectors is straightforward:
469  # integral of surface**2 divided by area = 1,
470  # and the cos**2 term gives a factor
471  # half, so multiply zero order by
472  # sqrt(n) and the rest by sqrt (2n)
473 
474  # zero order is a special case...
475  # need to deflate to eliminate infinite eigenvalue - actually want
476  # evals/evecs of zom - b where b is big and negative
477  zom = kers[0, :, :]
478  s = piston_orth(nr)
479 
480  ts = np.transpose(s)
481  # b1 = ((ts(,+)*zom(+,))(,+)*s(+,))(1:nr-1, 1:nr-1)
482  btemp = (ts.dot(zom).dot(s))[0:nr - 1, 0:nr - 1]
483 
484  #newev = SVdec(fktom*b1,v0,vt)
485  v0, newev, vt = np.linalg.svd(
486  fktom * btemp, full_matrices=True
487  ) # type: np.ndarray[np.float32], np.ndarray[np.float32],np.ndarray[np.float32]
488 
489  v1 = np.zeros((nr, nr), dtype=np.float32)
490  v1[0:nr - 1, 0:nr - 1] = v0
491  v1[nr - 1, nr - 1] = 1
492 
493  vs = s.dot(v1)
494  newev = np.concatenate((newev, [0]))
495  # print(np.size(newev))
496  evs[:, nxt] = np.float32(newev)
497  kers[nxt, :, :] = np.sqrt(nr) * vs
498 
499  nxt = 1
500  while True:
501  vs, newev, vt = np.linalg.svd(fktom * kers[nxt, :, :], full_matrices=True)
502  # newev = SVdec(fktom*kers(,,nxt),vs,vt)
503  evs[:, nxt] = np.float32(newev)
504  kers[nxt, :, :] = np.sqrt(2. * nr) * vs
505  mxn = max(np.float32(newev))
506  egtmxn = np.floor(evs[:, 0:nxt + 1] > mxn)
507  nxt = nxt + 1
508  if ((2 * np.sum(egtmxn) - np.sum(egtmxn[:, 0])) >= nkl):
509  break
510 
511  nus = nxt - 1
512  kers = kers[0:nus + 1, :, :]
513 
514  #evs = reform (evs [:, 1:nus], nr*(nus))
515 
516  evs = np.reshape(evs[:, 0:nus + 1], nr * (nus + 1), order='F')
517  a = np.argsort(-1. * evs)[0:nkl]
518 
519  # every eigenvalue occurs twice except
520  # those for the zeroth order mode. This
521  # could be done without the loops, but
522  # it isn't the stricking point anyway...
523 
524  no = 0
525  ni = 0
526  #oind = array(long,nf+1)
527  oind = np.zeros(nkl + 1, dtype=np.int32)
528 
529  while True:
530  if (a[ni] < nr):
531  oind[no] = a[ni]
532  no = no + 1
533  else:
534  oind[no] = a[ni]
535  oind[no + 1] = a[ni]
536  no = no + 2
537 
538  ni = ni + 1
539  if (no >= (nkl)):
540  break
541 
542  oind = oind[0:nkl]
543  tord = (oind) // nr + 1
544 
545  odd = np.arange(nkl, dtype=np.int32) % 2
546  pio = (oind) % nr + 1
547 
548  evals = evs[oind]
549  ordd = 2 * (tord - 1) - np.floor((tord > 1) & (odd)) + 1
550 
551  nord = max(ordd)
552 
553  rabas = np.zeros((nr, nkl), dtype=np.float32)
554  sizenpo = int(nord)
555  npo = np.zeros(sizenpo, dtype=np.int32)
556 
557  for i in range(nkl):
558  npo[np.int32(ordd[i]) - 1] = npo[np.int32(ordd[i]) - 1] + 1
559  rabas[:, i] = kers[tord[i] - 1, :, pio[i] - 1]
560 
561  return evals, nord, npo, ordd, rabas
562 
563 
564 #-------------------------------------------------------------------------
565 # function for calculate DM_kl on python
566 
567 
Here is the call graph for this function:

◆ gkl_sfi()

def shesha.util.kl_util.gkl_sfi (   p_dm,
  i 
)

Definition at line 568 of file kl_util.py.

568 def gkl_sfi(p_dm, i):
569  #DOCUMENT
570  #This routine returns the i'th function from the generalised KL
571  #basis bas. bas must be generated first with gkl_bas.
572  nr = p_dm._nr
573  npp = p_dm._npp
574  ordd = p_dm._ord
575  rabas = p_dm._rabas
576  azbas = p_dm._azbas
577  nkl = p_dm.nkl
578 
579  if (i > nkl - 1):
580  raise TypeError("kl funct order it's so big")
581 
582  else:
583 
584  ordi = np.int32(ordd[i])
585  rabasi = rabas[:, i]
586  azbasi = np.transpose(azbas)
587  azbasi = azbasi[ordi, :]
588 
589  sf1 = np.zeros((nr, npp), dtype=np.float64)
590  for j in range(npp):
591  sf1[:, j] = rabasi
592 
593  sf2 = np.zeros((npp, nr), dtype=np.float64)
594  for j in range(nr):
595  sf2[:, j] = azbasi
596 
597  sf = sf1 * np.transpose(sf2)
598 
599  return sf
600 
601 
Here is the caller graph for this function:

◆ kl_view()

def shesha.util.kl_util.kl_view (   p_dm,
  mask = 1 
)

Definition at line 642 of file kl_util.py.

642 def kl_view(p_dm, mask=1):
643 
644  nkl = p_dm.nkl
645  ncp = p_dm._ncp
646 
647  tab_kl = np.zeros((nkl, ncp, ncp), dtype=np.float64)
648  tab_klf = np.zeros((nkl, ncp, ncp), dtype=np.float64)
649  tab_klxy = np.zeros((nkl, ncp, ncp), dtype=np.float64)
650 
651  for i in range(nkl):
652 
653  tab_kl[i, :, :], tab_klf[i, :, :], tab_klxy[i, :, :] = pol2car(
654  gkl_sfi(p_dm, i), p_dm, mask)
655 
656  return tab_kl, tab_klf, tab_klxy
Here is the call graph for this function:

◆ make_azimuth()

np.ndarray shesha.util.kl_util.make_azimuth ( int  nord,
int  npp 
)

TODO docstring.

   :parameters:

       nord:

       npp:

   :return:

       azbas:

Definition at line 151 of file kl_util.py.

151  """
152 
153  azbas = np.zeros((npp, np.int32(1 + nord)), dtype=np.float32)
154  th = np.arange(npp, dtype=np.float32) * (2. * np.pi / npp)
155 
156  azbas[:, 0] = 1.0
157  for i in np.arange(1, nord, 2):
158  azbas[:, np.int32(i)] = np.cos((np.int32(i) // 2 + 1) * th)
159  for i in np.arange(2, nord, 2):
160  azbas[:, np.int32(i)] = np.sin((np.int32(i) // 2) * th)
161 
162  return azbas
163 
164 
165 def radii(nr: int, npp: int, cobs: float) -> np.ndarray:
166  """
167  This routine generates an nr x npp array with npp copies of the
168  radial coordinate array. Radial coordinate span the range from
169  r=cobs to r=1 with successive annuli having equal areas (ie, the
170  area between cobs and 1 is divided into nr equal rings, and the
171  points are positioned at the half-area mark on each ring). There
172  are no points on the border.
173 
174  TODO:
175 
176  :parameters:
177 
178  nr:
179 
180  npp:
181 
182  cobs: (float) : central obstruction
183 
184  :return:
185 
186  r

◆ make_kernels()

np.ndarray shesha.util.kl_util.make_kernels ( float  cobs,
int  nr,
np.ndarray  radp,
bytes  kl_type,
float   outscl = 3. 
)

Definition at line 85 of file kl_util.py.

85  kers :
86  """
87  nth = 5 * nr
88  kers = np.zeros((nth, nr, nr), dtype=np.float32)
89  cth = np.cos((np.arange(nth, dtype=np.float32)) * (2. * np.pi / nth))
90  dth = 2. * np.pi / nth
91  fnorm = -1. / (2 * np.pi * (1. - cobs**2)) * 0.5
92  # the 0.5 is to give the r**2 kernel, not the r kernel
93  for i in range(nr):
94  for j in range(i + 1):
95  te = 0.5 * np.sqrt(radp[i]**2 + radp[j]**2 - (2 * radp[i] * radp[j]) * cth)
96  # te in units of the diameter, not the radius
97  if (kl_type == scons.KLType.KOLMO):
98 
99  te = 6.88 * te**(5. / 3.)
100 
101  elif (kl_type == scons.KLType.KARMAN):
102 
103  te = 6.88 * te**(5. / 3.) * (1 - 1.485 * (te / outscl)**
104  (1. / 3.) + 5.383 * (te / outscl)**
105  (2) - 6.281 * (te / outscl)**(7. / 3.))
106 
107  else:
108 
109  raise TypeError("kl type unknown")
110 
111  f = np.fft.fft(te, axis=-1)
112  kelt = fnorm * dth * np.float32(f.real)
113  kers[:, i, j] = kers[:, j, i] = kelt
114  return kers
115 
116 

◆ make_radii()

float shesha.util.kl_util.make_radii ( float  cobs,
int  nr 
)

TODO docstring.

   :parameters:

cobs (float) : central obstruction

nr (int) :

Definition at line 53 of file kl_util.py.

53  """
54  d = (1. - cobs * cobs) / nr
55  rad2 = cobs**2 + d / 16. + d * (np.arange(nr, dtype=np.float32))
56  radp = np.sqrt(rad2)
57  return radp
58 
59 
60 def make_kernels(cobs: float, nr: int, radp: np.ndarray, kl_type: bytes,
61  outscl: float = 3.) -> np.ndarray:
62  """
63  This routine generates the kernel used to find the KL modes.
64  The kernel constructed here should be simply a discretization
65  of the continuous kernel. It needs rescaling before it is treated
66  as a matrix for finding the eigen-values. The outer scale
67  should be in units of the diameter of the telescope.
68 
69  TODO:
70 
71  :parameters:
72 
73  cobs : (float): central obstruction
74 
75  nr : (int) :
76 
77  radp : (float) :
78 
79  kl_type : (bytes) : "kolmo" or "karman"
80 
81  outscl : (float) : outter scale for Von Karman spectrum
82 
83  :return:
84 

◆ pcgeom()

def shesha.util.kl_util.pcgeom (   nr,
  npp,
  cobs,
  ncp,
  ncmar 
)

Definition at line 348 of file kl_util.py.

348  """
349  nused = ncp - 2 * ncmar
350  ff = 0.5 * nused
351  hw = np.float(ncp - 1) / 2.
352 
353  r = radii(nr, npp, cobs)
354  p = polang(r)
355 
356  px0 = r * np.cos(p)
357  py0 = r * np.sin(p)
358  px = ff * px0 + hw
359  py = ff * py0 + hw
360  ax = np.reshape(
361  np.arange(int(ncp)**2, dtype=np.float) + 1, (int(ncp), int(ncp)), order='F')
362  ax = np.float32(ax - 1) % ncp - 0.5 * (ncp - 1)
363  ax = ax / (0.5 * nused)
364  ay = np.transpose(ax)
365 
366  pincx, pincy, pincw = setpincs(ax, ay, px0, py0, cobs)
367 
368  dpi = 2 * np.pi
369  cr2 = (ax**2 + ay**2)
370  ap = np.clip(cr2, cobs**2 + 1.e-3, 0.999)
371  #cr = (cr2 - cobs**2) / (1 - cobs**2) * nr - 0.5;
372  cr = (cr2 - cobs**2) / (1 - cobs**2) * nr
373  cp = (np.arctan2(ay, ax) + dpi) % dpi
374  cp = (npp / dpi) * cp
375 
376  cr = np.clip(cr, 1.e-3, nr - 1.001)
377  # fudge -----, but one of the less bad ones
378  cp = np.clip(cp, 1.e-3, npp - 1.001)
379  # fudge ----- this is the line which
380  # gives that step in the cartesian grid
381  # at phi = 0.
382  return ncp, ncmar, px, py, cr, cp, pincx, pincy, pincw, ap
383 
384 
385 def set_pctr(dim: int, nr, npp, nkl: int, cobs: float, nord, ncmar=None, ncp=None):
386  """
387  This routine calls pcgeom to build a geom_struct with the
388  right initializations. bas is a gkl_basis_struct built with
389  the gkl_bas routine.
390  TODO:
391 
392  :parameters:
393 
394  dim:
395 
396  nr:
397 
398  npp:
399 
400  nkl:
401 
402  cobs:
403 
404  nord:
405 
406  ncmar: (optional)
407 
408  ncp: (optional)
409 
410  :returns:
411 
412  ncp
413 
414  ncmar
415 
416  px
417 
418  py
419 
420  cr
421 
422  cp
423 
424  pincx
425 
426  pincy
427 
428  pincw
429 
430  ap
Here is the call graph for this function:
Here is the caller graph for this function:

◆ piston_orth()

np.ndarray shesha.util.kl_util.piston_orth ( int  nr)

TODO docstring.

   :parameters:

       nr:

   :return:

       s:

Definition at line 127 of file kl_util.py.

127  """
128  s = np.zeros((nr, nr), dtype=np.float32) # type: np.ndarray[np.float32]
129  for j in range(nr - 1):
130  rnm = 1. / np.sqrt(np.float32((j + 1) * (j + 2)))
131  s[0:j + 1, j] = rnm
132  s[j + 1, j] = -1 * (j + 1) * rnm
133 
134  rnm = 1. / np.sqrt(nr)
135  s[:, nr - 1] = rnm
136  return s
137 
138 
Here is the caller graph for this function:

◆ pol2car()

def shesha.util.kl_util.pol2car (   pol,
  p_dm,
  mask = 0 
)

Definition at line 602 of file kl_util.py.

602 def pol2car(pol, p_dm, mask=0):
603  # DOCUMENT cart=pol2car(cpgeom, pol, mask=)
604  # This routine is used for polar to cartesian conversion.
605  # pol is built with gkl_bas and cpgeom with pcgeom.
606  # However, points not in the aperture are actually treated
607  # as though they were at the first or last radial polar value
608  # -- a small fudge, but not serious ?*******
609  #cd = interpolate.interp2d(cr, cp,pol)
610  ncp = p_dm._ncp
611  cr = p_dm._cr
612  cp = p_dm._cp
613  nr = p_dm._nr
614  npp = p_dm._npp
615 
616  r = np.arange(nr, dtype=np.float64)
617  phi = np.arange(npp, dtype=np.float64)
618  tab_phi, tab_r = np.meshgrid(phi, r)
619  tab_x = (tab_r / (nr)) * np.cos((tab_phi / (npp)) * 2 * np.pi)
620  tab_y = (tab_r / (nr)) * np.sin((tab_phi / (npp)) * 2 * np.pi)
621 
622  newx = np.linspace(-1, 1, ncp)
623  newy = np.linspace(-1, 1, ncp)
624  tx, ty = np.meshgrid(newx, newy)
625 
626  cd = interpolate.griddata((tab_r.flatten(), tab_phi.flatten()), pol.flatten(),
627  (cr, cp), method='cubic')
628  cdf = interpolate.griddata((tab_r.flatten("F"), tab_phi.flatten("F")),
629  pol.flatten("F"), (cr, cp), method='cubic')
630  cdxy = interpolate.griddata((tab_y.flatten(), tab_x.flatten()), pol.flatten(),
631  (tx, ty), method='cubic')
632 
633  if (mask == 1):
634  ap = p_dm.ap
635  cd = cd * (ap)
636  cdf = cdf * (ap)
637  cdxy = cdxy * (ap)
638 
639  return cd, cdf, cdxy
640 
641 
Here is the caller graph for this function:

◆ polang()

np.ndarray shesha.util.kl_util.polang ( np.ndarray  r)

Definition at line 214 of file kl_util.py.

214  """
215  s = r.shape
216  nr = s[0]
217  np1 = s[1]
218  phi1 = np.arange(np1, dtype=np.float) / float(np1) * 2. * np.pi
219  p1, p2 = np.meshgrid(np.ones(nr), phi1)
220  p = np.transpose(p2)
221 
222  return p
223 
224 
225 #__________________________________________________________________________
226 #__________________________________________________________________________
227 
228 
229 def setpincs(ax: np.ndarray, ay: np.ndarray, px: np.ndarray, py: np.ndarray,
230  cobs: float) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
231  """
232  This routine determines a set of squares for interpolating
233  from cartesian to polar coordinates, using only those points
234  with cobs < r < 1
235  SEE ALSO : pcgeom
236 
237  TODO:
238 
239  :parameters:
240 
241  ax:
242 
243  ay:
244 
245  px:
246 
247  py:
248 
249  cobs: (float) : central obstruction
250 
251  :return:
252 
253  pincx:
254 
255  pincy:
256 
Here is the caller graph for this function:

◆ radii()

np.ndarray shesha.util.kl_util.radii ( int  nr,
int  npp,
float  cobs 
)

Definition at line 187 of file kl_util.py.

187  """
188 
189  r2 = cobs**2 + (np.arange(nr, dtype=np.float) + 0.) / nr * (1.0 - cobs**2)
190  rs = np.sqrt(r2)
191  r = np.transpose(np.tile(rs, (npp, 1)))
192 
193  return r
194 
195 
196 #__________________________________________________________________________
197 #__________________________________________________________________________
198 
199 
200 def polang(r: np.ndarray) -> np.ndarray:
201  """
202  This routine generates an array with the same dimensions as r,
203  but containing the azimuthal values for a polar coordinate system.
204 
205  TODO:
206 
207  :parameters:
208 
209  r:
210 
211  :return:
212 
213  p:
Here is the caller graph for this function:

◆ set_pctr()

def shesha.util.kl_util.set_pctr ( int  dim,
  nr,
  npp,
int  nkl,
float  cobs,
  nord,
  ncmar = None,
  ncp = None 
)

Definition at line 431 of file kl_util.py.

431  """
432  ncp = dim
433  if (ncmar == None):
434  ncmar = 2
435  if (ncp == None):
436  ncp = 128
437  ncp, ncmar, px, py, cr, cp, pincx, pincy, pincw, ap = pcgeom(
438  nr, npp, cobs, ncp, ncmar)
439  return ncp, ncmar, px, py, cr, cp, pincx, pincy, pincw, ap
440 
441 
442 def gkl_fcom(kers: np.ndarray, cobs: float, nf: int):
443  """
444  This routine does the work : finding the eigenvalues and
445  corresponding eigenvectors. Sort them and select the right
446  one. It returns the KL modes : in polar coordinates : rabas
447  as well as the associated variance : evals. It also returns
448  a bunch of indices used to recover the modes in cartesian
449  coordinates (nord, npo and ordd).
450 
451  :parameters:
452 
453  kerns : (np.ndarray[ndim= ,dtype=np.float32]) :
454 
455  cobs : (float) : central obstruction
456 
457  nf : (int) :
Here is the call graph for this function:

◆ setpincs()

Tuple[np.ndarray, np.ndarray, np.ndarray] shesha.util.kl_util.setpincs ( np.ndarray  ax,
np.ndarray  ay,
np.ndarray  px,
np.ndarray  py,
float  cobs 
)

Definition at line 257 of file kl_util.py.

257  pincw
258  """
259 
260  s = ax.shape
261  nc = s[0]
262  # s = px.shape# not used
263  # nr = s[0]# not used
264  # npp = s[1]# not used
265  dcar = (ax[nc - 1, 0] - ax[0, 0]) / (nc - 1)
266  ofcar = ax[0, 0]
267  rlx = (px - ofcar) / dcar
268  rly = (py - ofcar) / dcar
269  lx = np.int32(rlx)
270  ly = np.int32(rly)
271  shx = rlx - lx
272  shy = rly - ly
273 
274  pincx = np.zeros((4, lx.shape[0], lx.shape[1]))
275  pincx[[1, 2], :, :] = lx + 1
276  pincx[[0, 3], :, :] = lx
277 
278  pincy = np.zeros((4, ly.shape[0], ly.shape[1]))
279  pincy[[0, 1], :, :] = ly
280  pincy[[2, 3], :, :] = ly + 1
281 
282  pincw = np.zeros((4, shx.shape[0], shx.shape[1]))
283  pincw[0, :, :] = (1 - shx) * (1 - shy)
284  pincw[1, :, :] = shx * (1 - shy)
285  pincw[2, :, :] = shx * shy
286  pincw[3, :, :] = (1 - shx) * shy
287 
288  axy = ax**2 + ay**2
289  axyinap = np.clip(axy, cobs**2. + 1.e-3, 0.999)
290  # sizeaxyinap=axyinap.shape[1]# not used
291 
292  # pincw = pincw*axyinap[pincx+(pincy-1)*sizeaxyinap] --->
293 
294  for z in range(pincw.shape[0]):
295  for i in range(pincw.shape[1]):
296  for j in range(pincw.shape[2]):
297  pincw[z, i, j] = pincw[z, i, j] * axyinap[np.int32(pincx[z, i, j]),
298  np.int32(pincy[z, i, j])]
299 
300  pincw = pincw * np.tile(1.0 / np.sum(pincw, axis=0), (4, 1, 1))
301 
302  return pincx, pincy, pincw
303 
304 
305 def pcgeom(nr, npp, cobs, ncp, ncmar):
306  """
307  This routine builds a geom_struct. px and py are the x and y
308  coordinates of points in the polar arrays. cr and cp are the
309  r and phi coordinates of points in the cartesian grids. ncmar
310  allows the possibility that there is a margin of ncmar points
311  in the cartesian arrays outside the region of interest
312 
313  TODO:
314 
315  :parameters:
316 
317  nr:
318 
319  npp:
320 
321  cobs: (float) : central obstruction
322 
323  ncp:
324 
325  ncmar:
326 
327  :returns:
328 
329  ncp:
330 
331  ncmar:
332 
333  px:
334 
335  py:
336 
337  cr:
338 
339  cp:
340 
341  pincx:
342 
343  pincy:
344 
345  pincw:
346 
347  ap:
Here is the caller graph for this function: