def numerical_image_gradients(theta0, delta, scene=None, stamp=None): dI_dp = [] for i, (p, dp) in enumerate(zip(theta0, delta)): theta = theta0.copy() imlo, _ = make_image(theta, scene, stamp) theta[i] += dp imhi, _ = make_image(theta, scene, stamp) dI_dp.append((imhi - imlo) / (dp)) return np.array(dI_dp)
def test_image_gradients(ptrue, delta, scene=None, stamp=None): delta = np.ones_like(ptrue) * 1e-6 #numerical grad_num = numerical_image_gradients(ptrue, delta, scene, stamp) image, grad = make_image(ptrue, scene, stamp) fig, axes = pl.subplots(len(ptrue), 3, sharex=True, sharey=True) for i in range(len(ptrue)): g = grad[i, :].reshape(stamp.nx, stamp.ny) c = axes[i, 0].imshow(grad_num[i, :, :].T, origin='lower') fig.colorbar(c, ax=axes[i, 0]) c = axes[i, 1].imshow(g.T, origin='lower') fig.colorbar(c, ax=axes[i, 1]) c = axes[i, 2].imshow((grad_num[i, :, :] - g).T, origin='lower') fig.colorbar(c, ax=axes[i, 2]) axes[0, 0].set_title('Numerical') axes[0, 1].set_title('Analytic') axes[0, 2].set_title('N - A')
def setup_scene(galaxy=False, fudge=1.0, fwhm=1.0, offset=0.0, size=(30, 30), add_noise=False): stamp = make_stamp(size, fwhm, offset=offset) # --- Get a Source and Scene ----- if galaxy: source = Galaxy() source.ngauss = 1 source.radii = np.arange(source.ngauss) * 0.5 + 1.0 source.q = 0.5 source.pa = np.deg2rad(30.) theta = [100., 10., 10., 0.5, np.deg2rad(10.)] label = ['$\psi$', '$x$', '$y$', '$q$', '$\\varphi$'] bounds = [(0, 1e4), (0., 30), (0, 30), (0, 1), (0, np.pi / 2)] else: source = Star() theta = [100., 10., 10.] label = ['$\psi$', '$x$', '$y$'] bounds = [(-1e6, 1e6), (-1e5, 1e5), (-1e5, 1e5)] scene = Scene(galaxy=galaxy) scene.sources = [source] # --- Generate mock and add to stamp --- ptrue = np.array(theta) * fudge true_image, partials = make_image(ptrue, scene, stamp) stamp.pixel_values = true_image.copy() err = stamp.pixel_values.max() * 1e-2 #err = np.sqrt(stamp.pixel_values.flatten()) stamp.ierr = np.ones(stamp.npix) / err if add_noise: noise = np.random.normal(0, err, size=(stamp.nx, stamp.ny)) stamp.pixel_values += noise return scene, stamp, ptrue, label
def setup_scene(psfname='', size=(100, 100), fudge=1.0, add_noise=False): # --- Get a postage stamp ---- stamp = make_stamp(size, psfname=psfname) # --- get the Scene --- scene = Scene(galaxy=False) sources = [Star()] scene.sources = sources # --- Get the mock image ---- label = ['flux', 'x', 'y'] theta = np.array([100., stamp.nx / 2., stamp.ny / 2.]) ptrue = theta * fudge stamp.pixel_values = make_image(ptrue, scene, stamp)[0] err = stamp.pixel_values.max() * 1e-2 #err = np.sqrt(stamp.pixel_values.flatten()) stamp.ierr = np.ones(stamp.npix) / err if add_noise: noise = np.random.normal(0, err, size=(stamp.nx, stamp.ny)) stamp.pixel_values += noise return scene, stamp, ptrue, label
stamp = make_stamp(size, psfname=psfname) # make the pixels tiny #stamp.distortion = np.eye(2) * 8.0 oversample = 8 stamp.psf.covariances *= oversample**2 #stamp.psf.covariances[:, 0, 0] /= oversample #stamp.psf.covariances[:, 1, 1] /= oversample stamp.psf.means *= oversample stamp.crpix = np.array([stamp.nx / 2., stamp.ny / 2.]) stamp.crval = np.zeros(2) T = -1.0 * np.eye(2) stamp.psf.covariances = np.matmul(T, np.matmul(stamp.psf.covariances, T.T)) stamp.psf.means = np.matmul(stamp.psf.means, T) # --- get the Scene --- scene = Scene() sources = [Star()] scene.sources = sources # --- Get the mock image ---- label = ['flux', 'x', 'y'] theta = np.array([100., 0.0, 0.0]) ptrue = theta stamp.pixel_values = make_image(ptrue, scene, stamp)[0] fig, ax = pl.subplots() ax.imshow(stamp.pixel_values.T, origin='lower') pl.show()
def fit_source(ra=53.115325, dec=-27.803518, imname='', psfname=None, stamp_size=(100, 100), use_grad=True, err_expand=1.0, jitter=0.0, gain=np.inf): """ """ # --- Build the postage stamp ---- stamp = make_stamp(imname, (ra, dec), stamp_size, psfname=psfname, center_type='celestial') stamp.snr = stamp.pixel_values * stamp.ierr stamp.ierr = stamp.ierr.flatten() / err_expand counts = stamp.pixel_values.flatten() - stamp.pixel_values.min() stamp.ierr = 1.0 / np.sqrt(1/stamp.ierr**2 + jitter**2 + counts/gain) # override the WCS so coordinates are in pixels # The scale matrix D stamp.scale = np.eye(2) # The sky coordinates of the reference pixel stamp.crval = np.zeros([2]) # The pixel coordinates of the reference pixel stamp.crpix = np.zeros([2]) # Rotate the PSF by 180 degrees T = -1.0 * np.eye(2) stamp.psf.covariances = np.matmul(T, np.matmul(stamp.psf.covariances, T.T)) stamp.psf.means = np.matmul(stamp.psf.means, T) # --- get the Scene --- scene = Scene(galaxy=False) sources = [Star()] scene.sources = sources # ---- Optimization ------ if use_grad: nll = argfix(negative_lnlike_stamp, scene=scene, stamp=stamp) else: nll = argfix(negative_lnlike_nograd, scene=scene, stamp=stamp) if False: nll = argfix(chi_vector, scene=scene, stamp=stamp) method = 'lm' use_grad = False if True: def callback(x): #nf += 1 print(x, nll(x)) callback = None # Initial and bounds p0 = np.array([stamp.pixel_values.sum(), stamp.nx/2, stamp.ny/2]) p0 += np.random.normal(0., [0.1 * p0[0], 0.5, 0.5]) bounds = [(1, 1e4), (0., stamp_size[0]), (0, stamp_size[1])] bounds = None # Optimize from scipy.optimize import minimize lbfgsb_opt = {'ftol': 1e-20, 'gtol': 1e-12, 'disp':True, 'iprint': -1, 'maxcor': 20} result = minimize(nll, p0, jac=use_grad, bounds=None, callback=callback, options=lbfgsb_opt) # plot results resid, partials = make_image(result.x, scene, stamp) dim = stamp.pixel_values mim = resid chi = (dim - mim) * stamp.ierr.reshape(stamp.nx, stamp.ny) fig, axes = pl.subplots(1, 4, sharex=True, sharey=True, figsize=(14.75, 3.25)) images = [dim, mim, dim-mim, chi] labels = ['Data', 'Model', 'Data-Model', '$\chi$'] for k, ax in enumerate(axes): c = ax.imshow(images[k].T, origin='lower') pl.colorbar(c, ax=ax) ax.set_title(labels[k]) return result, (fig, axes), nll(result.x), stamp, scene
if add_noise: noise = np.random.normal(0, err, size=(stamp.nx, stamp.ny)) stamp.pixel_values += noise return scene, stamp, ptrue, label if __name__ == "__main__": # Get a scene and a stamp at some parameters scene, stamp, ptrue, label = setup_scene(galaxy=True, fwhm=2.0, fudge=1.25, add_noise=True) true_image, partials = make_image(ptrue, scene, stamp) # Set up likelihoods nll = argfix(negative_lnlike_stamp, scene=scene, stamp=stamp) nll_nograd = argfix(negative_lnlike_nograd, scene=scene, stamp=stamp) # --- Chi2 on a grid ------ # needs to be debugged if False: mux = np.linspace(47, 53., 100) muy = np.linspace(47, 53., 100) flux = np.linspace(3000, 5000., 10) chi2 = np.zeros([len(mux), len(muy), len(flux)]) for i, x in enumerate(mux): for j, y in enumerate(muy):
if __name__ == "__main__": # --- Get a postage stamp ---- psfname = os.path.join(paths.psfmixture, 'f090_ng6_em_random.p') scene, stamp, ptrue, label = setup_scene(size=(50, 50), psfname=psfname, add_noise=True) nll = argfix(negative_lnlike_stamp, scene=scene, stamp=stamp) nll_nograd = argfix(negative_lnlike_nograd, scene=scene, stamp=stamp) # --- Plot a model and gradients thereof --- if False: theta_init = ptrue * 1.05 image_init, partials_init = make_image(theta_init, scene, stamp) fig, axes = pl.subplots(3, 2, sharex=True, sharey=True) ax = axes.flat[0] i = ax.imshow(stamp.pixel_values.T, origin='lower') ax.text(0.1, 0.9, 'Mock Data', transform=ax.transAxes) ax = axes.flat[1] i = ax.imshow(image_init.T, origin='lower') ax.text(0.1, 0.9, 'Initial Model', transform=ax.transAxes) for i, ddtheta in enumerate(partials_init[scene.free_inds, :]): ax = axes.flat[i + 2] ax.imshow(ddtheta.reshape(stamp.nx, stamp.ny).T, origin='lower') ax.text(0.1, 0.9, '$\partial I/\partial {}$'.format(label[i]), transform=ax.transAxes) pl.show()
scene.sources = sources label = ['flux', 'x', 'y'] nll = argfix(negative_lnlike_stamp, scene=scene, stamp=stamp) nll_nograd = argfix(negative_lnlike_nograd, scene=scene, stamp=stamp) # --- Initialize --- theta_init = np.array([stamp.pixel_values.sum() * 1.0, ra_init, dec_init]) if inpixels: world = np.array([ra_init, dec_init, 0]) hdr = fits.getheader(imname) ast = apy_wcs.WCS(hdr) center = ast.wcs_world2pix(world[None, :], 0)[0, :2] - stamp.lo theta_init = np.array( [stamp.pixel_values.sum() * 0.5, center[0], center[1]]) image_init, partials = make_image(theta_init, scene, stamp) # --- Plot initial value --- if True: fig, axes = pl.subplots(3, 2, sharex=True, sharey=True) ax = axes.flat[0] i = ax.imshow(stamp.pixel_values.T, origin='lower') ax.text(0.1, 0.9, 'Sim. Data', transform=ax.transAxes) ax = axes.flat[1] i = ax.imshow(image_init.T, origin='lower') ax.text(0.1, 0.9, 'Initial Model', transform=ax.transAxes) for i, ddtheta in enumerate(partials): ax = axes.flat[i + 2] ax.imshow(ddtheta.reshape(stamp.nx, stamp.ny).T, origin='lower') ax.text(0.1, 0.9,