42 from scipy.sparse
import csr_matrix
46 """ This optimizer class handles all the modal basis and DM Influence functions
50 _config : (config) : Configuration parameters module
52 _dms : (DmCompass) : DmCompass instance
54 _target : (TargetCompass) : TargetCompass instance
56 slaved_actus : TODO : docstring
58 selected_actus : TODO : docstring
60 couples_actus : TODO : docstring
62 index_under_spiders : TODO : docstring
64 modal_basis : (np.ndarray) : Last modal basis computed
66 projection_matrix : (np.ndarray) : Last projection_matrix computed
68 def __init__(self, config, dms, target):
69 """ Instantiate a ModalBasis object
72 config : (config) : Configuration parameters module
74 dms : (DmCompass) : DmCompass instance
76 target : (TargetCompass) : TargetCompass instance
89 """ Computes and return the influence function phase basis of the specified DM
93 dm_index : (int) : Index of the DM
96 influ_sparse : (csr_matrix) : influence function phases
98 return basis.compute_dm_basis(self.
_dms_dms._dms.d_dms[dm_index],
99 self.
_config_config.p_dms[dm_index],
103 """ Computes and return IF delta for the specified DM
106 dm_index : (int) : Index of the DM
109 influ_delta : (np.ndarray) : influence function deltas
111 ifsparse = basis.compute_dm_basis(self.
_dms_dms._dms.d_dms[dm_index],
114 mpup = self.
_config_config.p_geom.get_mpupil()
115 npix_in_pup = np.sum(mpup)
116 ifdelta = ifsparse.dot(ifsparse.T) / np.sum(mpup)
117 return ifdelta.toarray()
120 nbpairs: int =
None, return_delta: bool =
False) -> np.ndarray:
121 """ Computes a given modal basis ("KL2V", "Btt", "Btt_petal") and return the 2 transfer matrices
124 modal_basis_type : (str) : modal basis to compute ("KL2V", "Btt", "Btt_petal")
127 merged : (bool) : TODO description
129 nbpairs : (int) : TODO description
132 modal_basis : (np.ndarray) : modes to volts matrix
134 projection_matrix : (np.ndarray) : volts to modes matrix (None if "KL")
136 if (modal_basis_type ==
"KL2V"):
137 print(
"Computing KL2V basis...")
139 self.
_config_config.p_controllers[0], self.
_dms_dms._dms,
142 fnz = util.first_non_zero(self.
modal_basismodal_basis, axis=0)
146 fnz, np.arange(self.
modal_basismodal_basis.shape[1])
149 projection_matrix =
None
150 elif (modal_basis_type ==
"Btt"):
151 print(
"Computing Btt basis...")
153 merged=merged, nbpairs=nbpairs,
154 return_delta=return_delta)
155 fnz = util.first_non_zero(self.
modal_basismodal_basis, axis=0)
159 fnz, np.arange(self.
modal_basismodal_basis.shape[1])
162 elif (modal_basis_type ==
"Btt_petal"):
163 print(
"Computing Btt with a Petal basis...")
166 raise RuntimeError(
"Unsupported modal basis")
171 return_delta: bool =
False) -> np.ndarray:
172 """ Computes the so-called Btt modal basis. The <merged> flag allows merto merge
173 2x2 the actuators influence functions for actuators on each side of the spider (ELT case)
176 merged : (bool) : If True, merge 2x2 the actuators influence functions for
177 actuators on each side of the spider (ELT case). Default
180 nbpairs : (int) : Default is None. TODO : description
182 return_delta : (bool) : If False (default), the function returns
183 Btt (modes to volts matrix),
184 and P (volts to mode matrix).
185 If True, returns delta = IF.T.dot(IF) / N
189 Btt : (np.ndarray) : Btt modes to volts matrix
191 projection_matrix : (np.ndarray) : volts to Btt modes matrix
194 dms_basis = basis.compute_IFsparse(self.
_dms_dms._dms, self.
_config_config.p_dms, self.
_config_config.p_geom)
195 influ_basis = dms_basis[:-2,:]
196 tt_basis = dms_basis[-2:,:].toarray()
200 influ_basis2 = influ_basis.copy()
201 index_remove = index_under_spiders.copy()
202 index_remove += list(couples_actus[:, 1])
203 print(
"Pairing Actuators...")
204 for i
in range(couples_actus.shape[0]):
205 influ_basis2[couples_actus[i, 0], :] += influ_basis2[
206 couples_actus[i, 1], :]
207 print(
"Pairing Done")
208 boolarray = np.zeros(influ_basis2.shape[0], dtype=bool)
209 boolarray[index_remove] =
True
214 influ_basis2 = influ_basis2[~boolarray, :]
215 influ_basis = influ_basis2
217 self.
bttbtt, self.
projection_matrixprojection_matrix = basis.compute_btt(influ_basis.T, tt_basis.T, return_delta=return_delta)
220 btt2 = np.zeros((len(boolarray) + 2, self.
bttbtt.shape[1]))
221 btt2[np.r_[~boolarray,
True,
True], :] = self.
bttbtt
222 btt2[couples_actus[:, 1], :] = btt2[couples_actus[:, 0], :]
224 P2 = np.zeros((self.
bttbtt.shape[1], len(boolarray) + 2))
226 P2[:, couples_actus[:, 1]] = P2[:, couples_actus[:, 0]]
233 """ Used to compute merged IF from each side of the spider
234 for an ELT case (Petalling Effect)
237 dm_index : (int) : DM index
240 nbpairs : (int) : Default is None. TODO : description
243 pairs : (np.ndarray) : TODO description
245 discard : (list) : TODO description
247 p_geom = self.
_config_config.p_geom
250 cent = p_geom.pupdiam / 2. + 0.5
251 p_tel = self.
_config_config.p_tel
252 p_tel.t_spiders = 0.51
253 spup = mkP.make_pupil(p_geom.pupdiam, p_geom.pupdiam, p_tel, cent,
254 cent).astype(np.float32).T
257 spup2 = mkP.make_pupil(p_geom.pupdiam, p_geom.pupdiam, p_tel, cent,
258 cent).astype(np.float32).T
260 spiders = spup2 - spup
262 (spidersID, k) = scipy.ndimage.label(spiders)
263 spidersi = util.pad_array(spidersID, p_geom.ssize).astype(np.float32)
264 px_list_spider = [np.where(spidersi == i)
for i
in range(1, k + 1)]
267 dm_posx = self.
_config_config.p_dms[dm_index]._xpos - 0.5
268 dm_posy = self.
_config_config.p_dms[dm_index]._ypos - 0.5
269 dm_pos_mat = np.c_[dm_posx, dm_posy].T
271 pitch = self.
_config_config.p_dms[dm_index]._pitch
272 discard = np.zeros(len(dm_posx), dtype=bool)
276 for k, px_list
in enumerate(px_list_spider):
277 pts = np.c_[px_list[1],
281 line_eq = np.linalg.pinv(pts).dot(np.ones(pts.shape[0]))
282 aa, bb = line_eq[0], line_eq[1]
286 if np.abs(bb) < np.abs(aa):
287 one_point = np.array([1 / aa, 0.])
289 one_point = np.array([0., 1 / bb])
292 rotation = np.array([[-bb, aa], [-aa, -bb]]) / (aa**2 + bb**2)**.5
295 rotated_px = rotation.dot(pts.T - one_point[:,
None])
298 min_u, max_u = rotated_px[0].min() - 5. * pitch, rotated_px[0].max(
302 rotated_actus = rotation.dot(dm_pos_mat - one_point[:,
None])
303 sel_good_side = (rotated_actus[0] > min_u) & (rotated_actus[0] < max_u)
306 sel_discard = (np.abs(rotated_actus[1]) < threshold * pitch) & sel_good_side
307 discard |= sel_discard
310 sel_pairable = (np.abs(rotated_actus[1]) > threshold * pitch) & \
311 (np.abs(rotated_actus[1]) < 1. * pitch) & \
314 pairable_index = np.where(sel_pairable)[0]
315 u_coord = rotated_actus[
318 order = np.sort(u_coord)
319 order_index = pairable_index[np.argsort(
324 if (nbpairs
is None):
328 i = len(order) // 2 - nbpairs
329 ii = len(order) // 2 + nbpairs
333 if np.abs(order[i] - order[i + 1]) < .2 * pitch:
334 pairs += [(order_index[i], order_index[i + 1])]
338 print(
'To discard: %u actu' % np.sum(discard))
339 print(
'%u pairs to slave' % len(pairs))
340 if np.sum(discard) == 0:
343 list(np.where(discard)[0])
344 return np.asarray(pairs), list(np.where(discard)[0])
347 """ Computes a Btt modal basis with Pistons filtered
350 Btt : (np.ndarray) : Btt modes to volts matrix
352 P : (np.ndarray) : volts to Btt modes matrix
354 pzt_index = np.where([d.type
is scons.DmType.PZT
for d
in self.
_config_config.p_dms])[0][0]
356 petal_dm_index = np.where([
357 d.influ_type
is scons.InfluType.PETAL
for d
in self.
_config_config.p_dms
360 tt_index = np.where([d.type
is scons.DmType.TT
for d
in self.
_config_config.p_dms])[0][0]
363 self.
modal_basismodal_basis, self.
projection_matrixprojection_matrix = basis.compute_btt(influ_pzt.T, influ_tt.T, influ_petal=influ_petal)
367 """ Return the phase to modes matrix by using the given modal basis
370 modal_basis : (np.ndarray) : Modal basis matrix
373 phase_to_modes : (np.ndarray) : phase to modes matrix
375 nbmode = modal_basis.shape[1]
376 phase = self.
_target_target.get_tar_phase(0)
377 phase_to_modes = np.zeros((nbmode, phase.shape[0], phase.shape[1]))
378 S = np.sum(self.
_config_config.p_geom._spupil)
379 for i
in range(nbmode):
380 self.
_dms_dms.set_command((modal_basis[:, i]).copy())
382 self.
_target_target.raytrace(0, dms=self.
_dms_dms, ncpa=
False, reset=
True)
383 phase = self.
_target_target.get_tar_phase(0, pupil=
True)
385 norm = np.sqrt(np.sum((phase)**2) / S)
386 if norm == 0: norm = 1
387 phase_to_modes[i] = phase / norm
388 return phase_to_modes
This optimizer class handles all the modal basis and DM Influence functions related operations.
np.ndarray compute_merged_influ(self, int dm_index, *int nbpairs=None)
Used to compute merged IF from each side of the spider for an ELT case (Petalling Effect)
np.ndarray compute_phase_to_modes(self, np.ndarray modal_basis)
Return the phase to modes matrix by using the given modal basis.
np.ndarray compute_influ_delta(self, int dm_index)
Computes and return IF delta for the specified DM.
modal_basis
(np.ndarray) : Last modal basis computed
csr_matrix compute_influ_basis(self, int dm_index)
Computes and return the influence function phase basis of the specified DM as a sparse matrix.
projection_matrix
(np.ndarray) : Last projection_matrix computed
def __init__(self, config, dms, target)
np.ndarray compute_btt_petal(self)
Computes a Btt modal basis with Pistons filtered.
np.ndarray compute_btt_basis(self, *bool merged=False, int nbpairs=None, bool return_delta=False)
Computes the so-called Btt modal basis.
slaved_actus
TODO : docstring.
index_under_spiders
TODO : docstring.
selected_actus
TODO : docstring.
np.ndarray compute_modes_to_volts_basis(self, str modal_basis_type, *bool merged=False, int nbpairs=None, bool return_delta=False)
Computes a given modal basis ("KL2V", "Btt", "Btt_petal") and return the 2 transfer matrices.
couples_actus
TODO : docstring.
Python package for AO operations on COMPASS simulation.
Numerical constants for shesha and config enumerations for safe-typing.
Pupil creation functions.
Basic utilities function.