AnisoCADO 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of AnisoCADO might be problematic. Click here for more details.
- anisocado/__init__.py +10 -1
- anisocado/_anisocado.py +41 -49
- anisocado/misc.py +34 -24
- anisocado/psf.py +65 -48
- anisocado/psf_utils.py +35 -58
- anisocado/pupil_utils.py +210 -159
- anisocado/tests/__init__.py +1 -0
- anisocado/tests/test_playing_around.py +62 -0
- anisocado/tests/test_psf_functions.py +100 -0
- anisocado/tests/test_scao_psf.py +89 -0
- anisocado-0.4.0.dist-info/METADATA +53 -0
- anisocado-0.4.0.dist-info/RECORD +14 -0
- {AnisoCADO-0.3.0.dist-info → anisocado-0.4.0.dist-info}/WHEEL +1 -2
- AnisoCADO-0.3.0.dist-info/METADATA +0 -52
- AnisoCADO-0.3.0.dist-info/RECORD +0 -12
- AnisoCADO-0.3.0.dist-info/top_level.txt +0 -1
- anisocado/version.py +0 -3
- {AnisoCADO-0.3.0.dist-info → anisocado-0.4.0.dist-info}/LICENSE +0 -0
anisocado/pupil_utils.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
# -*- coding: utf-8 -*-
|
|
3
2
|
"""
|
|
4
3
|
Created on Fri Jun 8 15:38:32 2018
|
|
@@ -7,18 +6,14 @@ Created on Fri Jun 8 15:38:32 2018
|
|
|
7
6
|
|
|
8
7
|
Original Title : make_ricoPupil.py
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# import matplotlib.pyplot as plt
|
|
14
|
-
# plt.ion()
|
|
9
|
+
=====================================================
|
|
10
|
+
CONVENTIONS : Ce fichier est ecrit en convention X, Y
|
|
11
|
+
=====================================================
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
1.0 Convention X, Y
|
|
14
|
+
-------------------
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Dans la convention d'axes (x,y), tous les tableaux representant des images
|
|
16
|
+
Dans la convention d'axes (x, y), tous les tableaux representant des images
|
|
22
17
|
s'adressent par
|
|
23
18
|
tab[ix, iy]
|
|
24
19
|
Les indices s'utilisent alors classiquement
|
|
@@ -30,18 +25,18 @@ où ind[0] porte X. On fera donc appel a
|
|
|
30
25
|
tab[ix, iy]
|
|
31
26
|
|
|
32
27
|
La fonction meshgrid fait chier, et doit s'appeler par
|
|
33
|
-
X,Y = meshgrid(x,y, indexing=
|
|
28
|
+
X, Y = meshgrid(x, y, indexing="ij")
|
|
34
29
|
pour creer des tableaux conformes a un appel en X[ix, iy].
|
|
35
30
|
|
|
36
31
|
Dans les tableaux qui stockent des coord en x,y on utilise
|
|
37
|
-
x = tab[:,0]
|
|
38
|
-
y = tab[:,1]
|
|
32
|
+
x = tab[:, 0]
|
|
33
|
+
y = tab[:, 1]
|
|
39
34
|
pour que l'utilisation de flatten() mette X en premier. Cette facon de proceder
|
|
40
35
|
est logique/compatible avec les indices.
|
|
41
36
|
|
|
42
37
|
Dans les fonctions on place x d'abord, y ensuite, dans les arguments comme
|
|
43
38
|
dans le retour de fonction
|
|
44
|
-
def toto(...,x,y
|
|
39
|
+
def toto(..., x, y, ...)
|
|
45
40
|
return x, y
|
|
46
41
|
et
|
|
47
42
|
x, y = toto(...)
|
|
@@ -49,24 +44,26 @@ et
|
|
|
49
44
|
Graphisme: Pour afficher un tel tableau et avoir une representation
|
|
50
45
|
'naturelle' avec x "a droite" et y "en haut" il faut par contre
|
|
51
46
|
utiliser une transposition et retournement d'axe
|
|
52
|
-
plt.imshow(tab.T, origin=
|
|
47
|
+
plt.imshow(tab.T, origin="lower")
|
|
53
48
|
et qui offre une utilisation classique de
|
|
54
49
|
plt.plot(x, y, ...)
|
|
55
50
|
qui placera un overlay d'un plot de façon coherente sur l'image affichee.
|
|
56
51
|
|
|
57
52
|
|
|
58
|
-
Une sortie FITS d'un tableau tab[x,y] va generer un fichier qui contient des
|
|
53
|
+
Une sortie FITS d'un tableau tab[x, y] va generer un fichier qui contient des
|
|
59
54
|
data avec un axe rapide NAXIS1 dirige selon Y. Attention car de nombreux
|
|
60
|
-
logiciels considerent axe rapide = axe x (par exemple ds9), ou representent
|
|
55
|
+
logiciels considerent axe rapide = axe x (par exemple ds9), ou representent
|
|
61
56
|
l'axe rapide souvent horizontal en natif (ds9, python, yorick, idl, ...)
|
|
62
57
|
Donc, pour les entrees/sorties on transposera les data
|
|
63
|
-
pf.writeto(
|
|
58
|
+
pf.writeto("monfichier.fits", tab.T)
|
|
64
59
|
et
|
|
65
|
-
tab = pf.getdata(
|
|
60
|
+
tab = pf.getdata("monfichier.fits").T
|
|
61
|
+
|
|
66
62
|
|
|
63
|
+
2.0 Convention Y, X
|
|
64
|
+
-------------------
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
Dans la convention d'axe (y,x), tous les tableaux d'images sont
|
|
66
|
+
Dans la convention d'axe (y, x), tous les tableaux d'images sont
|
|
70
67
|
adresses par
|
|
71
68
|
tab[iy, ix]
|
|
72
69
|
|
|
@@ -90,67 +87,68 @@ et a l'appel de la fonction et recup des coordonnees on garde
|
|
|
90
87
|
x, y = toto(args, ax, ay, ..)
|
|
91
88
|
|
|
92
89
|
La fonction meshgrid doit s'appeler par
|
|
93
|
-
X,Y = meshgrid(x,y)
|
|
90
|
+
X, Y = meshgrid(x, y)
|
|
94
91
|
pour creer des tableaux conformes a un appel en X[iy, ix].
|
|
95
92
|
|
|
96
|
-
Dans les tableaux qui stockent des coord en x,y on utilise
|
|
97
|
-
x = tab[:,0]
|
|
98
|
-
y = tab[:,1]
|
|
93
|
+
Dans les tableaux qui stockent des coord en x, y on utilise
|
|
94
|
+
x = tab[:, 0]
|
|
95
|
+
y = tab[:, 1]
|
|
99
96
|
pour que l'utilisation de flatten() mette X en premier. Cependant cette
|
|
100
97
|
notation est en conflit avec le traitement des indices (fonction where()) qui
|
|
101
98
|
placent Y d'abord.
|
|
102
99
|
|
|
103
100
|
Graphisme: Pour afficher un tel tableau et avoir une representation
|
|
104
|
-
|
|
101
|
+
"naturelle" avec x "a droite" et y "en haut" il faut juste utiliser le
|
|
105
102
|
retournement d'axe
|
|
106
|
-
plt.imshow(tab, origin=
|
|
103
|
+
plt.imshow(tab, origin="lower")
|
|
107
104
|
suivi d'une utilisation classique de
|
|
108
105
|
plt.plot(x, y, ...)
|
|
109
106
|
qui placera un overlay d'un plot de façon coherente sur l'image affichee.
|
|
110
107
|
|
|
111
108
|
|
|
112
|
-
Une sortie FITS d'un tableau tab[x,y] cree un fichier qui aura un axe
|
|
109
|
+
Une sortie FITS d'un tableau tab[x, y] cree un fichier qui aura un axe
|
|
113
110
|
rapide NAXIS1 selon X, coherent avec la plupart des logiciels (ds9, python,
|
|
114
111
|
yorick, idl, ...)
|
|
115
112
|
|
|
116
113
|
|
|
117
|
-
|
|
114
|
+
3.0 Meshgrid
|
|
115
|
+
------------
|
|
118
116
|
|
|
119
117
|
Quand on definit
|
|
120
118
|
x = ...
|
|
121
119
|
y = ...
|
|
122
|
-
et qu'on utilise np.meshgrid(), on a
|
|
120
|
+
et qu'on utilise np.meshgrid(), on a
|
|
123
121
|
|
|
124
|
-
code
|
|
125
|
-
X,Y = meshgrid(x,y)
|
|
126
|
-
X,Y = meshgrid(x,y,indexing=
|
|
127
|
-
Y,X = meshgrid(y,x)
|
|
128
|
-
Y,X = meshgrid(y,x,indexing=
|
|
129
|
-
X,Y = meshgrid(y,x)
|
|
122
|
+
code convention d'appel mat/imshow
|
|
123
|
+
X, Y = meshgrid(x, y) [y, x] X horizontal
|
|
124
|
+
X, Y = meshgrid(x, y, indexing="ij") [x, y] X vertical
|
|
125
|
+
Y, X = meshgrid(y, x) [x, y] X vertical
|
|
126
|
+
Y, X = meshgrid(y, x, indexing="ij") [y, x] X horizontal
|
|
127
|
+
X, Y = meshgrid(y, x) incoherent
|
|
130
128
|
|
|
131
|
-
meshgrid(x,y) equivaut a indexing=
|
|
132
|
-
Indexing
|
|
129
|
+
meshgrid(x, y) equivaut a indexing="xy" (default).
|
|
130
|
+
Indexing "ij" ou "xy" affecte la transposition des X,Y de sortie.
|
|
133
131
|
L'interversion x/y dans les parametres d'appel et de sortie affecte la
|
|
134
132
|
transposition des X/Y.
|
|
135
133
|
|
|
136
134
|
|
|
137
|
-
Donc
|
|
138
|
-
- soit on utilise meshgrid(x,y) sans option d'indexing, ce qui donne des
|
|
135
|
+
Donc
|
|
136
|
+
- soit on utilise meshgrid(x, y) sans option d'indexing, ce qui donne des
|
|
139
137
|
plot 2D plutot user-friendly sans pencher la tete et sans transposee, mais
|
|
140
138
|
la notation d'appel dans les tableaux doit etre [iy,ix]
|
|
141
|
-
- soit on utilise meshgrid(..,indexing=
|
|
142
|
-
option des plots a regarder avec la tete 90° a droite, et une notation [x,y]
|
|
139
|
+
- soit on utilise meshgrid(..,indexing="ij"), on aura avec imshow() sans
|
|
140
|
+
option des plots a regarder avec la tete 90° a droite, et une notation [x, y]
|
|
143
141
|
partout dans le code.
|
|
144
|
-
Pour avoir les plots python "dans le bon sens" avec une notation [x,y] il faut
|
|
145
|
-
plt.imshow(p.T,origin=
|
|
142
|
+
Pour avoir les plots python "dans le bon sens" avec une notation [x, y] il faut
|
|
143
|
+
plt.imshow(p.T, origin="lower").
|
|
146
144
|
|
|
147
145
|
|
|
148
146
|
L'utilisation
|
|
149
|
-
X,Y = meshgrid(y,x)
|
|
147
|
+
X, Y = meshgrid(y, x)
|
|
150
148
|
ou
|
|
151
|
-
Y,X = meshgrid(x,y)
|
|
152
|
-
n'a de sens que si x==y (par exemple x=y=np.linspace(-1,1,n) ...) et permet
|
|
153
|
-
le meme rendu que indexing=
|
|
149
|
+
Y, X = meshgrid(x, y)
|
|
150
|
+
n'a de sens que si x==y (par exemple x=y=np.linspace(-1, 1, n) ...) et permet
|
|
151
|
+
le meme rendu que indexing="ij". Mais c'est un joli hasard. Des que les
|
|
154
152
|
axes x et y se distinguent, soit par le nbre de points, soit par les
|
|
155
153
|
valeurs (soit le range, le step, l'offset, etc.) alors inverser x et y est
|
|
156
154
|
juste purement incoherent.
|
|
@@ -159,7 +157,19 @@ juste purement incoherent.
|
|
|
159
157
|
"""
|
|
160
158
|
|
|
161
159
|
|
|
162
|
-
|
|
160
|
+
import numpy as np
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def fillPolygon(
|
|
164
|
+
x: float,
|
|
165
|
+
y: float,
|
|
166
|
+
i0: float,
|
|
167
|
+
j0: float,
|
|
168
|
+
scale: float,
|
|
169
|
+
gap: float,
|
|
170
|
+
N: int,
|
|
171
|
+
index: int = 0,
|
|
172
|
+
) -> np.ndarray:
|
|
163
173
|
"""
|
|
164
174
|
From a list of points defined by their 2 coordinates list
|
|
165
175
|
x and y, creates a filled polygon with sides joining the points.
|
|
@@ -169,28 +179,43 @@ def fillPolygon(x, y, i0, j0, scale, gap, N, index=0):
|
|
|
169
179
|
Arrays x and y are supposed to be in unit U, and scale is the
|
|
170
180
|
pixel size in U units.
|
|
171
181
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
x, y : float
|
|
185
|
+
List of points defining the polygon.
|
|
186
|
+
i0, j0 : float
|
|
187
|
+
Indices of pixels where the pupil should be centred.
|
|
188
|
+
May be floating-point indices.
|
|
189
|
+
scale : float
|
|
190
|
+
Size of a pixel of the image, in same unit as x and y.
|
|
191
|
+
gap : float
|
|
192
|
+
Half-space between segments in meters.
|
|
193
|
+
N : int
|
|
194
|
+
Size of output image.
|
|
195
|
+
index : int, optional
|
|
196
|
+
DESCRIPTION. The default is 0.
|
|
197
|
+
|
|
198
|
+
Returns
|
|
199
|
+
-------
|
|
200
|
+
np.ndarray
|
|
201
|
+
Filled polygon (N, N), boolean.
|
|
202
|
+
|
|
203
|
+
Examples
|
|
204
|
+
--------
|
|
205
|
+
>>> x = np.array([1,-1,-1.5,0,1.1])
|
|
206
|
+
>>> y = np.array([1,1.5,-0.2,-2,0])
|
|
207
|
+
>>> N = 200
|
|
208
|
+
>>> i0 = N/2
|
|
209
|
+
>>> j0 = N/2
|
|
210
|
+
>>> gap = 0.
|
|
211
|
+
>>> scale = 0.03
|
|
212
|
+
>>> pol = fillPolygon(x, y, i0, j0, scale, gap, N, index=2)
|
|
188
213
|
|
|
189
214
|
"""
|
|
190
215
|
# define coordinates map centred on (i0,j0) with same units as x,y.
|
|
191
216
|
X = (np.arange(N) - i0) * scale
|
|
192
217
|
Y = (np.arange(N) - j0) * scale
|
|
193
|
-
X, Y = np.meshgrid(X, Y, indexing=
|
|
218
|
+
X, Y = np.meshgrid(X, Y, indexing="ij") # indexage [x,y]
|
|
194
219
|
|
|
195
220
|
# define centre of polygon x0, y0
|
|
196
221
|
x0 = np.mean(x)
|
|
@@ -273,7 +298,7 @@ def centrePourVidal(N, i0, j0, centerMark):
|
|
|
273
298
|
res = 0
|
|
274
299
|
X = (np.arange(N) - i0) * scale
|
|
275
300
|
Y = (np.arange(N) - j0) * scale
|
|
276
|
-
X, Y = np.meshgrid(X, Y, indexing=
|
|
301
|
+
X, Y = np.meshgrid(X, Y, indexing="ij") # convention d'appel [x,y]
|
|
277
302
|
if centerMark == 1:
|
|
278
303
|
res = (X ** 2 + Y ** 2) < 1
|
|
279
304
|
if centerMark == 2:
|
|
@@ -299,7 +324,7 @@ def fillSpider(N, nspider, dspider, i0, j0, scale, rot):
|
|
|
299
324
|
a = np.ones((N, N), dtype=np.bool_)
|
|
300
325
|
X = (np.arange(N) - i0) * scale
|
|
301
326
|
Y = (np.arange(N) - j0) * scale
|
|
302
|
-
X, Y = np.meshgrid(X, Y, indexing=
|
|
327
|
+
X, Y = np.meshgrid(X, Y, indexing="ij") # convention d'appel [x,y]
|
|
303
328
|
w = 2 * np.pi / nspider
|
|
304
329
|
# rot += np.pi/2 # parce que c'est comme ca !!
|
|
305
330
|
for i in range(nspider):
|
|
@@ -311,7 +336,7 @@ def fillSpider(N, nspider, dspider, i0, j0, scale, rot):
|
|
|
311
336
|
|
|
312
337
|
def generateEeltPupil_slow(npt, dspider, i0, j0, pixscale, rotdegree):
|
|
313
338
|
"""
|
|
314
|
-
Computes the binary
|
|
339
|
+
Computes the binary ELT pupil on a map of size (npt, npt).
|
|
315
340
|
This is the original function, that builds the pupil shape according to
|
|
316
341
|
hardcoded contours.
|
|
317
342
|
This function is now obsolete, because it's been replaced by the faster
|
|
@@ -324,7 +349,8 @@ def generateEeltPupil_slow(npt, dspider, i0, j0, pixscale, rotdegree):
|
|
|
324
349
|
:param float pixscale: size of a pixel of the image, in meters.
|
|
325
350
|
:param float rotdegree: rotation angle of the pupil, in degrees.
|
|
326
351
|
|
|
327
|
-
|
|
352
|
+
Examples
|
|
353
|
+
--------
|
|
328
354
|
>>> pup = generateEeltPupil_slow(800, 0.6, 400, 400, 0.1, 3.0)
|
|
329
355
|
|
|
330
356
|
"""
|
|
@@ -495,7 +521,7 @@ def createHexaPattern(pitch, supportSize):
|
|
|
495
521
|
x = pitch * (np.arange(2 * nx + 1) - nx)
|
|
496
522
|
ny = int(np.ceil((supportSize / 2.0) / pitch / V3) + 1)
|
|
497
523
|
y = (V3 * pitch) * (np.arange(2 * ny + 1) - ny)
|
|
498
|
-
x, y = np.meshgrid(x, y, indexing=
|
|
524
|
+
x, y = np.meshgrid(x, y, indexing="ij")
|
|
499
525
|
x = x.flatten()
|
|
500
526
|
y = y.flatten()
|
|
501
527
|
peak_axis = np.append(x, x + pitch / 2.) # axe dirige selon sommet
|
|
@@ -510,7 +536,7 @@ def generateCoordSegments(D, rot):
|
|
|
510
536
|
Result is a tuple of arrays(6, 798).
|
|
511
537
|
|
|
512
538
|
:param float D: D is the pupil diameter in meters, it must be set to 40.0 m
|
|
513
|
-
for the nominal
|
|
539
|
+
for the nominal ELT.
|
|
514
540
|
:param float rot: pupil rotation angle in radians
|
|
515
541
|
|
|
516
542
|
"""
|
|
@@ -526,7 +552,7 @@ def generateCoordSegments(D, rot):
|
|
|
526
552
|
# Elimination des segments non valides grace a 2 nombres parfaitement
|
|
527
553
|
# empiriques ajustes a-la-mano.
|
|
528
554
|
inner_rad, outer_rad = 4.1, 15.4 # nominal, 798 segments
|
|
529
|
-
nn = (ll > inner_rad * pitch) & (ll < outer_rad * pitch)
|
|
555
|
+
nn = (ll > inner_rad * pitch) & (ll < outer_rad * pitch)
|
|
530
556
|
lx = lx[nn]
|
|
531
557
|
ly = ly[nn]
|
|
532
558
|
lx, ly = reorganizeSegmentsOrderESO(lx, ly)
|
|
@@ -592,7 +618,7 @@ def reorganizeSegmentsOrderESO(x, y):
|
|
|
592
618
|
sector = (t > k * pi_3) & (t < (k + 1) * pi_3)
|
|
593
619
|
u = k * pi_3
|
|
594
620
|
distance = (A * np.cos(u) - np.sin(u)) * x[sector] + (
|
|
595
|
-
|
|
621
|
+
np.cos(u) + A * np.sin(u)) * y[sector]
|
|
596
622
|
indsort = np.argsort(distance)
|
|
597
623
|
X = np.append(X, x[sector][indsort])
|
|
598
624
|
Y = np.append(Y, y[sector][indsort])
|
|
@@ -642,7 +668,7 @@ def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D,
|
|
|
642
668
|
:param float scale: size of a pixel of the image, in meters.
|
|
643
669
|
:param float gap: half-space between segments in meters
|
|
644
670
|
:param int N: size of the output array (N,N)
|
|
645
|
-
:param float D: diameter of the pupil. For the nominal
|
|
671
|
+
:param float D: diameter of the pupil. For the nominal ELT, D shall
|
|
646
672
|
be set to 40.0
|
|
647
673
|
:param bool softGap: if False, the gap between segments is binary 0/1
|
|
648
674
|
depending if the pixel is within the gap or not. If True, the gap
|
|
@@ -688,8 +714,8 @@ def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D,
|
|
|
688
714
|
# the width of the impulse response, chosen 2-pixel wide to be
|
|
689
715
|
# well sampled.
|
|
690
716
|
# The "depth" is related to the gap width. The integral of a
|
|
691
|
-
# Lorentzian of 2 pix wide is PI. Integral of a gap of width
|
|
692
|
-
# in pixels is
|
|
717
|
+
# Lorentzian of 2 pix wide is PI. Integral of a gap of width "gap"
|
|
718
|
+
# in pixels is "gap".
|
|
693
719
|
# So the depth equals to gap/scale/np.pi.
|
|
694
720
|
for i in range(nseg):
|
|
695
721
|
indx, indy, distedge = fillPolygon(hx[:, i], hy[:, i],
|
|
@@ -697,8 +723,8 @@ def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D,
|
|
|
697
723
|
scale, gap * 0., segdiam,
|
|
698
724
|
index=1)
|
|
699
725
|
pupil[indx + ix0[i], indy + iy0[i]] = attribute[i] * (
|
|
700
|
-
|
|
701
|
-
|
|
726
|
+
1. - (gap / scale / np.pi) / (
|
|
727
|
+
1 + (distedge / scale) ** 2))
|
|
702
728
|
else:
|
|
703
729
|
# Hard gaps
|
|
704
730
|
for i in range(nseg):
|
|
@@ -710,7 +736,7 @@ def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D,
|
|
|
710
736
|
# attribute is [piston, tip, tilt]
|
|
711
737
|
minimap = np.zeros((segdiam, segdiam))
|
|
712
738
|
xmap = np.arange(segdiam) - segdiam / 2
|
|
713
|
-
xmap, ymap = np.meshgrid(xmap, xmap, indexing=
|
|
739
|
+
xmap, ymap = np.meshgrid(xmap, xmap, indexing="ij") # [x,y] convention
|
|
714
740
|
pitch = 1.244683637214 # diameter of inscribed circle
|
|
715
741
|
diamseg = pitch * 2 / np.sqrt(3) # diameter of circumscribed circle
|
|
716
742
|
diamfrizou = (pitch + diamseg) / 2 * D / 40. # average diameter
|
|
@@ -724,61 +750,82 @@ def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D,
|
|
|
724
750
|
j0 - iy0[i], scale, 0., segdiam,
|
|
725
751
|
index=1)
|
|
726
752
|
minimap = attribute[0, i] + (factunit * attribute[1, i]) * xmap + (
|
|
727
|
-
|
|
753
|
+
factunit * attribute[2, i]) * ymap
|
|
728
754
|
pupil[indx + ix0[i], indy + iy0[i]] = minimap[indx, indy]
|
|
729
755
|
|
|
730
756
|
return pupil
|
|
731
757
|
|
|
732
758
|
|
|
733
|
-
#
|
|
734
|
-
# | | | |_ _/ ___| | | | | | | ____\ \ / / ____| |
|
|
735
|
-
# | |_| || | | _| |_| |_____| | | _| \ \ / /| _| | |
|
|
736
|
-
# | _ || | |_| | _ |_____| |___| |___ \ V / | |___| |___
|
|
737
|
-
# |_| |_|___\____|_| |_| |_____|_____| \_/ |_____|_____|
|
|
738
|
-
|
|
759
|
+
# High-level functions (whatever that's supposed to mean here...)
|
|
739
760
|
|
|
740
761
|
def getEeltSegmentNumber():
|
|
741
762
|
"""
|
|
742
|
-
|
|
743
|
-
to be able to generate either reflectivities, or phase errors, or else.
|
|
763
|
+
Return the number of segments of the ELT nominal pupil.
|
|
744
764
|
|
|
765
|
+
In order to be able to generate either reflectivities, or phase errors,
|
|
766
|
+
or else.
|
|
745
767
|
"""
|
|
746
768
|
hx, hy = generateCoordSegments(40., 0.)
|
|
747
769
|
n = hx.shape[-1]
|
|
748
770
|
return n
|
|
749
771
|
|
|
750
772
|
|
|
751
|
-
def generateEeltPupilMask(
|
|
752
|
-
|
|
773
|
+
def generateEeltPupilMask(
|
|
774
|
+
npt: int,
|
|
775
|
+
dspider: float,
|
|
776
|
+
i0: float,
|
|
777
|
+
j0: float,
|
|
778
|
+
pixscale: float,
|
|
779
|
+
gap: float,
|
|
780
|
+
rotdegree: float,
|
|
781
|
+
D: float = 40.0,
|
|
782
|
+
centerMark: int = 0,
|
|
783
|
+
) -> np.ndarray:
|
|
753
784
|
"""
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
:
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
785
|
+
Generate a boolean pupil mask of the binary ELT pupil.
|
|
786
|
+
|
|
787
|
+
On a map of size (npt, npt).
|
|
788
|
+
|
|
789
|
+
Parameters
|
|
790
|
+
----------
|
|
791
|
+
npt : int
|
|
792
|
+
Size of the output array.
|
|
793
|
+
dspider : float
|
|
794
|
+
Width of spiders in meters.
|
|
795
|
+
i0, j0 : float
|
|
796
|
+
Indices of pixels where the pupil should be centred
|
|
797
|
+
Can be floating-point indicess.
|
|
798
|
+
pixscale : float
|
|
799
|
+
Size of a pixel of the image, in meters.
|
|
800
|
+
gap : float
|
|
801
|
+
Half-space between segments in meters.
|
|
802
|
+
rotdegree : float
|
|
803
|
+
Rotation angle of the pupil, in degrees.
|
|
804
|
+
D : float, optional
|
|
805
|
+
Diameter of the pupil in meter. The default is 40.0 (ELT).
|
|
806
|
+
centerMark : int, optional
|
|
807
|
+
when centerMark!=0, a pixel is added at the centre of
|
|
808
|
+
symmetry of the pupil in order to debug things using compass.
|
|
809
|
+
centerMark==1 draws a point
|
|
810
|
+
centerMark==2 draws 2 lines.
|
|
811
|
+
The default is 0.
|
|
812
|
+
|
|
813
|
+
Returns
|
|
814
|
+
-------
|
|
815
|
+
pup : np.ndarray
|
|
816
|
+
Pupil image (npt, npt), boolean.
|
|
817
|
+
|
|
818
|
+
Examples
|
|
819
|
+
--------
|
|
820
|
+
>>> npt = 752
|
|
821
|
+
>>> i0 = npt/2+0.5
|
|
822
|
+
>>> j0 = npt/2+0.5
|
|
823
|
+
>>> rotdegree = 90.0
|
|
824
|
+
>>> pixscale = 40./npt
|
|
825
|
+
>>> dspider = 0.53
|
|
826
|
+
>>> gap = 0.02
|
|
827
|
+
>>> pup = generateEeltPupilMask(
|
|
828
|
+
... npt, dspider, i0, j0, pixscale, gap, rotdegree)
|
|
782
829
|
|
|
783
830
|
"""
|
|
784
831
|
rot = rotdegree * np.pi / 180
|
|
@@ -790,10 +837,11 @@ def generateEeltPupilMask(npt, dspider, i0, j0, pixscale, gap, rotdegree,
|
|
|
790
837
|
|
|
791
838
|
# From the data of hex mirrors, we build the pupil image using
|
|
792
839
|
# boolean
|
|
793
|
-
pup = generateSegmentProperties(
|
|
840
|
+
pup = generateSegmentProperties(
|
|
841
|
+
True, hx, hy, i0, j0, pixscale, gap, npt, D)
|
|
794
842
|
|
|
795
|
-
# SPIDERS
|
|
796
|
-
nspider = 3 # for the day where we have more/less spiders
|
|
843
|
+
# SPIDERS
|
|
844
|
+
nspider = 3 # for the day where we have more/less spiders
|
|
797
845
|
if (dspider > 0 and nspider > 0):
|
|
798
846
|
pup = pup & fillSpider(npt, nspider, dspider, i0, j0, pixscale, rot)
|
|
799
847
|
|
|
@@ -808,7 +856,7 @@ def generateEeltPupilMask(npt, dspider, i0, j0, pixscale, gap, rotdegree,
|
|
|
808
856
|
def generateEeltPupilReflectivity(refl, npt, dspider, i0, j0, pixscale, gap,
|
|
809
857
|
rotdegree, D=40.0, softGap=False):
|
|
810
858
|
"""
|
|
811
|
-
Generates a map of the reflectivity of the
|
|
859
|
+
Generates a map of the reflectivity of the ELT pupil, on an array
|
|
812
860
|
of size (npt, npt).
|
|
813
861
|
|
|
814
862
|
:returns: pupil image (npt, npt), with the same type of input argument refl
|
|
@@ -825,7 +873,7 @@ def generateEeltPupilReflectivity(refl, npt, dspider, i0, j0, pixscale, gap,
|
|
|
825
873
|
:param float pixscale: size of a pixel of the image, in meters.
|
|
826
874
|
:param float gap: half-space between segments in meters
|
|
827
875
|
:param float rotdegree: rotation angle of the pupil, in degrees.
|
|
828
|
-
:param float D: diameter of the pupil. For the nominal
|
|
876
|
+
:param float D: diameter of the pupil. For the nominal ELT, D shall
|
|
829
877
|
be set to 40.0
|
|
830
878
|
:param bool softGap: if False, the gap between segments is binary 0/1
|
|
831
879
|
depending if the pixel is within the gap or not. If True, the gap
|
|
@@ -833,20 +881,21 @@ def generateEeltPupilReflectivity(refl, npt, dspider, i0, j0, pixscale, gap,
|
|
|
833
881
|
gap width.
|
|
834
882
|
|
|
835
883
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
refl = np.ones(798)+np.random.randn(798)/20.
|
|
839
|
-
dead = 3
|
|
840
|
-
refl[(np.random.rand(dead)*797).astype(int)] = 0.
|
|
841
|
-
npt = 1200
|
|
842
|
-
i0 = npt/2+0.5
|
|
843
|
-
j0 = npt/2+0.5
|
|
844
|
-
rotdegree = 14.0
|
|
845
|
-
pixscale = 44./npt
|
|
846
|
-
dspider = 0.53
|
|
847
|
-
gap = 0.02
|
|
848
|
-
pup = generateEeltPupilReflectivity(
|
|
849
|
-
|
|
884
|
+
Examples
|
|
885
|
+
--------
|
|
886
|
+
>>> refl = np.ones(798)+np.random.randn(798)/20.
|
|
887
|
+
>>> dead = 3
|
|
888
|
+
>>> refl[(np.random.rand(dead)*797).astype(int)] = 0.
|
|
889
|
+
>>> npt = 1200
|
|
890
|
+
>>> i0 = npt/2+0.5
|
|
891
|
+
>>> j0 = npt/2+0.5
|
|
892
|
+
>>> rotdegree = 14.0
|
|
893
|
+
>>> pixscale = 44./npt
|
|
894
|
+
>>> dspider = 0.53
|
|
895
|
+
>>> gap = 0.02
|
|
896
|
+
>>> pup = generateEeltPupilReflectivity(
|
|
897
|
+
... refl, npt, dspider, i0, j0,
|
|
898
|
+
... pixscale, gap, rotdegree, softGap=True)
|
|
850
899
|
|
|
851
900
|
"""
|
|
852
901
|
rot = rotdegree * np.pi / 180
|
|
@@ -858,8 +907,8 @@ def generateEeltPupilReflectivity(refl, npt, dspider, i0, j0, pixscale, gap,
|
|
|
858
907
|
|
|
859
908
|
# From the data of hex mirrors, we build the pupil image according
|
|
860
909
|
# to the properties defined by input argument <refl>
|
|
861
|
-
pup = generateSegmentProperties(
|
|
862
|
-
|
|
910
|
+
pup = generateSegmentProperties(
|
|
911
|
+
refl, hx, hy, i0, j0, pixscale, gap, npt, D, softGap=softGap)
|
|
863
912
|
|
|
864
913
|
# SPIDERS ............................................
|
|
865
914
|
nspider = 3 # for the day where we have more/less spiders ;-)
|
|
@@ -872,7 +921,7 @@ def generateEeltPupilReflectivity(refl, npt, dspider, i0, j0, pixscale, gap,
|
|
|
872
921
|
def generateEeltPupilPhase(phase, npt, dspider, i0, j0, pixscale, rotdegree,
|
|
873
922
|
D=40.0):
|
|
874
923
|
"""
|
|
875
|
-
Generates a map of the segments phase errors of the
|
|
924
|
+
Generates a map of the segments phase errors of the ELT pupil, on an array
|
|
876
925
|
of size (npt, npt).
|
|
877
926
|
|
|
878
927
|
:returns: phase image (npt, npt), with the same type of input argument phase
|
|
@@ -885,21 +934,21 @@ def generateEeltPupilPhase(phase, npt, dspider, i0, j0, pixscale, rotdegree,
|
|
|
885
934
|
Can be floating-point indexes.
|
|
886
935
|
:param float pixscale: size of a pixel of the image, in meters.
|
|
887
936
|
:param float rotdegree: rotation angle of the pupil, in degrees.
|
|
888
|
-
:param float D: diameter of the pupil. For the nominal
|
|
937
|
+
:param float D: diameter of the pupil. For the nominal ELT, D shall
|
|
889
938
|
be set to 40.0
|
|
890
939
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
phase = np.random.randn(3,798)
|
|
894
|
-
phase = np.zeros((3,798)); phase[1,:]=1.
|
|
895
|
-
npt = 752
|
|
896
|
-
i0 = npt/2+0.5
|
|
897
|
-
j0 = npt/2+0.5
|
|
898
|
-
rotdegree = 90.0
|
|
899
|
-
pixscale = 41./npt
|
|
900
|
-
dspider = 0.51
|
|
901
|
-
pup = generateEeltPupilPhase(
|
|
902
|
-
|
|
940
|
+
Examples
|
|
941
|
+
--------
|
|
942
|
+
>>> phase = np.random.randn(3,798)
|
|
943
|
+
>>> phase = np.zeros((3,798)); phase[1,:]=1.
|
|
944
|
+
>>> npt = 752
|
|
945
|
+
>>> i0 = npt/2+0.5
|
|
946
|
+
>>> j0 = npt/2+0.5
|
|
947
|
+
>>> rotdegree = 90.0
|
|
948
|
+
>>> pixscale = 41./npt
|
|
949
|
+
>>> dspider = 0.51
|
|
950
|
+
>>> pup = generateEeltPupilPhase(
|
|
951
|
+
... phase, npt, dspider, i0, j0, pixscale, rotdegree)
|
|
903
952
|
|
|
904
953
|
"""
|
|
905
954
|
rot = rotdegree * np.pi / 180
|
|
@@ -911,12 +960,14 @@ def generateEeltPupilPhase(phase, npt, dspider, i0, j0, pixscale, rotdegree,
|
|
|
911
960
|
|
|
912
961
|
# From the data of hex mirrors, we build the pupil phase image according
|
|
913
962
|
# to the properties defined by input argument <phase>
|
|
914
|
-
pup = generateSegmentProperties(
|
|
915
|
-
|
|
963
|
+
pup = generateSegmentProperties(
|
|
964
|
+
phase, hx, hy, i0, j0, pixscale, 0.0, npt, D)
|
|
916
965
|
|
|
917
966
|
return pup
|
|
918
967
|
|
|
919
968
|
|
|
969
|
+
# TODO: What's this? Module-level example? Test case? Anyway, figure out where
|
|
970
|
+
# it belongs an put it there!
|
|
920
971
|
"""
|
|
921
972
|
refl = np.ones(798)+np.random.randn(798)/10.
|
|
922
973
|
N = npt = 800
|
|
@@ -933,12 +984,12 @@ p = generateEeltPupilMask(N, dspider, i0, j0+10, scale, rotdegree)
|
|
|
933
984
|
plt.clf()
|
|
934
985
|
plt.matshow(p, fignum=1)
|
|
935
986
|
|
|
936
|
-
#p = generateEeltPupilReflectivity(refl, N, dspider, i0, j0, pixscale,
|
|
987
|
+
#p = generateEeltPupilReflectivity(refl, N, dspider, i0, j0, pixscale,
|
|
937
988
|
rotdegree, D=40.0)
|
|
938
989
|
|
|
939
990
|
phase = np.zeros((3,798)); phase[1,:]=1.
|
|
940
991
|
phase = np.random.randn(3,798)
|
|
941
|
-
p = generateEeltPupilPhase(phase, N, dspider, i0, j0, pixscale, rotdegree,
|
|
992
|
+
p = generateEeltPupilPhase(phase, N, dspider, i0, j0, pixscale, rotdegree,
|
|
942
993
|
D=40.0)
|
|
943
994
|
|
|
944
995
|
plt.matshow(p, fignum=1)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|