def prepare_actuator_lattice(shape, Nact, sep, mask, dtype): """Prepare a lattice of actuators. Usage guide: returns a dict of { mask; shape Nact actuators; shape Nact poke_arr; shape shape ixx; shape (truthy part of mask) iyy; shape (truthy part of mask) } assign poke_arr[iyy, ixx] = actuators[mask] in the next step """ if mask is None: mask = np.ones(Nact, dtype=bool) actuators = np.zeros(Nact, dtype=dtype) cy, cx = [s // 2 for s in shape] Nactx, Nacty = Nact skip_samples_x, skip_samples_y = sep # python trick; floor division (//) rounds to negative inf, not zero # because FFT grid alignment biases things to the left, if Nact is odd # we want more on the negative side; # this will make that so neg_extreme_x = cx + -Nactx // 2 * skip_samples_x neg_extreme_y = cy + -Nacty // 2 * skip_samples_y pos_extreme_x = cx + Nactx // 2 * skip_samples_x pos_extreme_y = cy + Nacty // 2 * skip_samples_y # ix = np.arange(neg_extreme_x, pos_extreme_x+skip_samples_x, skip_samples_x) # iy = np.arange(neg_extreme_y, pos_extreme_y+skip_samples_y, skip_samples_y) # ixx, iyy = np.meshgrid(ix, iy) # ixx = ixx[mask] # iyy = iyy[mask] ix = slice(neg_extreme_x, pos_extreme_x, skip_samples_x) iy = slice(neg_extreme_y, pos_extreme_y, skip_samples_y) ixx = ix iyy = iy poke_arr = np.zeros(shape, dtype=dtype) return { 'mask': mask, 'actuators': actuators, 'poke_arr': poke_arr, 'ixx': ixx, 'iyy': iyy, }
def _ensure_P_vec(P): if not hasattr(P, '__iter__'): P = np.array([0, 0, P], dtype=config.precision) else: # iterable P2 = np.zeros(3, dtype=config.precision) P2[-len(P):] = P P = P2 return np.asarray(P).astype(config.precision)
def ray_aim(P, S, prescription, j, wvl, target=(0, 0, np.nan), debug=False): """Aim a ray such that it encounters the jth surface at target. Parameters ---------- P : numpy.ndarray shape (3,), a single ray's initial positions S : numpy.ndarray shape (3,) a single ray's initial direction cosines prescription : iterable sequence of surfaces in the prescription j : int the surface index in prescription at which the ray should hit (target) wvl : float wavelength of light to use in ray aiming, microns target : iterable of length 3 the position at which the ray should intersect the target surface NaNs indicate to ignore that position in aiming debug : bool, optional if True, returns the (ray-aiming) optimization result as well as the adjustment P Returns ------- numpy.ndarray deltas to P which result in ray intersection """ P = np.asarray(P).astype(config.precision).copy() S = np.asarray(S).astype(config.precision).copy() target = np.asarray(target) trace_path = prescription[:j + 1] def optfcn(x): P[:2] = x phist, _ = spencer_and_murty.raytrace(trace_path, P, S, wvl) final_position = phist[-1] euclidean_dist = (final_position - target)**2 euclidean_dist = np.nansum( euclidean_dist) / 3 # /3 = div by number of axes return euclidean_dist res = optimize.minimize(optfcn, np.zeros(2), method='L-BFGS-B') P[:] = 0 P[:2] = res.x if debug: return P, res else: return P
def _initialize_alphas(cs, x, alphas, j=0): # j = derivative order if alphas is None: if hasattr(x, 'dtype'): dtype = x.dtype else: dtype = config.precision if hasattr(x, 'shape'): shape = (len(cs), *x.shape) elif hasattr(x, '__len__'): shape = (len(cs), len(x)) else: shape = (len(cs), ) if j != 0: shape = (j + 1, *shape) alphas = np.zeros(shape, dtype=dtype) return alphas