40 import scipy.ndimage.interpolation
as interp
42 from .
import hdf5_util
as h5u
43 from .
import utilities
as util
47 EELT_data = os.environ.get(
'SHESHA_ROOT') +
"/data/apertures/"
50 def make_pupil(dim, pupd, tel, xc=-1, yc=-1, real=0, halfSpider=False):
51 """Initialize the system pupil
55 dim: (long) : = p_geom.pupdiam
57 pupd: (long) : linear size of total pupil = p_geom.pupdiam
59 tel: (Param_tel) : Telescope structure
61 xc: (int) = p_geom.pupdiam / 2. - 0.5
63 yc: (int) = p_geom.pupdiam / 2. - 0.5
70 if tel.type_ap == ApertureType.EELT_NOMINAL:
73 elif (tel.type_ap == ApertureType.EELT):
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, nmissing=tel.nbrmissing)
79 elif (tel.type_ap == ApertureType.KECK):
81 kpitch = seg_corner / 2 * np.sqrt(3)
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)
97 elif tel.type_ap == ApertureType.EELT_BP3:
98 print(
"ELT_pup_cobs = %5.3f" % 0.503)
101 elif tel.type_ap == ApertureType.EELT_BP5:
102 print(
"ELT_pup_cobs = %5.3f" % 0.632)
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)
109 elif tel.type_ap == ApertureType.VLT:
111 print(
"force_VLT_pup_cobs = %5.3f" % 0.14)
113 elif tel.type_ap == ApertureType.VLT_NOOBS:
115 print(
"Remove central obstruction to the VLT")
117 elif tel.type_ap == ApertureType.GENERIC:
121 raise NotImplementedError(
"Missing Pupil type.")
125 yc=0, real=0, cobs=0):
127 Initialize the system pupil
131 dim: (long) : linear size of ???
133 pupd: (long) : linear size of total pupil
135 t_spiders: (float) : secondary supports ratio.
137 spiders_type: (str) : secondary supports type: "four" or "six".
145 cobs: (float) : central obstruction ratio.
150 pup = util.dist(dim, xc, yc)
153 pup = np.exp(-(pup / (pupd * 0.5))**60.0)**0.69314
155 pup = (pup < (pupd + 1.) / 2).astype(np.float32)
159 pup -= np.exp(-(util.dist(dim, xc, yc) / (pupd * cobs * 0.5))**60.)**0.69314
161 pup -= (util.dist(dim, xc, yc) < (pupd * cobs + 1.) * 0.5).astype(np.float32)
164 first = 0.5 * (step - 1)
166 X = np.tile(np.arange(dim, dtype=np.float32) * step + first, (dim, 1))
170 t_spiders = t_spiders * pupd / dim
172 if (spiders_type ==
"four"):
174 s4_2 = 2 * np.sin(np.pi / 4)
175 t4 = np.tan(np.pi / 4)
177 spiders_map = ((X.T > (X + t_spiders / s4_2) * t4) +
178 (X.T < (X - t_spiders / s4_2) * t4)).astype(np.float32)
179 spiders_map *= ((X.T > (-X + t_spiders / s4_2) * t4) +
180 (X.T < (-X - t_spiders / s4_2) * t4)).astype(np.float32)
182 pup = pup * spiders_map
184 elif (spiders_type ==
"six"):
188 s2ma_2 = 2 * np.sin(np.pi / 2 - angle)
189 s6pa_2 = 2 * np.sin(np.pi / 6 + angle)
190 s6ma_2 = 2 * np.sin(np.pi / 6 - angle)
191 t2ma = np.tan(np.pi / 2 - angle)
192 t6pa = np.tan(np.pi / 6 + angle)
193 t6ma = np.tan(np.pi / 6 - angle)
195 spiders_map = ((X.T > (-X + t_spiders / s2ma_2) * t2ma) +
196 (X.T < (-X - t_spiders / s2ma_2) * t2ma))
197 spiders_map *= ((X.T > (X + t_spiders / s6pa_2) * t6pa) +
198 (X.T < (X - t_spiders / s6pa_2) * t6pa))
199 spiders_map *= ((X.T > (-X + t_spiders / s6ma_2) * t6ma) +
200 (X.T < (-X - t_spiders / s6ma_2) * t6ma))
201 pup = pup * spiders_map
203 print(
"Generic pupil created")
209 Initialize the VLT pupil
213 dim: (long) : linear size of ???
215 pupd: (long) : linear size of total pupil
217 tel: (Param_tel) : Telescope structure
220 if (tel.t_spiders == -1):
221 print(
"force t_spider =%5.3f" % (0.09 / 18.))
222 tel.set_t_spiders(0.09 / 18.)
223 angle = 50.5 * np.pi / 180.
225 Range = (0.5 * (1) - 0.25 / dim)
226 X = np.tile(np.linspace(-Range, Range, dim, dtype=np.float32), (dim, 1))
228 R = np.sqrt(X**2 + (X.T)**2)
230 pup = ((R < 0.5) & (R > (tel.cobs / 2))).astype(np.float32)
232 if (tel.t_spiders == -1):
237 (X - tel.cobs / 2 + tel.t_spiders / np.sin(angle)) * np.tan(angle)) +
238 (X.T < (X - tel.cobs / 2) * np.tan(angle))) * (X > 0) * (X.T > 0)
239 spiders_map += np.fliplr(spiders_map)
240 spiders_map += np.flipud(spiders_map)
241 spiders_map = interp.rotate(spiders_map, tel.pupangle, order=0, reshape=
False)
243 pup = pup * spiders_map
245 print(
"VLT pupil created")
251 Initialize the EELT pupil
255 dim: (long) : linear size of ???
257 pupd: (long) : linear size of total pupil
259 tel: (Param_tel) : Telescope structure
264 TODO : add force rescal pup elt
267 EELT_file = EELT_data +
"EELT-Custom_N" + str(dim) +
"_COBS" + str(
268 100 * tel.cobs) +
"_CLOCKED" + str(tel.pupangle) +
"_TSPIDERS" + str(
269 100 * tel.t_spiders) +
"_MS" + str(
270 tel.nbrmissing) +
"_REFERR" + str(
271 100 * tel.referr) +
".h5"
273 EELT_file = EELT_data + tel.type_ap.decode(
'UTF-8') +
"_N" + str(
274 dim) +
"_COBS" + str(100 * tel.cobs) +
"_CLOCKED" + str(
275 tel.pupangle) +
"_TSPIDERS" + str(
276 100 * tel.t_spiders) +
"_MS" + str(
277 tel.nbrmissing) +
"_REFERR" + str(
278 100 * tel.referr) +
".h5"
279 if (os.path.isfile(EELT_file)):
280 print(
"reading EELT pupil from file ", EELT_file)
281 pup = h5u.readHdf5SingleDataset(EELT_file)
283 print(
"creating EELT pupil...")
284 file = EELT_data +
"Coord_" + tel.type_ap.decode(
'UTF-8') +
".dat"
285 data = np.fromfile(file, sep=
"\n")
286 data = np.reshape(data, (data.size // 2, 2))
290 file = EELT_data +
"EELT_MISSING_" + tel.type_ap.decode(
'UTF-8') +
".dat"
291 k_seg = np.fromfile(file, sep=
"\n").astype(np.int32)
293 W = 1.45 * np.cos(np.pi / 6)
297 Range = (0.5 * (tel.diam * dim / pupd) - 0.25 / dim)
298 X = np.tile(np.linspace(-Range, Range, dim, dtype=np.float32), (dim, 1))
300 if (tel.t_spiders == -1):
301 print(
"force t_spider =%5.3f" % (0.014))
302 tel.set_t_spiders(0.014)
306 if (tel.nbrmissing > 0):
307 k_seg = np.sort(k_seg[:tel.nbrmissing])
309 file = EELT_data +
"EELT_REF_ERROR" +
".dat"
310 ref_err = np.fromfile(file, sep=
"\n")
315 std_ref = np.std(ref_err)
317 ref_err = ref_err * tel.referr / std_ref
319 if (tel.nbrmissing > 0):
322 pup = np.zeros((dim, dim))
324 t_3 = np.tan(np.pi / 3.)
327 vect_seg = tel.vect_seg
331 pup+=(1-ref_err[i])*(Yt<0.5*W)*(Yt>=-0.5*W)*(0.5*(Yt+t_3*Xt)<0.5*W) \
332 *(0.5*(Yt+t_3*Xt)>=-0.5*W)*(0.5*(Yt-t_3*Xt)<0.5*W) \
333 *(0.5*(Yt-t_3*Xt)>=-0.5*W)
336 for i
in range(N_seg):
339 pup+=(1-ref_err[i])*(Yt<0.5*W)*(Yt>=-0.5*W)*(0.5*(Yt+t_3*Xt)<0.5*W) \
340 *(0.5*(Yt+t_3*Xt)>=-0.5*W)*(0.5*(Yt-t_3*Xt)<0.5*W) \
341 *(0.5*(Yt-t_3*Xt)>=-0.5*W)
342 if (tel.t_spiders == 0):
345 t_spiders = tel.t_spiders * (tel.diam * dim / pupd)
347 s2_6 = 2 * np.sin(np.pi / 6)
348 t_6 = np.tan(np.pi / 6)
350 spiders_map = np.abs(X) > t_spiders / 2
353 (X + t_spiders / s2_6) * t_6) + (X.T <
354 (X - t_spiders / s2_6) * t_6))
357 (-X + t_spiders / s2_6) * t_6) + (X.T <
358 (-X - t_spiders / s2_6) * t_6))
360 pup = pup * spiders_map
362 if (tel.pupangle != 0):
363 pup = interp.rotate(pup, tel.pupangle, reshape=
False, order=0)
365 print(
"writing EELT pupil to file ", EELT_file)
366 h5u.writeHdf5SingleDataset(EELT_file, pup)
368 print(
"EELT pupil created")
372 def make_phase_ab(dim, pupd, tel, pup=None, xc=-1, yc=-1, real=0, halfSpider=False):
373 """Compute the EELT M1 phase aberration
377 dim: (long) : linear size of ???
379 pupd: (long) : linear size of total pupil
381 tel: (Param_tel) : Telescope structure
388 if ((tel.type_ap == ApertureType.GENERIC)
or (tel.type_ap == ApertureType.VLT)):
389 return np.zeros((dim, dim)).astype(np.float32)
391 elif tel.type_ap == ApertureType.EELT:
394 dim, 0, xc, yc, tel.diam / dim, tel.gap, tel.pupangle, D=tel.diam,
395 halfSpider=halfSpider, pitch=1.244683637214, nseg=33, inner_rad=4.1,
396 outer_rad=15.4, R=95.7853, nominalD=40, half_seg=0.75,
397 refl=[tel.std_piston, tel.std_tt, tel.std_tt])
398 elif (tel.type_ap == ApertureType.KECK):
400 kpitch = seg_corner / 2 * np.sqrt(3)
408 dim, 0, xc, yc, tel.diam / dim, tel.gap, tel.pupangle, D=tel.diam,
409 cobs=tel.cobs, halfSpider=halfSpider, pitch=kpitch, nseg=knseg,
410 inner_rad=0.9, outer_rad=3.4, R=kR, nominalD=knominalD, half_seg=0.9,
411 refl=[tel.std_piston, tel.std_tt, tel.std_tt])
413 ab_file = EELT_data +
"aberration_" + tel.type_ap.decode(
'UTF-8') + \
414 "_N" + str(dim) +
"_NPUP" + str(np.where(pup)[0].size) +
"_CLOCKED" + str(
415 tel.pupangle) +
"_TSPIDERS" + str(
416 100 * tel.t_spiders) +
"_MS" + str(tel.nbrmissing) +
"_REFERR" + str(
417 100 * tel.referr) +
"_PIS" + str(
418 tel.std_piston) +
"_TT" + str(tel.std_tt) +
".h5"
419 if (os.path.isfile(ab_file)):
420 print(
"reading aberration phase from file ", ab_file)
421 phase_error = h5u.readHdf5SingleDataset(ab_file)
423 print(
"computing M1 phase aberration...")
425 std_piston = tel.std_piston
428 W = 1.45 * np.cos(np.pi / 6)
430 file = EELT_data +
"EELT_Piston_" + tel.type_ap.decode(
'UTF-8') +
".dat"
431 p_seg = np.fromfile(file, sep=
"\n")
433 std_pis = np.std(p_seg)
434 p_seg = p_seg * std_piston / std_pis
437 file = EELT_data +
"EELT_TT_" + tel.type_ap.decode(
'UTF-8') +
".dat"
438 tt_seg = np.fromfile(file, sep=
"\n")
440 file = EELT_data +
"EELT_TT_DIRECTION_" + tel.type_ap.decode(
'UTF-8') +
".dat"
441 tt_phi_seg = np.fromfile(file, sep=
"\n")
443 phase_error = np.zeros((dim, dim))
444 phase_tt = np.zeros((dim, dim))
445 phase_defoc = np.zeros((dim, dim))
447 file = EELT_data +
"Coord_" + tel.type_ap.decode(
'UTF-8') +
".dat"
448 data = np.fromfile(file, sep=
"\n")
449 data = np.reshape(data, (data.size // 2, 2))
453 Range = (0.5 * (tel.diam * dim / pupd) - 0.25 / dim)
455 X = np.tile(np.linspace(-Range, Range, dim, dtype=np.float32), (dim, 1))
456 t_3 = np.tan(np.pi / 3.)
458 for i
in range(N_seg):
461 SEG=(Yt<0.5*W)*(Yt>=-0.5*W)*(0.5*(Yt+t_3*Xt)<0.5*W) \
462 *(0.5*(Yt+t_3*Xt)>=-0.5*W)*(0.5*(Yt-t_3*Xt)<0.5*W) \
463 *(0.5*(Yt-t_3*Xt)>=-0.5*W)
466 N_in_seg = np.sum(SEG)
467 Hex_diam = 2 * np.max(
468 np.sqrt(Xt[np.where(SEG)]**2 + Yt[np.where(SEG)]**2))
472 np.cos(tt_phi_seg[i]) * Xt + np.sin(tt_phi_seg[i]) * Yt)
473 mean_tt = np.sum(TT[np.where(SEG == 1)]) / N_in_seg
474 phase_tt += SEG * (TT - mean_tt)
478 phase_error += SEG * p_seg[i]
480 N_EELT = np.where(pup)[0].size
481 if (np.sum(phase_tt) != 0):
482 phase_tt *= std_tt / np.sqrt(
483 1. / N_EELT * np.sum(phase_tt[np.where(pup)]**2))
487 phase_error += phase_tt + phase_defoc
489 if (tel.pupangle != 0):
490 phase_error = interp.rotate(phase_error, tel.pupangle, reshape=
False,
493 print(
"phase aberration created")
494 print(
"writing aberration filel to file ", ab_file)
495 h5u.writeHdf5SingleDataset(ab_file, phase_error)
501 ooooooooooo ooooo ooooooooooo oooooooooo ooooo oooooooo8 ooooooo
502 888 88 888 88 888 88 888 888 888 o888 88 o888 888o
503 888ooo8 888 888 888oooo88 888 888 888 888
504 888 oo 888 o 888 888 88o 888 888o oo 888o o888
505 o888ooo8888 o888ooooo88 o888o o888o 88o8 o888o 888oooo88 88ooo88
510 centerMark=0, halfSpider=False, pitch=1.244683637214, nseg=33,
511 inner_rad=4.1, outer_rad=15.4, R=95.7853, nominalD=40,
512 half_seg=0.75, refl=None, rotSpiderDegree=None, nmissing=0):
514 Generates a boolean pupil mask of the binary EELT pupil
515 on a map of size (npt, npt).
518 :returns: pupil image (npt, npt), boolean
519 :param int npt: size of the output array
520 :param float dspider: width of spiders in meters
521 :param float i0, j0: index of pixels where the pupil should be centred = p_geom.pupdiam / 2. - 0.5
522 Can be floating-point indexes.
523 :param float pixscale: size of a pixel of the image, in meters = ptel.diam/(p_geom.pupdiam / 2. - 0.5)
524 :param float gap: gap between 2 segments in metres
525 :param float rotdegree: rotation angle of the pupil, in degrees.
526 :param float D: diameter of the pupil. For the nominal EELT, D shall
528 :param int centerMark: when centerMark!=0, a pixel is added at the centre of
529 symmetry of the pupil in order to debug things using compass.
530 centerMark==1 draws a point
531 centerMark==2 draws 2 lines
532 :param bool halfSpider: half Spider computation flag
533 :param float pitch: segment pitch
534 :param int nseg: number of segments across the diameter
535 :param float inner_rad: Inner radius [meters]
536 :param float outter_rad: outter radius [meters]
537 :param float R: M1 curvature radius
538 :param float nominalD: diameter needed to get nominal aperture after projection
539 :param float half_seg: segment half size
540 :param float refl: std of the reflectivity of each segment
548 pixscale = D/(npt / 2. - 0.5)
551 pup = generateEeltPupilMask(npt, dspider, i0, j0, pixscale, gap, rotdegree)
554 rot = rotdegree * np.pi / 180
556 if rotSpiderDegree
is None:
559 rotSpider = rotSpiderDegree * np.pi / 180
566 outer_rad=outer_rad, R=R, nominalD=nominalD)
573 elif np.isscalar(refl):
574 referr = np.random.random(hx.size)
575 referr = referr * refl / np.std(referr)
576 refl = np.ones(hx.size) - referr
577 elif type(refl) == list:
579 refpist = np.random.randn(hx.size)
580 refpist = refpist * refl[0] / np.std(refpist)
581 reftip = np.random.randn(hx.size)
582 reftip = reftip * refl[1] / np.std(reftip)
583 reftilt = np.random.randn(hx.size)
584 reftilt = reftilt * refl[2] / np.std(reftilt)
585 refl = np.array([refpist, reftip, reftilt])
588 "refl param must be None, scalar (reflectivity std error) or list of 3 elements (piston, tip and tilt std errors)"
593 ind_missing = np.random.randint(0, hx.size / 6, nmissing)
596 if np.isscalar(refl):
597 refl = np.ones(hx.size)
598 refl[ind_missing] = 0
600 elif (refl.shape[0] == 3):
601 print(
"WARNING: there are piston, tip and tilt std errors, missing segments will be ignored")
603 refl[ind_missing] = 0
607 nominalD=nominalD, pitch=pitch, half_seg=half_seg)
610 if (dspider > 0
and nspider > 0):
611 if (halfSpider
is True):
612 pup = pup *
fillHalfSpider(npt, nspider, dspider, i0, j0, pixscale,
615 pup = pup *
fillSpider(npt, nspider, dspider, i0, j0, pixscale, rotSpider)
623 obstru = (util.dist(pup.shape[0], pup.shape[0] // 2 + 0.5,
624 pup.shape[0] // 2 + 0.5) >=
625 (pup.shape[0] * cobs + 1.) * 0.5).astype(np.float32)
630 def fillPolygon(x, y, i0, j0, scale, gap, N, index=0):
632 From a list of points defined by their 2 coordinates list
633 x and y, creates a filled polygon with sides joining the points.
634 The polygon is created in an image of size (N, N).
635 The origin (x,y)=(0,0) is mapped at pixel i0, j0 (both can be
636 floating-point values).
637 Arrays x and y are supposed to be in unit U, and scale is the
638 pixel size in U units.
640 :returns: filled polygon (N, N), boolean
641 :param float x, y: list of points defining the polygon
642 :param float i0, j0: index of pixels where the pupil should be centred.
643 Can be floating-point indexes.
644 :param float scale: size of a pixel of the image, in same unit as x and y.
645 :param float N: size of output image.
648 x = np.array([1,-1,-1.5,0,1.1])
649 y = np.array([1,1.5,-0.2,-2,0])
655 pol = fillPolygon(x, y, i0, j0, scale, gap, N, index=2)
659 X = (np.arange(N) - i0) * scale
660 Y = (np.arange(N) - j0) * scale
661 X, Y = np.meshgrid(X, Y, indexing=
'ij')
669 T = (np.arctan2(Y - y0, X - x0) + 2 * np.pi) % (2 * np.pi)
670 t = (np.arctan2(y - y0, x - x0) + 2 * np.pi) % (2 * np.pi)
676 sens = np.median(np.diff(t))
686 x = np.roll(x, -imin)
687 y = np.roll(y, -imin)
688 t = np.roll(t, -imin)
695 indx, indy = (np.array([], dtype=np.int64), np.array([], dtype=np.int64))
696 distedge = np.array([], dtype=np.float32)
701 sub = np.where((T >= t[-1]) | (T <= (t[0])))
703 sub = np.where((T >= t[i]) & (T <= t[j]))
707 vnorm = np.sqrt(dx**2 + dy**2)
711 crossprod = dx * (Y[sub] - y[i]) - dy * (X[sub] - x[i])
712 tmp = crossprod > gap
713 indx = np.append(indx, sub[0][tmp])
714 indy = np.append(indy, sub[1][tmp])
715 distedge = np.append(distedge, crossprod[tmp])
720 return (indx, indy, distedge)
723 a[indx, indy] = distedge
726 a = np.zeros((N, N), dtype=bool)
735 i0 = j0 = N / 2. - 0.5
740 Utilisee dans compass/shesha/shesha/supervisor/canapassSupervisor.py
741 pour le slaving des actus.
744 msk = np.zeros((6, pupNoSpiders.shape[0], pupNoSpiders.shape[1]))
745 mid = int(pupNoSpiders.shape[0] / 2)
746 tmp = np.zeros((pupNoSpiders.shape[0], pupNoSpiders.shape[1]))
747 for angle
in np.linspace(0, 60, npts):
749 msk[5, :, :] = tmp < npts * pupNoSpiders
751 msk[2, :, :] = tmp < npts * pupNoSpiders
754 for angle
in np.linspace(0, 60, npts):
755 tmp +=
compute1Spider(1, N, dspider, i0, j0, pixscale, angle * 2 * np.pi / 360)
756 msk[0, :, :] = tmp < npts * pupNoSpiders
758 msk[3, :, :] = tmp < npts * pupNoSpiders
761 for angle
in np.linspace(0, 60, npts):
762 tmp +=
compute1Spider(2, N, dspider, i0, j0, pixscale, angle * 2 * np.pi / 360)
763 msk[1, :, :] = tmp < npts * pupNoSpiders
765 msk[4, :, :] = tmp < npts * pupNoSpiders
772 Fonction de fab pour creer le slaving.
773 La fonction cree un tableau de booleens avec une seule spider.
774 Utilisee par la fonction compute6Segments()
776 a = np.ones((N, N), dtype=bool)
777 X = (np.arange(N) - i0) * scale
778 Y = (np.arange(N) - j0) * scale
779 X, Y = np.meshgrid(X, Y, indexing=
'ij')
782 nn = (abs(X * np.cos(i * w - rot) + Y * np.sin(i * w - rot)) < dspider / 2.)
787 def fillSpider(N, nspider, dspider, i0, j0, scale, rot):
789 Creates a boolean spider mask on a map of dimensions (N,N)
790 The spider is centred at floating-point coords (i0,j0).
792 :returns: spider image (boolean)
793 :param int N: size of output image
794 :param int nspider: number of spiders
795 :param float dspider: width of spiders
796 :param float i0: coord of spiders symmetry centre
797 :param float j0: coord of spiders symmetry centre
798 :param float scale: size of a pixel in same unit as dspider
799 :param float rot: rotation angle in radians
802 a = np.ones((N, N), dtype=bool)
803 X = (np.arange(N) - i0) * scale
804 Y = (np.arange(N) - j0) * scale
805 X, Y = np.meshgrid(X, Y, indexing=
'ij')
806 w = 2 * np.pi / nspider
807 for i
in range(nspider):
808 nn = (abs(X * np.cos(i * w - rot) + Y * np.sin(i * w - rot)) < dspider / 2.)
814 a = np.ones((N, N), dtype=bool)
815 b = np.ones((N, N), dtype=bool)
816 X = (np.arange(N) - i0) * scale
817 Y = (np.arange(N) - j0) * scale
818 X, Y = np.meshgrid(X, Y, indexing=
'ij')
819 w = 2 * np.pi / nspider
820 for i
in range(nspider):
821 right = (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) <
822 dspider / 2) * (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) > 0.)
823 left = (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) >
824 -dspider / 2) * (X * np.cos(i * w - rot) + Y * np.sin(i * w - rot) < 0.)
832 Cree une liste de coordonnees qui decrit un maillage hexagonal.
833 Retourne un tuple (x,y).
835 Le maillage est centre sur 0, l'un des points est (0,0).
836 Une des pointes de l'hexagone est dirigee selon l'axe Y, au sens ou le
837 tuple de sortie est (x,y).
839 :param float pitch: distance between 2 neighbour points
840 :param int supportSize: size of the support that need to be populated
844 nx = int(np.ceil((supportSize / 2.0) / pitch) + 1)
845 x = pitch * (np.arange(2 * nx + 1) - nx)
846 ny = int(np.ceil((supportSize / 2.0) / pitch / V3) + 1)
847 y = (V3 * pitch) * (np.arange(2 * ny + 1) - ny)
848 x, y = np.meshgrid(x, y, indexing=
'ij')
851 peak_axis = np.append(x, x + pitch / 2.)
852 flat_axis = np.append(y, y + pitch * V3 / 2.)
853 return flat_axis, peak_axis
857 outer_rad=15.4, R=95.7853, nominalD=40):
859 Computes the coordinates of the corners of all the hexagonal
861 Result is a tuple of arrays(6, 798).
864 D: (float) : pupil diameter in meters (it must be set to 40.0 m for the ELT)
866 rot: (float) : pupil rotation angle in radians
868 pitch: (float): Segment pitch [meters]
870 nseg: (int) : number of segments across the diameter
872 inner_rad : (float): Inner radius [meters]
874 outer_rad : (float): Outer radius [meters]
876 R : (float): Curvature radius of the M1
878 nominalD: (float): diameter for nominal pupil
889 ll = np.sqrt(lx**2 + ly**2)
893 nn = (ll > inner_rad * pitch) & (ll < outer_rad * pitch)
897 ll = np.sqrt(lx**2 + ly**2)
903 th = np.linspace(0, 2 * np.pi, 7)[0:6]
904 hx = np.cos(th) * pitch / V3
905 hy = np.sin(th) * pitch / V3
910 x = (lx[
None, :] + hx[:,
None])
911 y = (ly[
None, :] + hy[:,
None])
912 r = np.sqrt(x**2 + y**2)
914 rrc = R / r * np.arctan(r / R)
924 mrot = np.array([[np.cos(rot), np.sin(rot)], [-np.sin(rot), np.cos(rot)]])
930 xyrot = np.dot(mrot, np.transpose(np.array([x, y]), (1, 0, 2)))
932 return xyrot[0], xyrot[1]
937 La fonction est appelee quand l'utilisateur a demande une pupille
938 ELT, et renseigne un diametre de telescope different de 40 metres.
940 Faut vraiment que je commente ou t'as compris ??
950 "Vous utilisez un telescope de type ELT. Ce telescope",
951 "est fait pour etre utilise avec un diametre de 40 m.",
" ",
952 "Or, vous utilisez un diametre different. Cela signifie",
953 "que le telescope que vous etes en train de creer a une",
954 "taille differente du veritable E-ELT de l'ESO.",
" ",
955 " * Soit vous savez exactement ce que vous faites, auquel",
956 "cas bonne route.",
" ",
957 " * Soit vous desirez creer LE vrai E-ELT et il faut changer",
959 " 1) le diametre telescope de votre fichier de parametres et",
960 " le renseigner a 40 metres.",
961 " p_tel.set_diam(40.0) # Nominal size for the real EELT",
962 " 2) le nombre d'actionneurs de M4 a 75",
963 " p_dm0.set_nact(75) # 75 actu in 40m for pitch=54.05cm",
964 " 3) option: tourner la pupille de 90 degres pour revenir au",
965 " cas initial de compass",
966 " p_tel.set_pupangle(90.) # ELT pup rotation in degrees"
975 Reorganisation des segments facon ESO.
977 ESO-193058 Standard Coordinate System and Basic Conventions
979 :param float x: tableau des centres X des segments
980 :param float y: idem Y
981 :return tuple (x,y): meme tuple que les arguments d'entree, mais tries.
989 t = (np.arctan2(y, x) + pi_6 - 1e-3) % (pix2)
994 sector = (t > k * pi_3) & (t < (k + 1) * pi_3)
996 distance = (A * np.cos(u) - np.sin(u)) * x[sector] + (
997 np.cos(u) + A * np.sin(u)) * y[sector]
998 indsort = np.argsort(distance)
999 X = np.append(X, x[sector][indsort])
1000 Y = np.append(Y, y[sector][indsort])
1006 Returns the data type of a numpy variable, either scalar value or array
1008 if np.isscalar(truc):
1011 return type(truc.flatten()[0])
1014 def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D, softGap=0,
1015 nominalD=40, pitch=1.244683637214, half_seg=0.75):
1017 Builds a 2D image of the pupil with some attributes for each of the
1018 segments. Those segments are described from arguments hx and hy, that
1019 are produced by the function generateCoordSegments(D, rot).
1021 When attribute is a phase, then it must be a float array of dimension
1022 [3, 798] with the dimension 3 being piston, tip, and tilt.
1023 Units of phase is xxx rms, and the output of the procedure will be
1027 :returns: pupil image (N, N), with the same type of input argument attribute
1029 :param float/int/bool attribute: scalar value or 1D-array of the reflectivity of
1030 the segments or 2D array of phase
1031 If attribute is scalar, the value will be replicated for all segments.
1032 If attribute is a 1D array, then it shall contain the reflectivities
1034 If attribute is a 2D array then it shall contain the piston, tip
1035 and tilt of the segments. The array shall be of dimension
1036 [3, 798] that contains [piston, tip, tilt]
1037 On output, the data type of the pupil map will be the same as attribute.
1038 :param float hx, hy: arrays [6,:] describing the segment shapes. They are
1039 generated using generateCoordSegments()
1040 :param float dspider: width of spiders in meters
1041 :param float i0, j0: index of pixels where the pupil should be centred.
1042 Can be floating-point indexes.
1043 :param float scale: size of a pixel of the image, in meters.
1044 :param float gap: half-space between segments in meters
1045 :param int N: size of the output array (N,N)
1046 :param float D: diameter of the pupil. For the nominal EELT, D shall
1048 :param bool softGap: if False, the gap between segments is binary 0/1
1049 depending if the pixel is within the gap or not. If True, the gap
1050 is a smooth region of a fwhm of 2 pixels with a depth related to the
1052 :param float nominalD: diameter needed to get nominal pupil aperture
1053 :param float pitch: segment pitch
1054 :param float half_seg: segment half size
1058 attribute = np.ones(798)+np.random.randn(798)/20.
1072 if np.isscalar(attribute):
1073 attribute = np.array([attribute] * nseg)
1076 pupil = np.zeros((N, N), dtype=
getdatatype(attribute))
1079 x0 = np.mean(hx, axis=0)
1080 y0 = np.mean(hy, axis=0)
1082 x0 = x0 / scale + i0
1083 y0 = y0 / scale + j0
1085 hexrad = half_seg * D / nominalD / scale
1086 ix0 = np.floor(x0 - hexrad).astype(int) - 1
1087 iy0 = np.floor(y0 - hexrad).astype(int) - 1
1088 segdiam = np.ceil(hexrad * 2 + 1).astype(int) + 1
1090 n = attribute.shape[0]
1104 for i
in range(nseg):
1105 indx, indy, distedge =
fillPolygon(hx[:, i], hy[:, i], i0 - ix0[i],
1106 j0 - iy0[i], scale, gap * 0., segdiam,
1108 pupil[indx + ix0[i], indy + iy0[i]] = attribute[i] * (
1109 1. - (gap / scale / np.pi) / (1 + (distedge / scale)**2))
1112 for i
in range(nseg):
1113 indx, indy, distedge =
fillPolygon(hx[:, i], hy[:, i], i0 - ix0[i],
1114 j0 - iy0[i], scale, gap, segdiam,
1116 pupil[indx + ix0[i], indy + iy0[i]] = attribute[i]
1119 minimap = np.zeros((segdiam, segdiam))
1120 xmap = np.arange(segdiam) - segdiam / 2
1121 xmap, ymap = np.meshgrid(xmap, xmap, indexing=
'ij')
1123 diamseg = pitch * 2 / np.sqrt(3)
1124 diamfrizou = (pitch + diamseg) / 2 * D / nominalD
1129 factunit = 4 * scale / diamfrizou
1130 for i
in range(nseg):
1131 indx, indy, _ =
fillPolygon(hx[:, i], hy[:, i], i0 - ix0[i], j0 - iy0[i],
1132 scale, 0., segdiam, index=1)
1133 minimap = attribute[0, i] + (factunit * attribute[1, i]) * xmap + (
1134 factunit * attribute[2, i]) * ymap
1135 pupil[indx + ix0[i], indy + iy0[i]] = minimap[indx, indy]
1142 Renvoie une image de boolens (False) de taille (N,N) avec un point
1143 ou une croix (True) centree sur (i0, j0).
1144 :param int N: taille de l'image de sortie
1145 :param float i0, j0: position du marqueur de sortie
1146 :param int centerMark: 0 (pour rien), 1 (option point) ou 2 (option croix)
1150 X = (np.arange(N) - i0) * scale
1151 Y = (np.arange(N) - j0) * scale
1152 X, Y = np.meshgrid(X, Y, indexing=
'ij')
1154 res = (X**2 + Y**2) < 1
1156 res = (np.abs(X) < 0.9) | (np.abs(Y) < 0.9)
Numerical constants for shesha and config enumerations for safe-typing.
def fillPolygon(x, y, i0, j0, scale, gap, N, index=0)
From a list of points defined by their 2 coordinates list x and y, creates a filled polygon with side...
def centrePourVidal(N, i0, j0, centerMark)
Renvoie une image de boolens (False) de taille (N,N) avec un point ou une croix (True) centree sur (i...
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, nmissing=0)
Generates a boolean pupil mask of the binary EELT pupil on a map of size (npt, npt).
def reorganizeSegmentsOrderESO(x, y)
Reorganisation des segments facon ESO.
def make_VLT(dim, pupd, tel)
Initialize the VLT pupil.
def make_phase_ab(dim, pupd, tel, pup=None, xc=-1, yc=-1, real=0, halfSpider=False)
Compute the EELT M1 phase aberration.
def compute6Segments(pupNoSpiders, N, pixscale, dspider, i0, j0, rot=0)
def createHexaPattern(pitch, supportSize)
Cree une liste de coordonnees qui decrit un maillage hexagonal.
def make_pupil(dim, pupd, tel, xc=-1, yc=-1, real=0, halfSpider=False)
Initialize the system pupil.
def make_EELT(dim, pupd, tel, N_seg=-1)
Initialize the EELT pupil.
def generateCoordSegments(D, rot, pitch=1.244683637214, nseg=33, inner_rad=4.1, outer_rad=15.4, R=95.7853, nominalD=40)
Computes the coordinates of the corners of all the hexagonal segments of M1.
def gendron()
La fonction est appelee quand l'utilisateur a demande une pupille ELT, et renseigne un diametre de te...
def compute1Spider(nspider, N, dspider, i0, j0, scale, rot)
Fonction de fab pour creer le slaving.
def getdatatype(truc)
Returns the data type of a numpy variable, either scalar value or array.
def fillHalfSpider(N, nspider, dspider, i0, j0, scale, rot)
def generateSegmentProperties(attribute, hx, hy, i0, j0, scale, gap, N, D, softGap=0, nominalD=40, pitch=1.244683637214, half_seg=0.75)
Builds a 2D image of the pupil with some attributes for each of the segments.
def fillSpider(N, nspider, dspider, i0, j0, scale, rot)
Creates a boolean spider mask on a map of dimensions (N,N) The spider is centred at floating-point co...
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.