def apply_displ_bias(self): logging.info('Applying displacement bias...') ax_slice, az_slice = ifunc.get_ax_az_slice(self.clip) displ_x_clip = self.displ['X']['img']['full'][ax_slice, az_slice] min_displ_x = np.percentile(displ_x_clip, 0.5) max_displ_x = np.percentile(displ_x_clip, 99.5) logging.info(' min_displ_x = {}'.format(min_displ_x)) bias = -min_displ_x + (max_displ_x - min_displ_x) * self.bias_mult self.displ['X']['img']['full'] += bias
def apply_displ_bias(self): logging.info("Applying displacement bias...") ax_slice, az_slice = ifunc.get_ax_az_slice(self.clip) displ_x_clip = self.displ["X"]["img"]["full"][ax_slice, az_slice] min_displ_x = np.percentile(displ_x_clip, 0.5) max_displ_x = np.percentile(displ_x_clip, 99.5) logging.info(" min_displ_x = {}".format(min_displ_x)) bias = -min_displ_x + (max_displ_x - min_displ_x) * self.bias_mult self.displ["X"]["img"]["full"] += bias
def calc_adj(self): for corr in self.corr_axes: if corr not in self.coeffs: self.coeffs[corr] = self.calc_coeffs(corr) ax_slice, az_slice = ifunc.get_ax_az_slice(self.clip) for axis in self.displ_axes: logging.info("Computing adj[{}][{}][full,clip]".format(axis, corr)) adj = ifunc.calc_adj_displ(self.ifuncs[axis], self.coeffs[corr], adj_clip=self.adj_clip) self.adj[axis][corr]["full"] = adj self.adj[axis][corr]["clip"] = adj[ax_slice, az_slice]
def calc_adj(self): for corr in self.corr_axes: if corr not in self.coeffs: self.coeffs[corr] = self.calc_coeffs(corr) ax_slice, az_slice = ifunc.get_ax_az_slice(self.clip) for axis in self.displ_axes: logging.info("Computing adj[{}][{}][full,clip]".format( axis, corr)) adj = ifunc.calc_adj_displ(self.ifuncs[axis], self.coeffs[corr], adj_clip=self.adj_clip) self.adj[axis][corr]['full'] = adj self.adj[axis][corr]['clip'] = adj[ax_slice, az_slice]
class AdjOpticsCase(object): """Provide the infrastructure to handle an analysis case for adjustable optics including a set of influence functions and displacements. :param ifuncs: dict to load ifuncs or define ifuncs :param displ: dict to load or define displacements :param case_id: case identifier string for report naming :param adj_clip: number of ifunc actuator rows, cols from edge to clip (scalar) :param clip: number of ax / az pixels from edge to clip (scalar or tuple) :param n_ss: sub-sample period (use 1 out of n_ss rows/columns) :param n_strips: number of axial strips for scatter calculation :param node_sep: node separation (microns) :param units: units """ def __init__(self, ifuncs=None, displ=None, case_id='10+2_exemplar', subcase_id=1, adj_clip=None, clip=20, bias_mult=None, n_ss=5, piston_tilt=True, node_sep=500, units='um', displ_axes=None, corr_axes=None, n_proc=4, n_strips=9): case = CASES[case_id] ifuncs = case['ifuncs'] displ = case['displ'] self.title = case['title'] self.case_id = case_id self.subcase_id = subcase_id self.ifuncs = dict() self.displ = AutoDict() self.piston_tilt = piston_tilt self.ifuncs_kwargs = ifuncs['kwargs'] self.displ_kwargs = displ['kwargs'] self.node_sep = node_sep self.units = units self.displ_axes = displ_axes or AXES self.corr_axes = corr_axes or AXES self.n_proc = n_proc self.n_strips = n_strips self.n_ss = n_ss self.adj_clip = adj_clip self.clip = clip self.bias_mult = bias_mult # Check if input ifuncs already has X and RY keys if all(axis in ifuncs for axis in AXES): for axis in AXES: self.ifuncs[axis] = ifuncs[axis].copy() else: # load ifuncs logging.info('Loading ifuncs X...') self.ifuncs['X'] = ifuncs['load_func'](axis='X', **ifuncs['kwargs']) logging.info('Computing ifuncs RY...') n_ax, n_az = self.ifuncs['X'].shape[-2:] self.n_coeffs_ax, self.n_coeffs_az = self.ifuncs['X'].shape[:2] ifx = self.ifuncs['X'] = self.ifuncs['X'].reshape(-1, n_ax, n_az) ifry = self.ifuncs['RY'] = np.empty_like(ifx) for i in range(ifx.shape[0]): ifry[i] = np.gradient(ifx[i], node_sep)[0] * RAD2ARCSEC self.n_ax, self.n_az = self.ifuncs['X'].shape[-2:] # Check if input displ already has X and RY keys if all(axis in displ for axis in AXES): for axis in AXES: self.displ[axis]['img']['full'] = \ displ[axis]['img']['full'].copy() else: # load displacements logging.info('Loading displ ...') self.displ['X']['img']['full'], self.displ['RY']['img']['full'] = \ displ['load_func'](self.n_ax, self.n_az, **displ['kwargs']) if self.bias_mult is not None: self.apply_displ_bias() self.displ['RY']['img']['full'] *= RAD2ARCSEC # Provide clipped displacements ax_slice, az_slice = ifunc.get_ax_az_slice(self.clip) for axis in AXES: self.displ[axis]['img']['clip'] = \ self.displ[axis]['img']['full'][ax_slice, az_slice] self.coeffs = AutoDict() # [corr_axis] self.adj = AutoDict() # [axis][corr_axis] self.resid = AutoDict() # [clip][type] for clip=('clip'|'full') # type = ('img'|'std'|'mean') self.scatter = AutoDict()
def __init__( self, ifuncs=None, displ=None, case_id="10+2_exemplar", subcase_id=1, adj_clip=None, clip=20, bias_mult=None, n_ss=5, piston_tilt=True, node_sep=500, units="um", displ_axes=None, corr_axes=None, n_proc=4, n_strips=9, ): case = CASES[case_id] ifuncs = case["ifuncs"] displ = case["displ"] self.title = case["title"] self.case_id = case_id self.subcase_id = subcase_id self.ifuncs = dict() self.displ = AutoDict() self.piston_tilt = piston_tilt self.ifuncs_kwargs = ifuncs["kwargs"] self.displ_kwargs = displ["kwargs"] self.node_sep = node_sep self.units = units self.displ_axes = displ_axes or AXES self.corr_axes = corr_axes or AXES self.n_proc = n_proc self.n_strips = n_strips self.n_ss = n_ss self.adj_clip = adj_clip self.clip = clip self.bias_mult = bias_mult # Check if input ifuncs already has X and RY keys if all(axis in ifuncs for axis in AXES): for axis in AXES: self.ifuncs[axis] = ifuncs[axis].copy() else: # load ifuncs logging.info("Loading ifuncs X...") self.ifuncs["X"] = ifuncs["load_func"](axis="X", **ifuncs["kwargs"]) logging.info("Computing ifuncs RY...") n_ax, n_az = self.ifuncs["X"].shape[-2:] self.n_coeffs_ax, self.n_coeffs_az = self.ifuncs["X"].shape[:2] ifx = self.ifuncs["X"] = self.ifuncs["X"].reshape(-1, n_ax, n_az) ifry = self.ifuncs["RY"] = np.empty_like(ifx) for i in range(ifx.shape[0]): ifry[i] = np.gradient(ifx[i], node_sep)[0] * RAD2ARCSEC self.n_ax, self.n_az = self.ifuncs["X"].shape[-2:] # Check if input displ already has X and RY keys if all(axis in displ for axis in AXES): for axis in AXES: self.displ[axis]["img"]["full"] = displ[axis]["img"]["full"].copy() else: # load displacements logging.info("Loading displ ...") self.displ["X"]["img"]["full"], self.displ["RY"]["img"]["full"] = displ["load_func"]( self.n_ax, self.n_az, **displ["kwargs"] ) if self.bias_mult is not None: self.apply_displ_bias() self.displ["RY"]["img"]["full"] *= RAD2ARCSEC # Provide clipped displacements ax_slice, az_slice = ifunc.get_ax_az_slice(self.clip) for axis in AXES: self.displ[axis]["img"]["clip"] = self.displ[axis]["img"]["full"][ax_slice, az_slice] self.coeffs = AutoDict() # [corr_axis] self.adj = AutoDict() # [axis][corr_axis] self.resid = AutoDict() # [clip][type] for clip=('clip'|'full') # type = ('img'|'std'|'mean') self.scatter = AutoDict()