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

Pupil creation functions. More...

Functions

def make_pupil (dim, pupd, tel, xc=-1, yc=-1, real=0, halfSpider=False)
 Initialize the system pupil. More...
 
def make_pupil_generic (dim, pupd, t_spiders=0.01, spiders_type=SpiderType.SIX, xc=0, yc=0, real=0, cobs=0)
 Initialize the system pupil. More...
 
def make_VLT (dim, pupd, tel)
 Initialize the VLT pupil. More...
 
def make_EELT (dim, pupd, tel, N_seg=-1)
 Initialize the EELT pupil. More...
 
def make_phase_ab (dim, pupd, tel, pup=None, xc=-1, yc=-1, real=0, halfSpider=False)
 Compute the EELT M1 phase aberration. More...
 
def generateEeltPupilMask (npt, dspider, i0, j0, pixscale, gap, rotdegree, D=40.0, cobs=0, centerMark=0, halfSpider=False, pitch=1.244683637214, nseg=33, inner_rad=4.1, outer_rad=15.4, R=95.7853, nominalD=40, half_seg=0.75, refl=None, rotSpiderDegree=None)
 
def fillPolygon (x, y, i0, j0, scale, gap, N, index=0)
 
def compute6Segments (pupNoSpiders, N, pixscale, dspider, i0, j0, rot=0)
 
def compute1Spider (nspider, N, dspider, i0, j0, scale, rot)
 
def fillSpider (N, nspider, dspider, i0, j0, scale, rot)
 
def fillHalfSpider (N, nspider, dspider, i0, j0, scale, rot)
 
def createHexaPattern (pitch, supportSize)
 
def generateCoordSegments (D, rot, pitch=1.244683637214, nseg=33, inner_rad=4.1, outer_rad=15.4, R=95.7853, nominalD=40)
 
def gendron ()
 
def reorganizeSegmentsOrderESO (x, y)
 
def getdatatype (truc)
 Returns the data type of a numpy variable, either scalar value or array. More...
 
def generateSegmentProperties (attribute, hx, hy, i0, j0, scale, gap, N, D, softGap=0, nominalD=40, pitch=1.244683637214, half_seg=0.75)
 
def centrePourVidal (N, i0, j0, centerMark)
 

Variables

string EELT_data = os.environ.get('SHESHA_ROOT') + "/data/apertures/"
 

Detailed Description

Pupil creation functions.

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

◆ centrePourVidal()

def shesha.util.make_pupil.centrePourVidal (   N,
  i0,
  j0,
  centerMark 
)

Definition at line 1123 of file make_pupil.py.

1123  """
1124  scale = 1.0
1125  res = 0
1126  X = (np.arange(N) - i0) * scale
1127  Y = (np.arange(N) - j0) * scale
1128  X, Y = np.meshgrid(X, Y, indexing='ij') # convention d'appel [x,y]
1129  if centerMark == 1:
1130  res = (X**2 + Y**2) < 1
1131  if centerMark == 2:
1132  res = (np.abs(X) < 0.9) | (np.abs(Y) < 0.9)
1133  return res
Here is the caller graph for this function:

◆ compute1Spider()

def shesha.util.make_pupil.compute1Spider (   nspider,
  N,
  dspider,
  i0,
  j0,
  scale,
  rot 
)

Definition at line 758 of file make_pupil.py.

758  """
759  a = np.ones((N, N), dtype=np.bool)
760  X = (np.arange(N) - i0) * scale
761  Y = (np.arange(N) - j0) * scale
762  X, Y = np.meshgrid(X, Y, indexing='ij') # convention d'appel [x,y]
763  w = 2 * np.pi / 6
764  i = nspider
765  nn = (abs(X * np.cos(i * w - rot) + Y * np.sin(i * w - rot)) < dspider / 2.)
766  a[nn] = False
767  return a
768 
769 
770 def fillSpider(N, nspider, dspider, i0, j0, scale, rot):
771  """
772  Creates a boolean spider mask on a map of dimensions (N,N)
773  The spider is centred at floating-point coords (i0,j0).
774 
775  :returns: spider image (boolean)
776  :param int N: size of output image
777  :param int nspider: number of spiders
778  :param float dspider: width of spiders
779  :param float i0: coord of spiders symmetry centre
780  :param float j0: coord of spiders symmetry centre
781  :param float scale: size of a pixel in same unit as dspider
782  :param float rot: rotation angle in radians
783 
Here is the caller graph for this function:

◆ compute6Segments()

def shesha.util.make_pupil.compute6Segments (   pupNoSpiders,
  N,
  pixscale,
  dspider,
  i0,
  j0,
  rot = 0 
)

Definition at line 725 of file make_pupil.py.

725  """
726  npts = 200
727  msk = np.zeros((6, pupNoSpiders.shape[0], pupNoSpiders.shape[1]))
728  mid = int(pupNoSpiders.shape[0] / 2)
729  tmp = np.zeros((pupNoSpiders.shape[0], pupNoSpiders.shape[1]))
730  for angle in np.linspace(0, 60, npts):
731  tmp += compute1Spider(0, N, dspider, i0, j0, pixscale, angle * 2 * np.pi / 360)
732  msk[5, :, :] = tmp < npts * pupNoSpiders
733  msk[5, mid:, :] = 0
734  msk[2, :, :] = tmp < npts * pupNoSpiders
735  msk[2, :mid, :] = 0
736  tmp *= 0
737  for angle in np.linspace(0, 60, npts):
738  tmp += compute1Spider(1, N, dspider, i0, j0, pixscale, angle * 2 * np.pi / 360)
739  msk[0, :, :] = tmp < npts * pupNoSpiders
740  msk[0, mid:, :] = 0
741  msk[3, :, :] = tmp < npts * pupNoSpiders
742  msk[3, :mid, :] = 0
743  tmp *= 0
744  for angle in np.linspace(0, 60, npts):
745  tmp += compute1Spider(2, N, dspider, i0, j0, pixscale, angle * 2 * np.pi / 360)
746  msk[1, :, :] = tmp < npts * pupNoSpiders
747  msk[1, :, :mid] = 0
748  msk[4, :, :] = tmp < npts * pupNoSpiders
749  msk[4, :, mid:] = 0
750  return msk
751 
752 
753 def compute1Spider(nspider, N, dspider, i0, j0, scale, rot):
754  """
755  Fonction de fab pour creer le slaving.
756  La fonction cree un tableau de booleens avec une seule spider.
757  Utilisee par la fonction compute6Segments()
Here is the call graph for this function:

◆ createHexaPattern()

def shesha.util.make_pupil.createHexaPattern (   pitch,
  supportSize 
)

Definition at line 825 of file make_pupil.py.

825  """
826  V3 = np.sqrt(3)
827  nx = int(np.ceil((supportSize / 2.0) / pitch) + 1)
828  x = pitch * (np.arange(2 * nx + 1) - nx)
829  ny = int(np.ceil((supportSize / 2.0) / pitch / V3) + 1)
830  y = (V3 * pitch) * (np.arange(2 * ny + 1) - ny)
831  x, y = np.meshgrid(x, y, indexing='ij')
832  x = x.flatten()
833  y = y.flatten()
834  peak_axis = np.append(x, x + pitch / 2.) # axe dirige selon sommet
835  flat_axis = np.append(y, y + pitch * V3 / 2.) # axe dirige selon plat
836  return flat_axis, peak_axis
837 
838 
839 def generateCoordSegments(D, rot, pitch=1.244683637214, nseg=33, inner_rad=4.1,
840  outer_rad=15.4, R=95.7853, nominalD=40):
841  """
842  Computes the coordinates of the corners of all the hexagonal
843  segments of M1.
844  Result is a tuple of arrays(6, 798).
845 
846  Parameters
847  -----------------------------------------
848  D: (float) : pupil diameter in meters (it must be set to 40.0 m for the ELT)
849  rot: (float) : pupil rotation angle in radians
850  pitch: (float): Segment pitch [meters]
851  nseg: (int) : number of segments across the diameter
852  inner_rad : (float): Inner radius [meters]
853  outer_rad : (float): Outer radius [meters]
854  R : (float): Curvature radius of the M1
855  nominalD: (float): diameter for nominal pupil
Here is the caller graph for this function:

◆ fillHalfSpider()

def shesha.util.make_pupil.fillHalfSpider (   N,
  nspider,
  dspider,
  i0,
  j0,
  scale,
  rot 
)

Definition at line 796 of file make_pupil.py.

796 def fillHalfSpider(N, nspider, dspider, i0, j0, scale, rot):
797  a = np.ones((N, N), dtype=np.bool)
798  b = np.ones((N, N), dtype=np.bool)
799  X = (np.arange(N) - i0) * scale
800  Y = (np.arange(N) - j0) * scale
801  X, Y = np.meshgrid(X, Y, indexing='ij') # convention d'appel [x,y]
802  w = 2 * np.pi / nspider
803  for i in range(nspider):
804  right = (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) <
805  dspider / 2) * (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) > 0.)
806  left = (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) >
807  -dspider / 2) * (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) < 0.)
808  a[right] = False
809  b[left] = False
810  return a, b
811 
812 
813 def createHexaPattern(pitch, supportSize):
814  """
815  Cree une liste de coordonnees qui decrit un maillage hexagonal.
816  Retourne un tuple (x,y).
817 
818  Le maillage est centre sur 0, l'un des points est (0,0).
819  Une des pointes de l'hexagone est dirigee selon l'axe Y, au sens ou le
820  tuple de sortie est (x,y).
821 
822  :param float pitch: distance between 2 neighbour points
823  :param int supportSize: size of the support that need to be populated
824 
Here is the caller graph for this function:

