OOPAO 1.0.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.
- OOPAO/Asterism.py +287 -0
- OOPAO/Atmosphere.py +1457 -0
- OOPAO/BioEdge.py +1363 -0
- OOPAO/DeformableMirror.py +949 -0
- OOPAO/Detector.py +528 -0
- OOPAO/FieldTransformer.py +178 -0
- OOPAO/GainSensingCamera.py +205 -0
- OOPAO/InfluenceFunctions.py +123 -0
- OOPAO/LiFT.py +349 -0
- OOPAO/MisRegistration.py +133 -0
- OOPAO/NCPA.py +187 -0
- OOPAO/OPD_map.py +51 -0
- OOPAO/Pyramid.py +1308 -0
- OOPAO/SPRINT.py +246 -0
- OOPAO/ShackHartmann.py +1301 -0
- OOPAO/Source.py +548 -0
- OOPAO/SpatialFilter.py +95 -0
- OOPAO/Telescope.py +663 -0
- OOPAO/Zernike.py +148 -0
- OOPAO/__init__.py +66 -0
- OOPAO/calibration/CalibrationVault.py +142 -0
- OOPAO/calibration/InteractionMatrix.py +336 -0
- OOPAO/calibration/__init__.py +7 -0
- OOPAO/calibration/ao_calibration.py +384 -0
- OOPAO/calibration/ao_cockpit_psim.py +2163 -0
- OOPAO/calibration/compute_KL_modal_basis.py +333 -0
- OOPAO/calibration/getFittingError.py +81 -0
- OOPAO/calibration/get_fast_atmosphere.py +42 -0
- OOPAO/calibration/get_modal_basis.py +159 -0
- OOPAO/calibration/initialization_AO.py +110 -0
- OOPAO/calibration/initialization_AO_PWFS.py +155 -0
- OOPAO/calibration/initialization_AO_SHWFS.py +176 -0
- OOPAO/closed_loop/__init__.py +6 -0
- OOPAO/closed_loop/run_cl.py +330 -0
- OOPAO/closed_loop/run_cl_first_stage.py +224 -0
- OOPAO/closed_loop/run_cl_from_phase_screens.py +179 -0
- OOPAO/closed_loop/run_cl_long_push_pull.py +283 -0
- OOPAO/closed_loop/run_cl_sinusoidal_modulation.py +525 -0
- OOPAO/closed_loop/run_cl_two_stages.py +248 -0
- OOPAO/closed_loop/run_cl_two_stages_atm_change.py +300 -0
- OOPAO/mis_registration_identification_algorithm/__init__.py +7 -0
- OOPAO/mis_registration_identification_algorithm/applyMisRegistration.py +159 -0
- OOPAO/mis_registration_identification_algorithm/computeMetaSensitivityMatrix_Pyramid.py +210 -0
- OOPAO/mis_registration_identification_algorithm/computeMetaSensitivyMatrix.py +248 -0
- OOPAO/mis_registration_identification_algorithm/estimateMisRegistration.py +232 -0
- OOPAO/mis_registration_identification_algorithm/estimateMisRegistration_Pyramid.py +188 -0
- OOPAO/phaseStats.py +285 -0
- OOPAO/runtime.py +140 -0
- OOPAO/tools/OopaoGUI.py +123 -0
- OOPAO/tools/__init__.py +7 -0
- OOPAO/tools/displayTools.py +523 -0
- OOPAO/tools/gpuTransforms.py +52 -0
- OOPAO/tools/interpolateGeometricalTransformation.py +373 -0
- OOPAO/tools/interpolate_influence_functions.py +100 -0
- OOPAO/tools/separableInterpolation.py +108 -0
- OOPAO/tools/set_paralleling_setup.py +126 -0
- OOPAO/tools/tools.py +785 -0
- OOPAO/tools/user_defined_influence_functions.py +565 -0
- oopao-1.0.0.dist-info/METADATA +182 -0
- oopao-1.0.0.dist-info/RECORD +63 -0
- oopao-1.0.0.dist-info/WHEEL +5 -0
- oopao-1.0.0.dist-info/licenses/LICENSE +674 -0
- oopao-1.0.0.dist-info/top_level.txt +1 -0
OOPAO/Asterism.py
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Tue Aug 23 14:35:32 2022
|
|
4
|
+
|
|
5
|
+
@author: cheritie
|
|
6
|
+
"""
|
|
7
|
+
import numpy as np
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
from OOPAO.tools.displayTools import makeSquareAxes
|
|
10
|
+
from OOPAO.runtime import array_backend
|
|
11
|
+
|
|
12
|
+
_xp, _gpu_flag = array_backend()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _on_gpu(items):
|
|
16
|
+
return _gpu_flag and any(isinstance(item, _xp.ndarray) for item in items)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _stack(items):
|
|
20
|
+
"""np.array(items), or a CuPy stack when the sources hold GPU-resident arrays (np.array would refuse them)."""
|
|
21
|
+
if _on_gpu(items):
|
|
22
|
+
return _xp.stack([_xp.asarray(item) for item in items])
|
|
23
|
+
return np.array(items)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _object_array(items):
|
|
27
|
+
"""np.array(items, dtype=object); with GPU-resident arrays, a 1D object array holding them."""
|
|
28
|
+
if _on_gpu(items):
|
|
29
|
+
out = np.empty(len(items), dtype=object)
|
|
30
|
+
for i, item in enumerate(items):
|
|
31
|
+
out[i] = item
|
|
32
|
+
return out
|
|
33
|
+
return np.array(items, dtype=object)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Asterism:
|
|
37
|
+
def __init__(self,
|
|
38
|
+
list_src: list):
|
|
39
|
+
"""
|
|
40
|
+
************************** REQUIRED PARAMETERS **************************
|
|
41
|
+
|
|
42
|
+
An Asterism object is an asterism of Source objects. It requires the following parameters:
|
|
43
|
+
|
|
44
|
+
_ list_src : a list of Source objects that can combine NGS and LGS types
|
|
45
|
+
|
|
46
|
+
************************** COUPLING AN ASTERISM OBJECT **************************
|
|
47
|
+
|
|
48
|
+
Once generated, an asterism object "ast" can be coupled to a Telescope "tel" that contains the OPD.
|
|
49
|
+
_ This is achieved using the * operator : ast*tel
|
|
50
|
+
_ It can be accessed using : tel.src
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
************************** MAIN PROPERTIES **************************
|
|
54
|
+
|
|
55
|
+
The main properties of a Telescope object are listed here:
|
|
56
|
+
_ ast.coordinates : coordinates of the source objects
|
|
57
|
+
_ ast.altitude : altitude of the source objects
|
|
58
|
+
_ ast.nPhoton : nPhoton property of the source objects
|
|
59
|
+
|
|
60
|
+
************************** EXEMPLE **************************
|
|
61
|
+
|
|
62
|
+
Create a list of source object in H band with a magnitude 8 and combine it to the telescope
|
|
63
|
+
|
|
64
|
+
src_1 = Source(opticalBand = 'H', magnitude = 8, coordinates=[0,0])
|
|
65
|
+
src_2 = Source(opticalBand = 'H', magnitude = 8, coordinates=[60,0])
|
|
66
|
+
src_3 = Source(opticalBand = 'H', magnitude = 8, coordinates=[60,120])
|
|
67
|
+
src_4 = Source(opticalBand = 'H', magnitude = 8, coordinates=[60,240])
|
|
68
|
+
|
|
69
|
+
ast = Asterism([src_1,src_2,src_3, src_4])
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
self.n_source = len(list_src)
|
|
75
|
+
self.src = list_src
|
|
76
|
+
|
|
77
|
+
for i, src in enumerate(self.src):
|
|
78
|
+
src.inAsterism = True
|
|
79
|
+
src.ast_idx = i
|
|
80
|
+
self.chromatic_shift = None
|
|
81
|
+
print(self)
|
|
82
|
+
self.tag = 'asterism'
|
|
83
|
+
self.type = 'asterism'
|
|
84
|
+
self.wavelength = self.src[0].wavelength
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def laser_coordinates(self):
|
|
88
|
+
_laser_coordinates = []
|
|
89
|
+
for src in self.src:
|
|
90
|
+
_laser_coordinates.append(src.laser_coordinates)
|
|
91
|
+
return _laser_coordinates
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def Na_profile(self):
|
|
95
|
+
_Na_profile = []
|
|
96
|
+
for src in self.src:
|
|
97
|
+
_Na_profile.append(src.Na_profile)
|
|
98
|
+
return _Na_profile
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def fwhm_spot_up(self):
|
|
102
|
+
_fwhm_spot_up = []
|
|
103
|
+
for src in self.src:
|
|
104
|
+
_fwhm_spot_up.append(src.fwhm_spot_up)
|
|
105
|
+
return _fwhm_spot_up
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def fluxMap(self):
|
|
109
|
+
_fluxMap = []
|
|
110
|
+
for src in self.src:
|
|
111
|
+
_fluxMap.append(src.fluxMap)
|
|
112
|
+
return _fluxMap
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def phase(self):
|
|
116
|
+
_phase = []
|
|
117
|
+
for src in self.src:
|
|
118
|
+
_phase.append(src.phase)
|
|
119
|
+
return _phase
|
|
120
|
+
|
|
121
|
+
@phase.setter
|
|
122
|
+
def phase(self, val):
|
|
123
|
+
for src in self.src:
|
|
124
|
+
src.phase = val[src.ast_idx]
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def phase_no_pupil(self):
|
|
128
|
+
_phase_no_pupil = []
|
|
129
|
+
for src in self.src:
|
|
130
|
+
_phase_no_pupil.append(src.phase_no_pupil)
|
|
131
|
+
return _phase_no_pupil
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def coordinates(self):
|
|
135
|
+
_coordinates = []
|
|
136
|
+
for src in self.src:
|
|
137
|
+
_coordinates.append(src.coordinates)
|
|
138
|
+
return _coordinates
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def altitude(self):
|
|
142
|
+
_altitude = []
|
|
143
|
+
for src in self.src:
|
|
144
|
+
_altitude.append(src.altitude)
|
|
145
|
+
return _altitude
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def nPhoton(self):
|
|
149
|
+
_nPhoton = []
|
|
150
|
+
for src in self.src:
|
|
151
|
+
_nPhoton.append(src.nPhoton)
|
|
152
|
+
return _nPhoton
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def OPD(self):
|
|
156
|
+
_OPD = []
|
|
157
|
+
for src in self.src:
|
|
158
|
+
_OPD.append(src.OPD)
|
|
159
|
+
return _stack(_OPD)
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def OPD_no_pupil(self):
|
|
163
|
+
_OPD_no_pupil = []
|
|
164
|
+
for src in self.src:
|
|
165
|
+
_OPD_no_pupil.append(src.OPD_no_pupil)
|
|
166
|
+
return _stack(_OPD_no_pupil)
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def scintillation(self):
|
|
170
|
+
_scintillation = []
|
|
171
|
+
for src in self.src:
|
|
172
|
+
_scintillation.append(getattr(src, 'scintillation', None))
|
|
173
|
+
return _object_array(_scintillation)
|
|
174
|
+
|
|
175
|
+
@scintillation.setter
|
|
176
|
+
def scintillation(self, val):
|
|
177
|
+
for src in self.src:
|
|
178
|
+
src.scintillation = val[src.ast_idx]
|
|
179
|
+
|
|
180
|
+
@property
|
|
181
|
+
def scintillation_no_pupil(self):
|
|
182
|
+
_scintillation_no_pupil = []
|
|
183
|
+
for src in self.src:
|
|
184
|
+
_scintillation_no_pupil.append(getattr(src, 'scintillation_no_pupil', None))
|
|
185
|
+
return _object_array(_scintillation_no_pupil)
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def intensity(self):
|
|
189
|
+
# Aggregated field intensity (fluxMap * scintillation) of each source.
|
|
190
|
+
# This is the energy-bearing quantity; the per-source intensity is kept
|
|
191
|
+
# as a SINGLE array on each Source so a FieldTransformer warp conserves
|
|
192
|
+
# energy (no W(flux)*W(scint) cross-term). dtype=object mirrors the
|
|
193
|
+
# scintillation aggregation since sources may have None / differently
|
|
194
|
+
# shaped intensities (e.g. before propagation, or NGS vs LGS).
|
|
195
|
+
_intensity = []
|
|
196
|
+
for src in self.src:
|
|
197
|
+
_intensity.append(getattr(src, 'intensity', None))
|
|
198
|
+
return _object_array(_intensity)
|
|
199
|
+
|
|
200
|
+
@intensity.setter
|
|
201
|
+
def intensity(self, val):
|
|
202
|
+
# Distribute a per-source intensity back to each Source so a
|
|
203
|
+
# FieldTransformer can write warped intensities the same way it does
|
|
204
|
+
# for scintillation. After such a write the per-source fluxMap /
|
|
205
|
+
# scintillation are stale relative to intensity -- intensity is the
|
|
206
|
+
# authoritative amplitude path (amplitude = sqrt(intensity)).
|
|
207
|
+
for src in self.src:
|
|
208
|
+
src.intensity = val[src.ast_idx]
|
|
209
|
+
|
|
210
|
+
def __pow__(self, obj):
|
|
211
|
+
# Re-propagation function. Same as .* in OOMAO
|
|
212
|
+
obj.src = self
|
|
213
|
+
for src in self.src:
|
|
214
|
+
src.optical_path = [[src.type + '('+src.optBand+')', src]]
|
|
215
|
+
self.reset()
|
|
216
|
+
self*obj
|
|
217
|
+
return self
|
|
218
|
+
|
|
219
|
+
def __mul__(self, obj):
|
|
220
|
+
# Propagation function.
|
|
221
|
+
if obj is not None:
|
|
222
|
+
if isinstance(obj, list):
|
|
223
|
+
for i in range(len(obj)):
|
|
224
|
+
self*obj[i]
|
|
225
|
+
else:
|
|
226
|
+
obj.relay(self)
|
|
227
|
+
return self
|
|
228
|
+
|
|
229
|
+
def reset(self):
|
|
230
|
+
for src in self.src:
|
|
231
|
+
src.reset()
|
|
232
|
+
|
|
233
|
+
def print_optical_path(self):
|
|
234
|
+
for src in self.src:
|
|
235
|
+
src.print_optical_path()
|
|
236
|
+
|
|
237
|
+
# for backward compatibility
|
|
238
|
+
def print_properties(self):
|
|
239
|
+
print(self)
|
|
240
|
+
|
|
241
|
+
def display_asterism(self):
|
|
242
|
+
plt.figure()
|
|
243
|
+
x = np.linspace(0, 2*np.pi, 100, endpoint=True)
|
|
244
|
+
r = np.linspace(0, max(self.coordinates)[0], 6, endpoint=True)
|
|
245
|
+
for i_circle in range(1, 6):
|
|
246
|
+
plt.plot(r[i_circle]*np.cos(x), r[i_circle]*np.sin(x), '--k')
|
|
247
|
+
cm = plt.get_cmap('gist_rainbow')
|
|
248
|
+
for i_src in range(self.n_source):
|
|
249
|
+
if self.src[i_src].type == "NGS":
|
|
250
|
+
marker = '*'
|
|
251
|
+
size_marker = 20
|
|
252
|
+
else:
|
|
253
|
+
marker = '*'
|
|
254
|
+
size_marker = 10
|
|
255
|
+
plt.plot(self.src[i_src].coordinates[0]*np.cos(np.deg2rad(self.src[i_src].coordinates[1])),
|
|
256
|
+
self.src[i_src].coordinates[0]*np.sin(np.deg2rad(self.src[i_src].coordinates[1])),
|
|
257
|
+
marker,
|
|
258
|
+
markersize=size_marker,
|
|
259
|
+
color=cm(1.*i_src/self.n_source),
|
|
260
|
+
markeredgecolor='k',
|
|
261
|
+
label=self.src[i_src].type+'_'+str(i_src))
|
|
262
|
+
makeSquareAxes()
|
|
263
|
+
plt.xlabel('[Arcsec]')
|
|
264
|
+
plt.ylabel('[Arcsec]')
|
|
265
|
+
plt.legend()
|
|
266
|
+
|
|
267
|
+
def properties(self) -> dict:
|
|
268
|
+
self.prop = dict()
|
|
269
|
+
self.prop['parameters'] = f"{'Source':^8s}|{'Wavelength':^12s}|{'Zenith':^8s}|{'Azimuth':^9s}|{'Altitude':^10s}|{'Magnitude':^11s}|{'Flux':^11s}|"
|
|
270
|
+
self.prop['units'] = f"{'':^8s}|{'[m]':^12s}|{'[arcsec]':^8s}|{'[°]':^9s}|{'[m]':^10s}|{'':^11s}|{'[ph/m²/s]':^11s}|"
|
|
271
|
+
for i in range(self.n_source):
|
|
272
|
+
if i % 2 == 0:
|
|
273
|
+
self.prop['layer_%02d'%i] = f"\033[00m{'%3d-%s'%(i+1,self.src[i].type):^8s}|{self.src[i].wavelength:^12.1e}|{self.src[i].coordinates[0]:^8.2f}|{self.src[i].coordinates[1]:^9.2f}|{self.src[i].altitude:^10.2f}|{self.src[i]._magnitude:^11.2f}|{self.src[i]._nPhoton:^11.1e}|"
|
|
274
|
+
else:
|
|
275
|
+
self.prop['layer_%02d'%i] = f"\033[47m{'%3d-%s'%(i+1,self.src[i].type):^8s}|{self.src[i].wavelength:^12.1e}|{self.src[i].coordinates[0]:^8.2f}|{self.src[i].coordinates[1]:^9.2f}|{self.src[i].altitude:^10.2f}|{self.src[i]._magnitude:^11.2f}|{self.src[i]._nPhoton:^11.1e}|"
|
|
276
|
+
return self.prop
|
|
277
|
+
|
|
278
|
+
def __repr__(self):
|
|
279
|
+
self.properties()
|
|
280
|
+
str_prop = str()
|
|
281
|
+
n_char = len(max(self.prop.values(), key=len)) - len('\033[00m')
|
|
282
|
+
for i in range(len(self.prop.values())):
|
|
283
|
+
str_prop += list(self.prop.values())[i] + '\n'
|
|
284
|
+
title = f'\n{" Asterism ":-^{n_char}}\n'
|
|
285
|
+
end_line = f'\033[00m{"":-^{n_char}}\n'
|
|
286
|
+
table = title + str_prop + end_line
|
|
287
|
+
return table
|