def __init__(self, detector_shape, data, psfs, masks, patch_locs, floor=0.05, gain=0.01, initial_flat=None, alpha_flat=None, alpha_model=None, alpha_delta=None, alpha_bkgs=None, model_noise=False, est_noise=False): self.N = data.shape[0] self.D = data.shape[1] self.data = data self.gain = gain self.floor = floor self.patch_D = np.int(np.sqrt(data.shape[1])) self.flat_D = detector_shape[0] * detector_shape[1] self.detect_D = detector_shape self.masks = masks self.psfs = psfs self.patch_locs = patch_locs self.flat_model = initial_flat self.alpha_bkgs = alpha_bkgs self.alpha_flat = alpha_flat self.alpha_delta = alpha_delta self.alpha_model = alpha_model self.model_noise = model_noise if model_noise: self.est_noise = False else: self.est_noise = est_noise if self.masks == None: self.sum = np.sum self.dot = np.dot else: self.sum = self.quick_masked_sum self.dot = self.quick_masked_dot self.initialize(initial_flat) # ONLY SQUARE PATCHES FOR NOW!!! patch_side = np.int(np.sqrt(data[0].size)) assert (patch_side - np.sqrt(data[0].size)) == 0., 'Non-square patches' self.flatmap = FlatMapper(self.flat_model, patch_side, patch_locs)
def neg_log_likelihood(self, flat, flxs, bkgs, return_grads=True): """ Return the neg log likelihood of the data. `parms` is an array with the flat, flux, and background parameters appended. """ if self.model_noise: floor, gain = parms[-2:] else: floor, gain = self.floor, self.gain mapper = FlatMapper(flat, self.patch_D, self.patch_locs) flat_patches = mapper.get_1D_flat_patches() # model for the flux, pre-flat incident_model = flxs[:, None] * self.psfs + bkgs[:, None] models = flat_patches * incident_model if self.est_noise: x = self.data else: x = models C = floor + gain * x dmm = self.data - models dmm2 = dmm**2. nll = 0.5 * self.sum(dmm2 / C + np.log(C)) if return_grads: m_grad = self.grad_model(models, dmm, dmm2, 1. / C, gain) flat_grad = self.grad_flat_nll(incident_model, m_grad, mapper.rowinds, mapper.colinds) flux_grad = self.grad_fluxes(flat_patches, self.psfs, m_grad) bkg_grad = self.grad_bkgs(flat_patches, m_grad) return nll, flat_grad, flux_grad, bkg_grad else: return nll, None, None, None
def neg_log_likelihood(self, flat, flxs, bkgs, return_grads=True): """ Return the neg log likelihood of the data. `parms` is an array with the flat, flux, and background parameters appended. """ if self.model_noise: floor, gain = parms[-2:] else: floor, gain = self.floor, self.gain mapper = FlatMapper(flat, self.patch_D, self.patch_locs) flat_patches = mapper.get_1D_flat_patches() # model for the flux, pre-flat incident_model = flxs[:, None] * self.psfs + bkgs[:, None] models = flat_patches * incident_model if self.est_noise: x = self.data else: x = models C = floor + gain * x dmm = self.data - models dmm2 = dmm ** 2. nll = 0.5 * self.sum(dmm2 / C + np.log(C)) if return_grads: m_grad = self.grad_model(models, dmm, dmm2, 1. / C, gain) flat_grad = self.grad_flat_nll(incident_model, m_grad, mapper.rowinds, mapper.colinds) flux_grad = self.grad_fluxes(flat_patches, self.psfs, m_grad) bkg_grad = self.grad_bkgs(flat_patches, m_grad) return nll, flat_grad, flux_grad, bkg_grad else: return nll, None, None, None
def render_patches(self, psf_model, patch_side, flux_range, bkg_range, index, noise_parms, bad_frac): """ Make fake patches using a psf model, include noise, backgrounds, and a range of flux values. """ # center locations, dont allow less than full patches for now buff = (patch_side - 1) / 2 ind = ((self.pixel_rows >= buff) & (self.pixel_rows < self.flat_field.shape[0] - buff) & (self.pixel_cols >= buff) & (self.pixel_cols < self.flat_field.shape[1] - buff)) self.row_centers = self.pixel_rows[ind] self.col_centers = self.pixel_cols[ind] self.N = self.row_centers.size # flux and background defs self.fluxes = self.draw_fluxes(flux_range, index) self.bkgs = np.random.rand(self.N) * (bkg_range[1] - bkg_range[0]) self.bkgs += bkg_range[0] # define subpixel shifts and render psfs self.shifts = np.random.rand(self.N, 2) - 0.5 self.psfs = psf_model.render(self.shifts) # flat map pls = (self.row_centers, self.col_centers) flatmap = FlatMapper(self.flat_field, patch_side, pls) # create data self.data = self.psfs * self.fluxes[:, None] + self.bkgs[:, None] self.true_flats = flatmap.get_1D_flat_patches() self.data *= self.true_flats # does this go here?? self.vars = noise_parms[0] + self.data * noise_parms[1] self.data += (np.random.randn(self.N, patch_side ** 2) * np.sqrt(self.vars)) # make a set of masks to indicate 'bad data' size = self.flat_field.size bf = np.zeros(size, np.bool) Nbad = np.int(np.round(size * bad_frac)) ind = np.random.permutation(size)[:Nbad] bf[ind] = True self.bad_field = bf.reshape(self.flat_field.shape) badmap = FlatMapper(self.bad_field, patch_side, pls) self.masks = badmap.get_1D_flat_patches()