◆ fillPolygon()

def shesha.util.make_pupil.fillPolygon (   x,
  y,
  i0,
  j0,
  scale,
  gap,
  N,
  index = 0 
)

Definition at line 640 of file make_pupil.py.

640  """
641  # define coordinates map centred on (i0,j0) with same units as x,y.
642  X = (np.arange(N) - i0) * scale
643  Y = (np.arange(N) - j0) * scale
644  X, Y = np.meshgrid(X, Y, indexing='ij') # indexage [x,y]
645 
646  # define centre x0, y0 of the polygon
647  x0 = np.mean(x)
648  y0 = np.mean(y)
649 
650  # compute angles of all pixels coordinates of the map, and all
651  # corners of the polygon
652  T = (np.arctan2(Y - y0, X - x0) + 2 * np.pi) % (2 * np.pi)
653  t = (np.arctan2(y - y0, x - x0) + 2 * np.pi) % (2 * np.pi)
654 
655  # on va voir dans quel sens ca tourne. Je rajoute ca pour que ca marche
656  # quel que soit le sens de rotation des points du polygone.
657  # En fait, j'aurais peut etre pu classer les points par leur angle, pour
658  # etre sur que ca marche meme si les points sont donnes dans ts les cas
659  sens = np.median(np.diff(t))
660  if sens < 0:
661  x = x[::-1]
662  y = y[::-1]
663  t = t[::-1]
664 
665  # re-organise order of polygon points so that it starts from
666  # angle = 0, or at least closest to 0.
667  imin = t.argmin() # position of the minimum
668  if imin != 0:
669  x = np.roll(x, -imin)
670  y = np.roll(y, -imin)
671  t = np.roll(t, -imin)
672 
673  # For each couple of consecutive corners A, B, of the polygon, one fills
674  # the triangle AOB with True.
675  # Last triangle has a special treatment because it crosses the axis
676  # with theta=0=2pi
677  n = x.shape[0] # number of corners of polygon
678  indx, indy = (np.array([], dtype=np.int), np.array([], dtype=np.int))
679  distedge = np.array([], dtype=np.float)
680  for i in range(n):
681  j = i + 1 # j=element next i except when i==n : then j=0 (cycling)
682  if j == n:
683  j = 0
684  sub = np.where((T >= t[-1]) | (T <= (t[0])))
685  else:
686  sub = np.where((T >= t[i]) & (T <= t[j]))
687  # compute unitary vector des 2 sommets
688  dy = y[j] - y[i]
689  dx = x[j] - x[i]
690  vnorm = np.sqrt(dx**2 + dy**2)
691  dx /= vnorm
692  dy /= vnorm
693  # calcul du produit vectoriel
694  crossprod = dx * (Y[sub] - y[i]) - dy * (X[sub] - x[i])
695  tmp = crossprod > gap
696  indx = np.append(indx, sub[0][tmp])
697  indy = np.append(indy, sub[1][tmp])
698  distedge = np.append(distedge, crossprod[tmp])
699 
700  # choice of what is returned : either only the indexes, or the
701  # boolean map
702  if index == 1:
703  return (indx, indy, distedge)
704  elif index == 2:
705  a = np.zeros((N, N))
706  a[indx, indy] = distedge
707  return a
708  else:
709  a = np.zeros((N, N), dtype=np.bool)
710  a[indx, indy] = True # convention [x,y]
711 
712  return a
713 
714 
715 def compute6Segments(pupNoSpiders, N, pixscale, dspider, i0, j0, rot=0):
716  """
717  N = p_geom.pupdiam
718  i0 = j0 = N / 2. - 0.5
719  D = p_tel.diam
720  pixscale = D/N
721  dspider = 0.51
722 
723  Utilisee dans compass/shesha/shesha/supervisor/canapassSupervisor.py
724  pour le slaving des actus.
Here is the caller graph for this function:

◆ fillSpider()

def shesha.util.make_pupil.fillSpider (   N,
  nspider,
  dspider,
  i0,
  j0,
  scale,
  rot 
)

Definition at line 784 of file make_pupil.py.

