2 import astropy.io.fits
as fits
14 """return the indices of the used actuators
17 xpos: (np.ndarray[ndim=1, dtype=np.int32]): (optional) actuator position in x
19 ypos: (np.ndarray[ndim=1, dtype=np.int32]): (optional) actuator position in y
22 Np: (int): (optional) number of actuators along the diameter
28 if (Np > 0
and Np != u.size):
29 raise ValueError(
"Number of actuator along the diameter unconsistent")
35 X = (xpos - pMin) / u[1]
36 Y = (ypos - pMin) / u[1]
37 return (Y * Np + X).astype(np.int32)
40 def get_idx(p_dm, *, xpos=None, ypos=None):
41 """return a correspondance between the covariance matrix indices and the covariance map indices
44 p_dm: (Param_dm): dm settings
47 xpos: (np.ndarray[ndim=1, dtype=np.int32]): (optional) actuator position in x
49 ypos: (np.ndarray[ndim=1, dtype=np.int32]): (optional) actuator position in y
52 index_map : (np.ndarray[ndim=1, dtype=np.int32]) : correspondance between the covariance matrix indices and the covariance map indices
55 if (xpos
is not None and ypos
is not None):
62 xx = np.tile(np.arange(Np), (Np, 1)).flatten(
'C')[csI]
63 xx = -np.tile(xx, (xx.size, 1))
66 yy = np.tile(np.arange(Np), (Np, 1)).flatten(
'F')[csI]
67 yy = -np.tile(yy, (yy.size, 1))
73 return dx.flatten(
"F") + (p_dm.nact * 2 - 1) * (dy.flatten(
"F") - 1)
77 size = sup.config.p_geom.pupdiam
78 N = 2**(int(np.log(2 * size) / np.log(2) + 1))
80 supportFi = np.zeros((N, N), dtype=np.float32)
81 fi = sup.config.p_dms[0]._influ[:, :, 0] * 1e-6
82 supportFi[:fi.shape[0], :fi.shape[1]] = fi
84 abs2fi = np.abs(np.fft.fft2(supportFi.T))**2
90 """otf = OTF_telescope(fourier)
92 Computes the OTF of the telescope, so that
93 > fft(OTF_telescope()).re
94 produces a PSF normalized with max(psf)=SR=1.0
97 size = sup.config.p_geom.pupdiam
98 N = 2**(int(np.log(2 * size) / np.log(2) + 1))
99 ud = sup.config.p_tel.diam / sup.config.p_geom.pupdiam
101 x = ud / (sup.config.p_tel.diam / 2.) * (np.arange(N) + 1 -
103 x2 = np.tile(x * x, (x.size, 1))
104 r = np.sqrt(x2 + x2.T)
107 pup = sup.config.p_geom._ipupil
111 surface_pup_m2 = sup.config.p_tel.diam**2 * (
112 1 - sup.config.p_tel.cobs**2) * np.pi / 4.
113 surface_pup_pix = surface_pup_m2 / ud**2
114 factnorm = surface_pup_pix**2
125 """ Return the number of valid subaps (per wfs) as well as their position
128 sup : (CompassSupervisor) : current supervisor
131 wfs : (str) : (optional), default "all" wfs used by tao ( among "all", "lgs", "ngs")
139 p_wfss = sup.config.p_wfs_ngs
141 p_wfss = sup.config.p_wfs_lgs + [sup.config.p_wfs_ngs[-1]]
143 p_wfss = sup.config.p_wfs_lgs + sup.config.p_wfs_ngs
145 validX = wfs._validpuppixx
146 validY = wfs._validpuppixy
147 toMeter = (sup.config.p_tel.diam / wfs.nxsub / wfs._pdiam)
148 validX = (validX - validX.max() / 2) * toMeter
149 validY = (validY - validY.max() / 2) * toMeter
152 nsubap.append(len(validX))
157 """ computes the autocorrelation so that
162 a: (np.ndarray[ndim=2, dtype=np.float32]): matrix to compute the autocorrelation on
166 b = np.abs(np.fft.fft2(a))
167 b = np.fft.ifft2(b * b).real * a.size
169 b = np.abs(np.fft.fft(a))
170 b = np.fft.ifft(b * b).real
172 print(
"error: autocorrelation: expect dim 1 or 2")
193 return 1.e-6 * np.exp(-(x * x + y * y) / (2 * x0 * x0))
196 def generate_files(sup, *,path=".", single_file=False, dm_use_tt=False, wfs="all",
197 lgs_filter_cst=0.1, tar=-1):
198 """write inputs parameters
200 sys-params.txt: contains the system parameters
204 subaps.fits : number and position of the subapertures
207 sup : (CompassSupervisor) : current supervisor
210 path : (str): (optional), default './' path where the files are written
212 single_file : (bool): (optional), default=False write a single fits File
214 wfs : (str) : (optional), default "all" wfs used by tao ( among "all", "lgs", "ngs")
216 lgs_filter_cst : (float) : (optional) add constant to filter out lgs tt
218 tar : (list) : (optional), default -1 index of the target
220 p_dm = sup.config.p_dms[0]
221 if (p_dm.type ==
'tt'):
222 print(
"ERROR: first dm must not be a 'tip-tilt")
225 ntotact = p_dm._ntotact
228 p_dm_tt = sup.config.p_dms[-1]
229 if (p_dm_tt.type !=
'tt'):
230 print(
"ERROR: tip-tilt dm must be the last one")
234 write_sys_param(sup, path=path, wfs=wfs, lgs_filter_cst=lgs_filter_cst, tar=tar)
236 idx =
get_idx(p_dm, xpos=p_dm._xpos, ypos=p_dm._ypos)
240 if (
not single_file):
241 hdu_idx = fits.PrimaryHDU(idx)
242 hdu_idx.header[
"NACT"] = nact
243 hdu_idx.header[
"NTOTACT"] = ntotact
244 hdul = fits.HDUList([hdu_idx])
245 hdul.writeto(path +
"/idx.fits", overwrite=1)
246 fits.writeto(path +
"/otftel.fits", otf, overwrite=1)
247 fits.writeto(path +
"/abs2fi.fits", abs2fi, overwrite=1)
249 hdu_prime = fits.PrimaryHDU(np.zeros(0))
250 hdu_nsubap = fits.ImageHDU(nsubaps, name=
"NSUBAP")
251 hdu_Xpos = fits.ImageHDU(X, name=
"XPOS")
252 hdu_Ypos = fits.ImageHDU(Y, name=
"YPOS")
253 hdul = fits.HDUList([hdu_prime, hdu_nsubap, hdu_Xpos, hdu_Ypos])
254 hdul.writeto(path +
"/subaps.fits", overwrite=1)
256 hdu_prime = fits.PrimaryHDU(np.zeros(0))
257 hdu_nsubap = fits.ImageHDU(nsubaps, name=
"NSUBAP")
258 hdu_Xpos = fits.ImageHDU(X, name=
"XPOS")
259 hdu_Ypos = fits.ImageHDU(Y, name=
"YPOS")
260 hdu_idx = fits.ImageHDU(idx, name=
"IDX")
261 hdu_idx.header[
"NACT"] = nact
262 hdu_idx.header[
"NTOTACT"] = ntotact
263 hdu_abs2fi = fits.ImageHDU(abs2fi, name=
"ABS2FI")
264 hdu_otf = fits.ImageHDU(otf, name=
"OTF")
265 hdul = fits.HDUList([
266 hdu_prime, hdu_nsubap, hdu_Xpos, hdu_Ypos, hdu_idx, hdu_abs2fi, hdu_otf
268 hdul.writeto(path +
"/sys-inputs.fits", overwrite=1)
272 """ transform a np.array into a string
275 a : (np.ndarray[ndim=1, dtype=np.int32]) : input array
278 if (type(a)
is np.ndarray):
279 for i
in range(a.size):
280 string += str(a[i]) +
" "
281 if (type(a)
is list):
282 for i
in range(len(a)):
283 string += str(a[i]) +
" "
289 def write_sys_param(sup, path=".", wfs="all", lgs_filter_cst=0.1, tar=-1):
290 """ Write a sysParam file for tao based on the compass configuration
293 sup : (CompassSupervisor) : current supervisor
296 path : (str) : (optional), "./" path to the sysParam file
298 wfs : (str) : (optional), default "all" wfs used by tao ( among "all", "lgs", "ngs")
300 lgs_filter_cst : (float) : (optional) add constant to filter out lgs tt
302 tar : (list) : (optional), default -1 index of the target
307 p_wfs_ngs = sup.config.p_wfs_ngs
308 p_wfs_lgs = sup.config.p_wfs_lgs
312 p_wfss = p_wfs_lgs + [p_wfs_ngs[-1]]
314 p_wfss = p_wfs_lgs + p_wfs_ngs
315 p_wfs_ts = sup.config.p_wfs_ts
316 p_targets = sup.config.p_targets
317 p_tel = sup.config.p_tel
318 p_loop = sup.config.p_loop
320 if (len(p_wfs_lgs) > 0):
321 lgs_flux = p_wfs_lgs[0].lgsreturnperwatt * p_wfs_lgs[0].laserpower * p_wfs_lgs[
322 0].optthroughput * 10**4
323 lgs_pix_size = p_wfs_lgs[0].pixsize
324 lambda_lgs = p_wfs_lgs[0].Lambda * 1e-6
325 through_lgs = p_wfs_lgs[0].optthroughput
326 spot_width = p_wfs_lgs[0].beamsize
327 lgs_alt = p_wfs_lgs[0].gsalt
331 lambda_lgs = 5.89e-07
336 if (len(p_wfs_ts) > 0):
337 ts_xpos = [w.xpos
for w
in p_wfs_ts]
338 ts_ypos = [w.ypos
for w
in p_wfs_ts]
343 f = open(path +
"/sys-params.txt",
"w")
344 f.write(
"diam : meter : Telescope diameter\n")
345 f.write(
to_str(p_tel.diam))
346 f.write(
"\nobs : percent : Central obscuration\n")
347 f.write(
to_str(p_tel.cobs))
348 f.write(
"\ntFrame : second : frame rate\n")
349 f.write(
to_str(p_loop.ittime))
350 f.write(
"\nnW : : number of WFS\n")
351 f.write(
to_str(len(p_wfss)))
352 f.write(
"\nnLgs : : number of LGS\n")
353 f.write(
to_str(len(p_wfs_lgs)))
354 f.write(
"\nnTS : : number of Truth Sensor\n")
355 f.write(
to_str(len(p_wfs_ts)))
356 f.write(
"\nnTarget : : number of Target\n")
358 f.write(
to_str(len(p_targets)))
361 f.write(
"\nNssp : : number of subaperture per wfs along the diameter\n")
362 f.write(
to_str([wfs.nxsub
for wfs
in p_wfss]))
363 f.write(
"\nfracsub : % : Minimal illumination fraction for valid subap\n")
365 f.write(
"\ngsAlt : meter^-1 : inverse of lazer altitude\n")
366 f.write(
to_str([1 / w.gsalt
for w
in p_wfs_lgs] + [0
for w
in p_wfs_ngs]))
367 f.write(
"\ntype : : guide star type (1:NGS, 2:LGS)\n")
368 f.write(
to_str([2
for w
in p_wfs_lgs] + [1
for w
in p_wfs_ngs]))
369 f.write(
"\nalphaX_as : arcsec : pointing direction of the wfs on x axis\n")
370 f.write(
to_str([w.xpos
for w
in p_wfss]))
371 f.write(
"\nalphaY_as : arcsec : pointing direction of the wfs on y axis\n")
372 f.write(
to_str([w.ypos
for w
in p_wfss]))
373 f.write(
"\nXPup : meter : pupil shift of the WFS\n")
374 f.write(
to_str([0
for i
in range(len(p_wfss))]))
375 f.write(
"\nYPup : meter : pupil shift of the WFS\n")
376 f.write(
to_str([0
for i
in range(len(p_wfss))]))
377 f.write(
"\nthetaML : : rotation of the microlenses\n")
378 f.write(
to_str([0
for i
in range(len(p_wfss))]))
379 f.write(
"\nthetaCam : : rotation of the camera\n")
380 f.write(
to_str([0
for i
in range(len(p_wfss))]))
381 f.write(
"\nsensibility: : sensitivity coeff of this WFS\n")
382 f.write(
to_str([1
for i
in range(len(p_wfss))]))
383 f.write(
"\ntracking : arcsec^2 : telescope tracking error parameters (x^2, y^2 and xy)\n"
386 f.write(
"\npasDPHI : : Precision of DPHI precomputation. //deprecated\n"
389 f.write(
"\nncpu : : Number of CPU used (only with openMP)\n")
391 f.write(
"\nmrNGS : : magnitude of NGS\n")
392 if (len(p_wfs_ngs) > 0):
393 f.write(
to_str([w.gsmag
for w
in p_wfs_ngs]))
396 f.write(
"\nlgsFlux : (ph/m2/s) : LGS photon return at M1\n")
398 f.write(
"\nngsPixSize : arcsec : NGS pixel size\n")
399 if (len(p_wfs_ngs) > 0):
400 f.write(
to_str(p_wfs_ngs[0].pixsize))
403 f.write(
"\nlgsPixSize : arcsec : LGS pixel size\n")
404 f.write(
to_str(lgs_pix_size))
405 f.write(
"\nlambdaNGS : meter : wave length for NGS\n")
406 if (len(p_wfs_ngs) > 0):
407 f.write(
to_str(p_wfs_ngs[0].Lambda * 1e-6))
410 f.write(
"\nlambdaLGS : meter : wave length for LGS\n")
411 f.write(
to_str(lambda_lgs))
412 f.write(
"\nbdw_m : meter : bandwidth\n")
414 f.write(
"\nthroughNGS : percent : transmission for NGS\n")
415 if (len(p_wfs_ngs) > 0):
416 f.write(
to_str(p_wfs_ngs[0].optthroughput))
419 f.write(
"\nthroughLGS : percent : transmission for LGS\n")
420 f.write(
to_str(through_lgs))
421 f.write(
"\nthroughAtm : percent : atmosphere transmission\n")
422 f.write(
to_str(through_atm))
423 f.write(
"\nRON : nb of e- : Read Out Noise \n")
424 f.write(
to_str(int(np.ceil(p_wfss[0].noise))))
425 f.write(
"\nlgsCst : : constant on lgs (simulate that LGS cannot measure tip-tilt and focus)\n")
426 f.write(
to_str(lgs_filter_cst))
427 f.write(
"\nspotWidth : arcsec : lazer width\n")
428 f.write(
to_str(spot_width))
429 f.write(
"\nlgsAlt : meter : sodium layer altitude\n")
431 f.write(
"\nlgsDepth : meter : depth of the sodium layer\n")
432 f.write(
to_str(lgs_depth))
433 f.write(
"\ntargetX_as : arcsec : taget direction on x axis\n")
435 f.write(
to_str(ts_xpos + [t.xpos
for t
in p_targets]))
436 elif(isinstance(tar,(list,np.ndarray))):
437 f.write(
to_str(ts_xpos + [tar[0]]))
439 f.write(
to_str(ts_xpos + [p_targets[tar].xpos]))
440 f.write(
"\ntargetY_as : arcsec : taget direction on y axis\n")
442 f.write(
to_str(ts_ypos + [t.ypos
for t
in p_targets]))
443 elif(isinstance(tar,(list,np.ndarray))):
444 f.write(
to_str(ts_ypos + [tar[1]]))
446 f.write(
to_str(ts_ypos + [p_targets[tar].ypos]))
450 """ Write a atmParam file for tao based on the compass configuration
453 sup : (CompassSupervisor) : current supervisor
456 path : (str) : (optional), default "./" path to the atmParam file
458 f = open(path +
"/prof-1-atmos-night0.txt",
"w")
460 f.write(
to_str(sup.config.p_atmos.nscreens))
461 f.write(
"\nr0 @ wfs lambda\n")
462 f.write(
to_str(sup.config.p_atmos.r0))
463 f.write(
"\ncn2 ESO units\n")
464 f.write(
to_str(sup.config.p_atmos.get_frac().tolist()))
465 f.write(
"\nh in meters\n")
466 f.write(
to_str(sup.config.p_atmos.get_alt().tolist()))
467 f.write(
"\nl0 in meters\n")
468 f.write(
to_str(sup.config.p_atmos.get_L0().tolist()))
469 f.write(
"\nwind direction \n")
470 f.write(
to_str(sup.config.p_atmos.get_winddir().tolist()))
471 f.write(
"\nwind speed meter/s^-1\n")
472 f.write(
to_str(sup.config.p_atmos.get_windspeed().tolist()))
474 shutil.copyfile(path +
"/prof-1-atmos-night0.txt", path +
"/prof0-atmos-night0.txt")
477 def write_meta_Dx(meta_Dx, *,nTS=0, nmeas=None, trans=True, path="."):
478 """Write command matrices
480 split the meta command matrix
483 meta_Dx: (np.ndarray[ndim=2, dtype=np.float32]): "meta" command matrix
486 nTS: (int): (optional), default=0. Number of truth sensors, command matrices are written as Di.fits where 'i' belongs to [0,nTS[ , if nTS<1 write the whole matrix as Dx.fits
488 nmeas: (np.ndarray[ndim=1, dtype=np.int32]): (optional) if set, must contains the number of measurements for each TS, the matrix is split according to theses numbers. By default, the matrix is split evenly between the nTS truth sensors
490 trans: (bool): (optional), default=True. Transpose the matrix if true
492 path: (str): (optional), default './' path where the files are written
496 fits.writeto(path +
"/Dx.fits", meta_Dx.T, overwrite=
True)
498 fits.writeto(path +
"/Dx.fits", meta_Dx, overwrite=
True)
502 n = meta_Dx.shape[1] // nTS
503 nmeas = np.arange(0, meta_Dx.shape[1] + n, n)
505 nmeas = np.append(0, nmeas.cumsum())
508 print(i + 1,
"out of", nTS, end=
'\r')
509 Dx = meta_Dx[:, nmeas[i]:nmeas[i + 1]]
511 fits.writeto(path +
"/Dx" + str(i) +
".fits", Dx.T, overwrite=
True)
513 fits.writeto(path +
"/Dx" + str(i) +
".fits", Dx, overwrite=
True)
def get_abs2fi(sup, *dm=0)
def write_atm_param(sup, *path=".")
Write a atmParam file for tao based on the compass configuration.
def autocorrelation(a)
computes the autocorrelation so that
def write_meta_Dx(meta_Dx, *nTS=0, nmeas=None, trans=True, path=".")
Write command matrices.
def used_actu(xpos, ypos, *Np=-1)
return the indices of the used actuators
def write_sys_param(sup, path=".", wfs="all", lgs_filter_cst=0.1, tar=-1)
Write a sysParam file for tao based on the compass configuration.
def get_subaps(sup, *wfs="all")
Return the number of valid subaps (per wfs) as well as their position.
def OTF_telescope(sup)
otf = OTF_telescope(fourier)
def to_str(a="")
transform a np.array into a string
def get_idx(p_dm, *xpos=None, ypos=None)
return a correspondance between the covariance matrix indices and the covariance map indices
def generate_files(sup, *path=".", single_file=False, dm_use_tt=False, wfs="all", lgs_filter_cst=0.1, tar=-1)
write inputs parameters