784  """
785  a = np.ones((N, N), dtype=np.bool)
786  X = (np.arange(N) - i0) * scale
787  Y = (np.arange(N) - j0) * scale
788  X, Y = np.meshgrid(X, Y, indexing='ij') # convention d'appel [x,y]
789  w = 2 * np.pi / nspider
790  for i in range(nspider):
791  nn = (abs(X * np.cos(i * w - rot) + Y * np.sin(i * w - rot)) < dspider / 2.)
792  a[nn] = False
793  return a
794 
795 
Here is the caller graph for this function:

◆ gendron()

def shesha.util.make_pupil.gendron ( )

Definition at line 919 of file make_pupil.py.

919  """
920  mymsg = [
921  "\n\n\n\n", "__ ___ ____ _ _ ___ _ _ ___ _",
922  "\ \ / / \ | _ \| \ | |_ _| \ | |/ ___|",
923  " \ \ /\ / / _ \ | |_) | \| || || \| | | _ ",
924  " \ V V / ___ \| _ <| |\ || || |\ | |_| |",
925  " \_/\_/_/ \_\_| \_\_| \_|___|_| \_|\____|", " \n",
926  "Vous utilisez un telescope de type ELT. Ce telescope",
927  "est fait pour etre utilise avec un diametre de 40 m.", " ",
928  "Or, vous utilisez un diametre different. Cela signifie",
929  "que le telescope que vous etes en train de creer a une",
930  "taille differente du veritable E-ELT de l'ESO.", " ",
931  " * Soit vous savez exactement ce que vous faites, auquel",
932  "cas bonne route.", " ",
933  " * Soit vous desirez creer LE vrai E-ELT et il faut changer",
934  "plusieurs choses:",
935  " 1) le diametre telescope de votre fichier de parametres et",
936  " le renseigner a 40 metres.",
937  " p_tel.set_diam(40.0) # Nominal size for the real EELT",
938  " 2) le nombre d'actionneurs de M4 a 75",
939  " p_dm0.set_nact(75) # 75 actu in 40m for pitch=54.05cm",
940  " 3) option: tourner la pupille de 90 degres pour revenir au",
941  " cas initial de compass",
942  " p_tel.set_pupangle(90.) # ELT pup rotation in degrees"
943  " ", "\n\n"
944  ]
945  for ligne in mymsg:
946  print(ligne)
947 
948 
949 def reorganizeSegmentsOrderESO(x, y):
950  """
951  Reorganisation des segments facon ESO.
952  Voir
953  ESO-193058 Standard Coordinate System and Basic Conventions
954 
955  :param float x: tableau des centres X des segments
956  :param float y: idem Y
957  :return tuple (x,y): meme tuple que les arguments d'entree, mais tries.
958 

◆ generateCoordSegments()

def shesha.util.make_pupil.generateCoordSegments (   D,
  rot,
  pitch = 1.244683637214,
  nseg = 33,
  inner_rad = 4.1,
  outer_rad = 15.4,
  R = 95.7853,
  nominalD = 40 
)

Definition at line 856 of file make_pupil.py.

856 
857  """
858  V3 = np.sqrt(3)
859  #pitch = 1.227314 # no correction du bol
860  #pitch = 1.244683637214 # diametre du cerle INSCRIT
861  # diamseg = pitch*2/V3 # diametre du cercle contenant TOUT le segment
862  # print("segment diameter : %.6f\n" % diamseg)
863 
864  # Creation d'un pattern hexa avec pointes selon la variable <ly>
865  lx, ly = createHexaPattern(pitch, (nseg + 2) * pitch)
866  ll = np.sqrt(lx**2 + ly**2)
867  # Elimination des segments non valides grace a 2 nombres parfaitement
868  # empiriques ajustes a-la-mano.
869  #inner_rad, outer_rad = 4.1, 15.4 # nominal, 798 segments
870  nn = (ll > inner_rad * pitch) & (ll < outer_rad * pitch)
871  lx = lx[nn]
872  ly = ly[nn]
873  lx, ly = reorganizeSegmentsOrderESO(lx, ly)
874  ll = np.sqrt(lx**2 + ly**2)
875 
876  # n = ll.shape[0]
877  # print("Nbre de segments : %d\n" % n)
878  # Creation d'un hexagone-segment avec pointe dirigee vers
879  # variable <hx> (d'ou le cos() sur hx)
880  th = np.linspace(0, 2 * np.pi, 7)[0:6]
881  hx = np.cos(th) * pitch / V3
882  hy = np.sin(th) * pitch / V3
883 
884  # Le maillage qui permet d'empiler des hexagones avec sommets 3h-9h
885  # est un maillage hexagonal avec sommets 12h-6h, donc a 90°.
886  # C'est pour ca qu'il a fallu croiser les choses avant.
887  x = (lx[None, :] + hx[:, None])
888  y = (ly[None, :] + hy[:, None])
889  r = np.sqrt(x**2 + y**2)
890  #R = 95.7853
891  rrc = R / r * np.arctan(r / R) # correction factor
892  x *= rrc
893  y *= rrc
894 
895  #nominalD = 40.0 # size of the OFFICIAL E-ELT
896  if D != nominalD:
897  x *= D / nominalD
898  y *= D / nominalD
899 
900  # Rotation matrices
901  mrot = np.array([[np.cos(rot), np.sin(rot)], [-np.sin(rot), np.cos(rot)]])
902 
903  # rotation of coordinates
904  # le tableau [x,y] est de taille (2,6,798). Faut un transpose a la con
905  # pour le transformer en (6,2,798) pour pouvoir faire le np.dot
906  # correctement. En sortie, xrot est (2,6,798).
907  xyrot = np.dot(mrot, np.transpose(np.array([x, y]), (1, 0, 2)))
908 
909  return xyrot[0], xyrot[1]
910 
911 
912 def gendron():
913  """
914  La fonction est appelee quand l'utilisateur a demande une pupille
915  ELT, et renseigne un diametre de telescope different de 40 metres.
916 
917  Faut vraiment que je commente ou t'as compris ??
918 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateEeltPupilMask()

def shesha.util.make_pupil.generateEeltPupilMask (   npt,
  dspider,
  i0,
  j0,
  pixscale,
  gap,
  rotdegree,
  D = 40.0,
  cobs = 0,
  centerMark = 0,
  halfSpider = False,
  pitch = 1.244683637214,
  nseg = 33,
  inner_rad = 4.1,
  outer_rad = 15.4,
  R = 95.7853,
  nominalD = 40,
  half_seg = 0.75,
  refl = None,
  rotSpiderDegree = None 
)

Definition at line 549 of file make_pupil.py.

549  gap = 0.0
550  pup = generateEeltPupilMask(npt, dspider, i0, j0, pixscale, gap, rotdegree)
551 
552  """
553  rot = rotdegree * np.pi / 180
554 
555  if rotSpiderDegree is None:
556  rotSpider = rot
557  else:
558  rotSpider = rotSpiderDegree * np.pi / 180
559 
560  # Generation of segments coordinates.
561  # hx and hy have a shape [6,798] describing the 6 vertex of the 798
562  # hexagonal mirrors
563  #hx, hy = generateCoordSegments( D, rot)
564  hx, hy = generateCoordSegments(D, rot, pitch=pitch, nseg=nseg, inner_rad=inner_rad,
565  outer_rad=outer_rad, R=R, nominalD=nominalD)
566  # From the data of hex mirrors, we build the pupil image using
567  # boolean
568  #pup = generateSegmentProperties(True, hx, hy, i0, j0, pixscale, gap, npt, D)
569  if (refl == 0):
570  refl = True
571  elif np.isscalar(refl):
572  referr = np.random.random(hx.size)
573  referr = referr * refl / np.std(referr)
574  refl = np.ones(hx.size) - referr
575  elif type(refl) == list:
576  if len(refl) == 3:
577  refpist = np.random.random(hx.size)
578  refpist = refpist * refl[0] / np.std(refpist)
579  reftip = np.random.random(hx.size)
580  reftip = reftip * refl[1] / np.std(reftip)
581  reftilt = np.random.random(hx.size)
582  reftilt = reftilt * refl[2] / np.std(reftilt)
583  refl = np.array([refpist, reftip, reftilt])
584  else:
585  raise ValueError(
586  "refl param must be None, scalar (reflectivity std error) or list of 3 elements (piston, tip and tilt std errors)"
587  )
588 
589  pup = generateSegmentProperties(refl, hx, hy, i0, j0, pixscale, gap, npt, D,
590  nominalD=nominalD, pitch=pitch, half_seg=half_seg)
591  # SPIDERS ............................................
592  nspider = 3 # for the day where we have more/less spiders ;-)
593  if (dspider > 0 and nspider > 0):
594  if (halfSpider is True):
595  pup = pup * fillHalfSpider(npt, nspider, dspider, i0, j0, pixscale,
596  rotSpider)
597  else:
598  pup = pup * fillSpider(npt, nspider, dspider, i0, j0, pixscale, rotSpider)
599 
600  # Rajout d'un pixel au centre (pour marquer le centre) ou d'une croix,
601  # selon la valeur de centerMark
602  if centerMark:
603  pup = np.logical_xor(pup, centrePourVidal(npt, i0, j0, centerMark))
604 
605  if cobs > 0:
606  obstru = (util.dist(pup.shape[0], pup.shape[0] // 2 + 0.5,
607  pup.shape[0] // 2 + 0.5) >=
608  (pup.shape[0] * cobs + 1.) * 0.5).astype(np.float32)
609  pup *= obstru
610  return pup
611 
612 
613 def fillPolygon(x, y, i0, j0, scale, gap, N, index=0):
614  """
615  From a list of points defined by their 2 coordinates list
616  x and y, creates a filled polygon with sides joining the points.
617  The polygon is created in an image of size (N, N).
618  The origin (x,y)=(0,0) is mapped at pixel i0, j0 (both can be
619  floating-point values).
620  Arrays x and y are supposed to be in unit U, and scale is the
621  pixel size in U units.
622 
623  :returns: filled polygon (N, N), boolean
624  :param float x, y: list of points defining the polygon
625  :param float i0, j0: index of pixels where the pupil should be centred.
626  Can be floating-point indexes.
627  :param float scale: size of a pixel of the image, in same unit as x and y.
628  :param float N: size of output image.
629 
630  :Example:
631  x = np.array([1,-1,-1.5,0,1.1])
632  y = np.array([1,1.5,-0.2,-2,0])
633  N = 200
634  i0 = N/2
635  j0 = N/2
636  gap = 0.
637  scale = 0.03
638  pol = fillPolygon(x, y, i0, j0, scale, gap, N, index=2)
639 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateSegmentProperties()

def shesha.util.make_pupil.generateSegmentProperties (   attribute,
  hx,
  hy,
  i0,
  j0,
  scale,
  gap,
  N,
  D,
  softGap = 0,
  nominalD = 40,
  pitch = 1.244683637214,
  half_seg = 0.75 
)

Definition at line 1041 of file make_pupil.py.

1041 
1042  """
1043 
1044  # number of segments
1045  nseg = hx.shape[-1]
1046  # If <attribute> is a scalar, then we make a list. It will be required
1047  # later on to set the attribute to each segment.
1048  if np.isscalar(attribute):
1049  attribute = np.array([attribute] * nseg)
1050 
1051  # the pupil map is created with the same data type as <attribute>
1052  pupil = np.zeros((N, N), dtype=getdatatype(attribute))
1053 
1054  # average coord of segments
1055  x0 = np.mean(hx, axis=0)
1056  y0 = np.mean(hy, axis=0)
1057  # avg coord of segments in pixel indexes
1058  x0 = x0 / scale + i0
1059  y0 = y0 / scale + j0
1060  # size of mini-support
1061  hexrad = half_seg * D / nominalD / scale
1062  ix0 = np.floor(x0 - hexrad).astype(int) - 1
1063  iy0 = np.floor(y0 - hexrad).astype(int) - 1
1064  segdiam = np.ceil(hexrad * 2 + 1).astype(int) + 1
1065 
1066  n = attribute.shape[0]
1067  if n != 3:
1068  # attribute is a signel value : either reflectivity, or boolean,
1069  # or just piston.
1070  if softGap != 0:
1071  # Soft gaps
1072  # The impact of gaps are modelled using a simple function: Lorentz, 1/(1+x**2)
1073  # The fwhm is always equal to 2 pixels because the gap is supposed
1074  # to be "small/invisible/undersampled". The only visible thing is
1075  # the width of the impulse response, chosen 2-pixel wide to be
1076  # well sampled.
1077  # The "depth" is related to the gap width. The integral of a Lorentzian
1078  # of 2 pix wide is PI. Integral of a gap of width 'gap' in pixels is 'gap'.
1079  # So the depth equals to gap/scale/np.pi.
1080  for i in range(nseg):
1081  indx, indy, distedge = fillPolygon(hx[:, i], hy[:, i], i0 - ix0[i],
1082  j0 - iy0[i], scale, gap * 0., segdiam,
1083  index=1)
1084  pupil[indx + ix0[i], indy + iy0[i]] = attribute[i] * (
1085  1. - (gap / scale / np.pi) / (1 + (distedge / scale)**2))
1086  else:
1087  # Hard gaps
1088  for i in range(nseg):
1089  indx, indy, distedge = fillPolygon(hx[:, i], hy[:, i], i0 - ix0[i],
1090  j0 - iy0[i], scale, gap, segdiam,
1091  index=1)
1092  pupil[indx + ix0[i], indy + iy0[i]] = attribute[i]
1093  else:
1094  # attribute is [piston, tip, tilt]
1095  minimap = np.zeros((segdiam, segdiam))
1096  xmap = np.arange(segdiam) - segdiam / 2
1097  xmap, ymap = np.meshgrid(xmap, xmap, indexing='ij') # [x,y] convention
1098  #pitch = 1.244683637214 # diameter of inscribed circle
1099  diamseg = pitch * 2 / np.sqrt(3) # diameter of circumscribed circle
1100  diamfrizou = (pitch + diamseg) / 2 * D / nominalD # average diameter of the 2
1101  # Calcul du facteur de mise a l'echelle pour l'unite des tilts.
1102  # xmap et ymap sont calculees avec un increment de +1 pour deux pixels
1103  # voisins, donc le facteur a appliquer est tel que l'angle se conserve
1104  # donc factunit*1 / scale = 4*factunit
1105  factunit = 4 * scale / diamfrizou
1106  for i in range(nseg):
1107  indx, indy, _ = fillPolygon(hx[:, i], hy[:, i], i0 - ix0[i], j0 - iy0[i],
1108  scale, 0., segdiam, index=1)
1109  minimap = attribute[0, i] + (factunit * attribute[1, i]) * xmap + (
1110  factunit * attribute[2, i]) * ymap
1111  pupil[indx + ix0[i], indy + iy0[i]] = minimap[indx, indy]
1112 
1113  return pupil
1114 
1115 
1116 def centrePourVidal(N, i0, j0, centerMark):
1117  """
1118  Renvoie une image de boolens (False) de taille (N,N) avec un point
1119  ou une croix (True) centree sur (i0, j0).
1120  :param int N: taille de l'image de sortie
1121  :param float i0, j0: position du marqueur de sortie
1122  :param int centerMark: 0 (pour rien), 1 (option point) ou 2 (option croix)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getdatatype()

def shesha.util.make_pupil.getdatatype (   truc)

Returns the data type of a numpy variable, either scalar value or array.

Definition at line 983 of file make_pupil.py.

983  """
984  if np.isscalar(truc):
985  return type(truc)
986  else:
987  return type(truc.flatten()[0])
988 
989 
990 def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D, softGap=0,
991  nominalD=40, pitch=1.244683637214, half_seg=0.75):
992  """
993  Builds a 2D image of the pupil with some attributes for each of the
994  segments. Those segments are described from arguments hx and hy, that
995  are produced by the function generateCoordSegments(D, rot).
996 
997  When attribute is a phase, then it must be a float array of dimension
998  [3, 798] with the dimension 3 being piston, tip, and tilt.
999  Units of phase is xxx rms, and the output of the procedure will be
1000  in units of xxx.
1001 
1002 
1003  :returns: pupil image (N, N), with the same type of input argument attribute
1004 
1005  :param float/int/bool attribute: scalar value or 1D-array of the reflectivity of
1006  the segments or 2D array of phase
1007  If attribute is scalar, the value will be replicated for all segments.
1008  If attribute is a 1D array, then it shall contain the reflectivities
1009  of all segments.
1010  If attribute is a 2D array then it shall contain the piston, tip
1011  and tilt of the segments. The array shall be of dimension
1012  [3, 798] that contains [piston, tip, tilt]
1013  On output, the data type of the pupil map will be the same as attribute.
1014  :param float hx, hy: arrays [6,:] describing the segment shapes. They are
1015  generated using generateCoordSegments()
1016  :param float dspider: width of spiders in meters
1017  :param float i0, j0: index of pixels where the pupil should be centred.
1018  Can be floating-point indexes.
1019  :param float scale: size of a pixel of the image, in meters.
1020  :param float gap: half-space between segments in meters
1021  :param int N: size of the output array (N,N)
1022  :param float D: diameter of the pupil. For the nominal EELT, D shall
1023  be set to 40.0
1024  :param bool softGap: if False, the gap between segments is binary 0/1
1025  depending if the pixel is within the gap or not. If True, the gap
1026  is a smooth region of a fwhm of 2 pixels with a depth related to the
1027  gap width.
1028  :param float nominalD: diameter needed to get nominal pupil aperture
1029  :param float pitch: segment pitch
1030  :param float half_seg: segment half size
1031 
1032 
1033 
1034  attribute = np.ones(798)+np.random.randn(798)/20.
1035  N = 800
1036  i0 = N/2
1037  j0 = N/2
1038  rotdegree = 0.0
1039  scale = 41./N
1040  gap = 0.03
Here is the caller graph for this function:

◆ make_EELT()

def shesha.util.make_pupil.make_EELT (   dim,
  pupd,
  tel,
  N_seg = -1 
)

Initialize the EELT pupil.

:parameters:

dim (long) : linear size of ???

pupd (long) : linear size of total pupil

tel (Param_tel) : Telescope structure

N_seg (int)

TODO complete TODO add force rescal pup elt

Definition at line 261 of file make_pupil.py.

261  """
262  if (N_seg == -1):
263  EELT_file = EELT_data + "EELT-Custom_N" + str(dim) + "_COBS" + str(
264  100 * tel.cobs) + "_CLOCKED" + str(tel.pupangle) + "_TSPIDERS" + str(
265  100 * tel.t_spiders) + "_MS" + str(
266  tel.nbrmissing) + "_REFERR" + str(
267  100 * tel.referr) + ".h5"
268  else:
269  EELT_file = EELT_data + tel.type_ap.decode('UTF-8') + "_N" + str(
270  dim) + "_COBS" + str(100 * tel.cobs) + "_CLOCKED" + str(
271  tel.pupangle) + "_TSPIDERS" + str(
272  100 * tel.t_spiders) + "_MS" + str(
273  tel.nbrmissing) + "_REFERR" + str(
274  100 * tel.referr) + ".h5"
275  if (os.path.isfile(EELT_file)):
276  print("reading EELT pupil from file ", EELT_file)
277  pup = h5u.readHdf5SingleDataset(EELT_file)
278  else:
279  print("creating EELT pupil...")
280  file = EELT_data + "Coord_" + tel.type_ap.decode('UTF-8') + ".dat"
281  data = np.fromfile(file, sep="\n")
282  data = np.reshape(data, (data.size // 2, 2))
283  x_seg = data[:, 0]
284  y_seg = data[:, 1]
285 
286  file = EELT_data + "EELT_MISSING_" + tel.type_ap.decode('UTF-8') + ".dat"
287  k_seg = np.fromfile(file, sep="\n").astype(np.int32)
288 
289  W = 1.45 * np.cos(np.pi / 6)
290 
291  #tel.set_diam(39.146)
292  #tel.set_diam(37.)
293  Range = (0.5 * (tel.diam * dim / pupd) - 0.25 / dim)
294  X = np.tile(np.linspace(-Range, Range, dim, dtype=np.float32), (dim, 1))
295 
296  if (tel.t_spiders == -1):
297  print("force t_spider =%5.3f" % (0.014))
298  tel.set_t_spiders(0.014)
299  #t_spiders=0.06
300  #tel.set_t_spiders(t_spiders)
301 
302  if (tel.nbrmissing > 0):
303  k_seg = np.sort(k_seg[:tel.nbrmissing])
304 
305  file = EELT_data + "EELT_REF_ERROR" + ".dat"
306  ref_err = np.fromfile(file, sep="\n")
307 
308  #mean_ref = np.sum(ref_err)/798.
309  #std_ref = np.sqrt(1./798.*np.sum((ref_err-mean_ref)**2))
310  #mean_ref=np.mean(ref_err)
311  std_ref = np.std(ref_err)
312 
313  ref_err = ref_err * tel.referr / std_ref
314 
315  if (tel.nbrmissing > 0):
316  ref_err[k_seg] = 1.0
317 
318  pup = np.zeros((dim, dim))
319 
320  t_3 = np.tan(np.pi / 3.)
321  if N_seg == -1:
322 
323  vect_seg = tel.vect_seg
324  for i in vect_seg:
325  Xt = X + x_seg[i]
326  Yt = X.T + y_seg[i]
327  pup+=(1-ref_err[i])*(Yt<0.5*W)*(Yt>=-0.5*W)*(0.5*(Yt+t_3*Xt)<0.5*W) \
328  *(0.5*(Yt+t_3*Xt)>=-0.5*W)*(0.5*(Yt-t_3*Xt)<0.5*W) \
329  *(0.5*(Yt-t_3*Xt)>=-0.5*W)
330 
331  else:
332  for i in range(N_seg):
333  Xt = X + x_seg[i]
334  Yt = X.T + y_seg[i]
335  pup+=(1-ref_err[i])*(Yt<0.5*W)*(Yt>=-0.5*W)*(0.5*(Yt+t_3*Xt)<0.5*W) \
336  *(0.5*(Yt+t_3*Xt)>=-0.5*W)*(0.5*(Yt-t_3*Xt)<0.5*W) \
337  *(0.5*(Yt-t_3*Xt)>=-0.5*W)
338  if (tel.t_spiders == 0):
339  print('No spider')
340  else:
341  t_spiders = tel.t_spiders * (tel.diam * dim / pupd)
342 
343  s2_6 = 2 * np.sin(np.pi / 6)
344  t_6 = np.tan(np.pi / 6)
345 
346  spiders_map = np.abs(X) > t_spiders / 2
347  spiders_map *= (
348  (X.T >
349  (X + t_spiders / s2_6) * t_6) + (X.T <
350  (X - t_spiders / s2_6) * t_6))
351  spiders_map *= (
352  (X.T >
353  (-X + t_spiders / s2_6) * t_6) + (X.T <
354  (-X - t_spiders / s2_6) * t_6))
355 
356  pup = pup * spiders_map
357 
358  if (tel.pupangle != 0):
359  pup = interp.rotate(pup, tel.pupangle, reshape=False, order=0)
360 
361  print("writing EELT pupil to file ", EELT_file)
362  h5u.writeHdf5SingleDataset(EELT_file, pup)
363 
364  print("EELT pupil created")
365  return pup
366 
367 
Here is the caller graph for this function:

◆ make_phase_ab()

def shesha.util.make_pupil.make_phase_ab (   dim,
  pupd,
  tel,
  pup = None,
  xc = -1,
  yc = -1,
  real = 0,
  halfSpider = False 
)

Compute the EELT M1 phase aberration.

:parameters:

dim (long) : linear size of ???

pupd (long) : linear size of total pupil

tel (Param_tel) : Telescope structure

pup (?)

TODO complete

Definition at line 382 of file make_pupil.py.

382  """
383 
384  if ((tel.type_ap == ApertureType.GENERIC) or (tel.type_ap == ApertureType.VLT)):
385  return np.zeros((dim, dim)).astype(np.float32)
386 
387  elif tel.type_ap == ApertureType.EELT:
388 
389  return generateEeltPupilMask(
390  dim, 0, xc, yc, tel.diam / dim, tel.gap, tel.pupangle, D=tel.diam,
391  halfSpider=halfSpider, pitch=1.244683637214, nseg=33, inner_rad=4.1,
392  outer_rad=15.4, R=95.7853, nominalD=40, half_seg=0.75,
393  refl=[tel.std_piston, tel.std_tt, tel.std_tt])
394  elif (tel.type_ap == ApertureType.KECK):
395  seg_corner = 1.8
396  kpitch = seg_corner / 2 * np.sqrt(3)
397  knseg = 7
398  kinner_rad = 0.9
399  kouter_rad = 3.4
400  kR = 85
401  knominalD = 10.96
402  khalf_seg = 0.9
403  return generateEeltPupilMask(
404  dim, 0, xc, yc, tel.diam / dim, tel.gap, tel.pupangle, D=tel.diam,
405  cobs=tel.cobs, halfSpider=halfSpider, pitch=kpitch, nseg=knseg,
406  inner_rad=0.9, outer_rad=3.4, R=kR, nominalD=knominalD, half_seg=0.9,
407  refl=[tel.std_piston, tel.std_tt, tel.std_tt])
408  else:
409  ab_file = EELT_data + "aberration_" + tel.type_ap.decode('UTF-8') + \
410  "_N" + str(dim) + "_NPUP" + str(np.where(pup)[0].size) + "_CLOCKED" + str(
411  tel.pupangle) + "_TSPIDERS" + str(
412  100 * tel.t_spiders) + "_MS" + str(tel.nbrmissing) + "_REFERR" + str(
413  100 * tel.referr) + "_PIS" + str(
414  tel.std_piston) + "_TT" + str(tel.std_tt) + ".h5"
415  if (os.path.isfile(ab_file)):
416  print("reading aberration phase from file ", ab_file)
417  phase_error = h5u.readHdf5SingleDataset(ab_file)
418  else:
419  print("computing M1 phase aberration...")
420 
421  std_piston = tel.std_piston
422  std_tt = tel.std_tt
423 
424  W = 1.45 * np.cos(np.pi / 6)
425 
426  file = EELT_data + "EELT_Piston_" + tel.type_ap.decode('UTF-8') + ".dat"
427  p_seg = np.fromfile(file, sep="\n")
428  #mean_pis=np.mean(p_seg)
429  std_pis = np.std(p_seg)
430  p_seg = p_seg * std_piston / std_pis
431  N_seg = p_seg.size
432 
433  file = EELT_data + "EELT_TT_" + tel.type_ap.decode('UTF-8') + ".dat"
434  tt_seg = np.fromfile(file, sep="\n")
435 
436  file = EELT_data + "EELT_TT_DIRECTION_" + tel.type_ap.decode('UTF-8') + ".dat"
437  tt_phi_seg = np.fromfile(file, sep="\n")
438 
439  phase_error = np.zeros((dim, dim))
440  phase_tt = np.zeros((dim, dim))
441  phase_defoc = np.zeros((dim, dim))
442 
443  file = EELT_data + "Coord_" + tel.type_ap.decode('UTF-8') + ".dat"
444  data = np.fromfile(file, sep="\n")
445  data = np.reshape(data, (data.size // 2, 2))
446  x_seg = data[:, 0]
447  y_seg = data[:, 1]
448 
449  Range = (0.5 * (tel.diam * dim / pupd) - 0.25 / dim)
450 
451  X = np.tile(np.linspace(-Range, Range, dim, dtype=np.float32), (dim, 1))
452  t_3 = np.tan(np.pi / 3.)
453 
454  for i in range(N_seg):
455  Xt = X + x_seg[i]
456  Yt = X.T + y_seg[i]
457  SEG=(Yt<0.5*W)*(Yt>=-0.5*W)*(0.5*(Yt+t_3*Xt)<0.5*W) \
458  *(0.5*(Yt+t_3*Xt)>=-0.5*W)*(0.5*(Yt-t_3*Xt)<0.5*W) \
459  *(0.5*(Yt-t_3*Xt)>=-0.5*W)
460 
461  if (i == 0):
462  N_in_seg = np.sum(SEG)
463  Hex_diam = 2 * np.max(
464  np.sqrt(Xt[np.where(SEG)]**2 + Yt[np.where(SEG)]**2))
465 
466  if (tt_seg[i] != 0):
467  TT = tt_seg[i] * (
468  np.cos(tt_phi_seg[i]) * Xt + np.sin(tt_phi_seg[i]) * Yt)
469  mean_tt = np.sum(TT[np.where(SEG == 1)]) / N_in_seg
470  phase_tt += SEG * (TT - mean_tt)
471 
472  #TODO defocus
473 
474  phase_error += SEG * p_seg[i]
475 
476  N_EELT = np.where(pup)[0].size
477  if (np.sum(phase_tt) != 0):
478  phase_tt *= std_tt / np.sqrt(
479  1. / N_EELT * np.sum(phase_tt[np.where(pup)]**2))
480 
481  #TODO defocus
482 
483  phase_error += phase_tt + phase_defoc
484 
485  if (tel.pupangle != 0):
486  phase_error = interp.rotate(phase_error, tel.pupangle, reshape=False,
487  order=2)
488 
489  print("phase aberration created")
490  print("writing aberration filel to file ", ab_file)
491  h5u.writeHdf5SingleDataset(ab_file, phase_error)
492 
493  return phase_error
494 
495 
496 """
497 
498  _____ _ _____ ____ ___ ____ ___
499 | ____| | |_ _| | _ \|_ _/ ___/ _ \
500 | _| | | | | | |_) || | | | | | |
501 | |___| |___| | | _ < | | |__| |_| |
502 |_____|_____|_| |_| \_\___\____\___/
503 
504 
505 """
506 
507 
508 def generateEeltPupilMask(npt, dspider, i0, j0, pixscale, gap, rotdegree, D=40.0, cobs=0,
509  centerMark=0, halfSpider=False, pitch=1.244683637214, nseg=33,
510  inner_rad=4.1, outer_rad=15.4, R=95.7853, nominalD=40,
511  half_seg=0.75, refl=None, rotSpiderDegree=None):
512  """
513  Generates a boolean pupil mask of the binary EELT pupil
514  on a map of size (npt, npt).
515 
516 
517  :returns: pupil image (npt, npt), boolean
518  :param int npt: size of the output array
519  :param float dspider: width of spiders in meters
520  :param float i0, j0: index of pixels where the pupil should be centred = p_geom.pupdiam / 2. - 0.5
521  Can be floating-point indexes.
522  :param float pixscale: size of a pixel of the image, in meters = ptel.diam/(p_geom.pupdiam / 2. - 0.5)
523  :param float gap: gap between 2 segments in metres
524  :param float rotdegree: rotation angle of the pupil, in degrees.
525  :param float D: diameter of the pupil. For the nominal EELT, D shall
526  be set to 40.0
527  :param int centerMark: when centerMark!=0, a pixel is added at the centre of
528  symmetry of the pupil in order to debug things using compass.
529  centerMark==1 draws a point
530  centerMark==2 draws 2 lines
531  :param bool halfSpider: half Spider computation flag
532  :param float pitch: segment pitch
533  :param int nseg: number of segments across the diameter
534  :param float inner_rad: Inner radius [meters]
535  :param float outter_rad: outter radius [meters]
536  :param float R: M1 curvature radius
537  :param float nominalD: diameter needed to get nominal aperture after projection
538  :param float half_seg: segment half size
539  :param float refl: std of the reflectivity of each segment
540 
541  :Example:
542  npt = p_geom.pupdiam
543  D = p_tel.diam
544  i0 = npt / 2. - 0.5
545  j0 = npt / 2. - 0.5
546  rotdegree = 0.
547  pixscale = D/(npt / 2. - 0.5)
548  dspider = 0.51
Here is the call graph for this function:

◆ make_pupil()

def shesha.util.make_pupil.make_pupil (   dim,
  pupd,
  tel,
  xc = -1,
  yc = -1,
  real = 0,
  halfSpider = False 
)

Initialize the system pupil.

:parameters:

dim (long) : = p_geom.pupdiam

pupd (long) : linear size of total pupil = p_geom.pupdiam

tel (Param_tel) : Telescope structure

xc (int) = p_geom.pupdiam / 2. - 0.5

yc (int) = p_geom.pupdiam / 2. - 0.5

real (int)

TODO complete

Definition at line 68 of file make_pupil.py.

68  """
69 
70  if tel.type_ap == ApertureType.EELT_NOMINAL:
71  N_seg = 798
72  return make_EELT(dim, pupd, tel, N_seg)
73  elif (tel.type_ap == ApertureType.EELT):
74  return generateEeltPupilMask(dim, tel.t_spiders, xc, yc, tel.diam / dim, tel.gap,
75  tel.pupangle, D=tel.diam, halfSpider=halfSpider,
76  pitch=1.244683637214, nseg=33, inner_rad=4.1,
77  outer_rad=15.4, R=95.7853, nominalD=40,
78  half_seg=0.75, refl=tel.referr)
79  elif (tel.type_ap == ApertureType.KECK):
80  seg_corner = 1.8
81  kpitch = seg_corner / 2 * np.sqrt(3)
82  knseg = 7
83  kinner_rad = 0.9
84  kouter_rad = 3.4
85  kR = 85
86  knominalD = 10.96
87  khalf_seg = 0.9
88  return generateEeltPupilMask(
89  dim, tel.t_spiders, xc, yc, tel.diam / dim, tel.gap, tel.pupangle,
90  D=tel.diam, cobs=tel.cobs, halfSpider=halfSpider, pitch=kpitch,
91  nseg=knseg, inner_rad=0.9, outer_rad=3.4, R=kR, nominalD=knominalD,
92  half_seg=0.9, refl=tel.referr, rotSpiderDegree=-30)
93  elif tel.type_ap == ApertureType.EELT_BP1:
94  print("ELT_pup_cobs = %5.3f" % 0.339)
95  N_seg = 768
96  return make_EELT(dim, pupd, tel, N_seg)
97  elif tel.type_ap == ApertureType.EELT_BP3:
98  print("ELT_pup_cobs = %5.3f" % 0.503)
99  N_seg = 672
100  return make_EELT(dim, pupd, tel, N_seg)
101  elif tel.type_ap == ApertureType.EELT_BP5:
102  print("ELT_pup_cobs = %5.3f" % 0.632)
103  N_seg = 558
104  return make_EELT(dim, pupd, tel, N_seg)
105  elif tel.type_ap == ApertureType.EELT_CUSTOM:
106  print("EELT_CUSTOM not implemented. Falling back to EELT-Nominal")
107  tel.set_type_ap(ApertureType.EELT_NOMINAL)
108  return make_EELT(dim, pupd, tel, N_seg)
109  elif tel.type_ap == ApertureType.VLT:
110  tel.set_cobs(0.14)
111  print("force_VLT_pup_cobs = %5.3f" % 0.14)
112  return make_VLT(dim, pupd, tel)
113  elif tel.type_ap == ApertureType.GENERIC:
114  return make_pupil_generic(dim, pupd, tel.t_spiders, tel.spiders_type, xc, yc,
115  real, tel.cobs)
116  else:
117  raise NotImplementedError("Missing Pupil type.")
118 
119 
Here is the call graph for this function:

◆ make_pupil_generic()

def shesha.util.make_pupil.make_pupil_generic (   dim,
  pupd,
  t_spiders = 0.01,
  spiders_type = SpiderType.SIX,
  xc = 0,
  yc = 0,
  real = 0,
  cobs = 0 
)

Initialize the system pupil.

:parameters:

dim (long) : linear size of ???

pupd (long) : linear size of total pupil

t_spiders (float) : secondary supports ratio.

spiders_type (str) : secondary supports type: "four" or "six".

xc (int)

yc (int)

real (int)

cobs (float) : central obstruction ratio.

TODO complete

Definition at line 143 of file make_pupil.py.

143  TODO: complete
144  """
145 
146  pup = util.dist(dim, xc, yc)
147 
148  if (real == 1):
149  pup = np.exp(-(pup / (pupd * 0.5))**60.0)**0.69314
150  else:
151  pup = (pup < (pupd + 1.) / 2).astype(np.float32)
152 
153  if (cobs > 0):
154  if (real == 1):
155  pup -= np.exp(-(util.dist(dim, xc, yc) / (pupd * cobs * 0.5))**60.)**0.69314
156  else:
157  pup -= (util.dist(dim, xc, yc) < (pupd * cobs + 1.) * 0.5).astype(np.float32)
158 
159  step = 1. / dim
160  first = 0.5 * (step - 1)
161 
162  X = np.tile(np.arange(dim, dtype=np.float32) * step + first, (dim, 1))
163 
164  if (t_spiders < 0):
165  t_spiders = 0.01
166  t_spiders = t_spiders * pupd / dim
167 
168  if (spiders_type == "four"):
169 
170  s4_2 = 2 * np.sin(np.pi / 4)
171  t4 = np.tan(np.pi / 4)
172 
173  spiders_map = ((X.T > (X + t_spiders / s4_2) * t4) +
174  (X.T < (X - t_spiders / s4_2) * t4)).astype(np.float32)
175  spiders_map *= ((X.T > (-X + t_spiders / s4_2) * t4) +
176  (X.T < (-X - t_spiders / s4_2) * t4)).astype(np.float32)
177 
178  pup = pup * spiders_map
179 
180  elif (spiders_type == "six"):
181 
182  #angle = np.pi/(180/15.)
183  angle = 0
184  s2ma_2 = 2 * np.sin(np.pi / 2 - angle)
185  s6pa_2 = 2 * np.sin(np.pi / 6 + angle)
186  s6ma_2 = 2 * np.sin(np.pi / 6 - angle)
187  t2ma = np.tan(np.pi / 2 - angle)
188  t6pa = np.tan(np.pi / 6 + angle)
189  t6ma = np.tan(np.pi / 6 - angle)
190 
191  spiders_map = ((X.T > (-X + t_spiders / s2ma_2) * t2ma) +
192  (X.T < (-X - t_spiders / s2ma_2) * t2ma))
193  spiders_map *= ((X.T > (X + t_spiders / s6pa_2) * t6pa) +
194  (X.T < (X - t_spiders / s6pa_2) * t6pa))
195  spiders_map *= ((X.T > (-X + t_spiders / s6ma_2) * t6ma) +
196  (X.T < (-X - t_spiders / s6ma_2) * t6ma))
197  pup = pup * spiders_map
198 
199  print("Generic pupil created")
200  return pup
201 
202 
Here is the caller graph for this function:

◆ make_VLT()

def shesha.util.make_pupil.make_VLT (   dim,
  pupd,
  tel 
)

Initialize the VLT pupil.

:parameters:

dim (long) : linear size of ???

pupd (long) : linear size of total pupil

tel (Param_tel) : Telescope structure

Definition at line 214 of file make_pupil.py.

214  """
215 
216  if (tel.set_t_spiders == -1):
217  print("force t_spider =%5.3f" % (0.09 / 18.))
218  tel.set_t_spiders(0.09 / 18.)
219  angle = 50.5 * np.pi / 180. # --> 50.5 degre *2 d'angle entre les spiders
220 
221  Range = (0.5 * (1) - 0.25 / dim)
222  X = np.tile(np.linspace(-Range, Range, dim, dtype=np.float32), (dim, 1))
223 
224  R = np.sqrt(X**2 + (X.T)**2)
225 
226  pup = ((R < 0.5) & (R > (tel.cobs / 2))).astype(np.float32)
227 
228  if (tel.set_t_spiders == -1):
229  print('No spider')
230  else:
231  spiders_map = (
232  (X.T >
233  (X - tel.cobs / 2 + tel.t_spiders / np.sin(angle)) * np.tan(angle)) +
234  (X.T < (X - tel.cobs / 2) * np.tan(angle))) * (X > 0) * (X.T > 0)
235  spiders_map += np.fliplr(spiders_map)
236  spiders_map += np.flipud(spiders_map)
237  spiders_map = interp.rotate(spiders_map, tel.pupangle, order=0, reshape=False)
238 
239  pup = pup * spiders_map
240 
241  print("VLT pupil created")
242  return pup
243 
244 
Here is the caller graph for this function:

◆ reorganizeSegmentsOrderESO()

def shesha.util.make_pupil.reorganizeSegmentsOrderESO (   x,
  y 
)

Definition at line 959 of file make_pupil.py.

959  """
960  # pi/2, pi/6, 2.pi, ...
961  pi_3 = np.pi / 3
962  pi_6 = np.pi / 6
963  pix2 = 2 * np.pi
964  # calcul des angles
965  t = (np.arctan2(y, x) + pi_6 - 1e-3) % (pix2)
966  X = np.array([])
967  Y = np.array([])
968  A = 100.
969  for k in range(6):
970  sector = (t > k * pi_3) & (t < (k + 1) * pi_3)
971  u = k * pi_3
972  distance = (A * np.cos(u) - np.sin(u)) * x[sector] + (
973  np.cos(u) + A * np.sin(u)) * y[sector]
974  indsort = np.argsort(distance)
975  X = np.append(X, x[sector][indsort])
976  Y = np.append(Y, y[sector][indsort])
977  return X, Y
978 
979 
Here is the caller graph for this function:

Variable Documentation

◆ EELT_data

string shesha.util.make_pupil.EELT_data = os.environ.get('SHESHA_ROOT') + "/data/apertures/"

Definition at line 47 of file make_pupil.py.