def test_poly_mean(): # Zero'th order polynomial fitting should be pretty trivial, just # the same as the mean fitting. So much of this code is just taken from # the mean testing in test_simple N = 0 nparam = 5 interp = piff.Polynomial(N) nstars = 100 # Choose some random values of star parameters np_rng = np.random.RandomState(1234) vectors = [np_rng.random_sample(size=nparam) for i in range(nstars)] # take the mean of them. Our curve fit should be able to reproduce this. mean = np.mean(vectors, axis=0) # Choose some random positions in the field. data = [ piff.Star.makeTarget(u=np_rng.random_sample() * 10, v=np_rng.random_sample() * 10).data for i in range(nstars) ] fit = [piff.StarFit(v) for v in vectors] stars = [piff.Star(d, f) for d, f in zip(data, fit)] # Run our solver. interp.solve(stars) # we expect one set of coefficients per object assert len(interp.coeffs) == 5 # We should have very close values (not necessarily identical) since # we calculate these in numerically different ways. for mu, val in zip(mean, interp.coeffs): assert np.isclose(mu, val[0, 0]) # We also expect that if we interpolate to any point we just # get the mean as well for i in range(30): target = piff.Star.makeTarget(u=np_rng.random_sample() * 10, v=np_rng.random_sample() * 10) target = interp.interpolate(target) np.testing.assert_almost_equal(target.fit.params, mean) # Now test running it via the config parser config = { 'interp': { 'type': 'Polynomial', 'order': 0, } } logger = piff.config.setup_logger() interp = piff.Interp.process(config['interp'], logger) interp.solve(stars) # Same tests assert len(interp.coeffs) == 5 for mu, val in zip(mean, interp.coeffs): assert np.isclose(mu, val[0, 0]) np.testing.assert_almost_equal(target.fit.params, mean)
def test_twodstats(): """Make sure we can execute and print a readout of the plot """ if __name__ == '__main__': logger = piff.config.setup_logger(2) else: logger = None model = piff.Gaussian(fastfit=True) interp = piff.Polynomial(order=1) # should find that order=1 is better # create background model stars, true_model = generate_starlist(100) psf = piff.SimplePSF(model, interp) psf.fit(stars, None, None) # check the coeffs of sigma and g2, which are actually linear fits # skip g1 since it is actually a 2d parabola # factor of 0.263 is to account for going from pixel xy to wcs uv np.testing.assert_almost_equal(psf.interp.coeffs[0].flatten(), np.array([0.4, 0, 1. / (0.263 * 2048), 0]), decimal=4) np.testing.assert_almost_equal(psf.interp.coeffs[2].flatten(), np.array([-0.1 * 1000 / 2048, 0, 0.1 / (0.263 * 2048), 0]), decimal=4) stats = piff.TwoDHistStats(number_bins_u=5, number_bins_v=5, reducing_function='np.mean') stats.compute(psf, stars, logger=logger) # check the twodhists # get the average value in the bin u_i = 3 v_i = 3 icen = stats.twodhists['u'][v_i, u_i] / 0.263 jcen = stats.twodhists['v'][v_i, u_i] / 0.263 print('icen = ',icen) print('jcen = ',jcen) icenter = 1000 jcenter = 2000 # the average value in the bin should match up with the model for the average coordinates sigma, g1, g2 = psf_model(icen, jcen, icenter, jcenter) sigma_average = stats.twodhists['T'][v_i, u_i] g1_average = stats.twodhists['g1'][v_i, u_i] g2_average = stats.twodhists['g2'][v_i, u_i] # assert equal to 4th decimal print('sigma, g1, g2 = ',[sigma,g1,g2]) print('av sigma, g1, g2 = ',[sigma_average,g1_average,g2_average]) np.testing.assert_almost_equal([sigma, g1, g2], [sigma_average, g1_average, g2_average], decimal=2) # Test the plotting and writing twodstats_file = os.path.join('output','twodstats.pdf') stats.write(twodstats_file) # repeat for whisker stats = piff.WhiskerStats(number_bins_u=21, number_bins_v=21, reducing_function='np.mean') stats.compute(psf, stars) # Test the plotting and writing twodstats_file = os.path.join('output','whiskerstats.pdf') stats.write(twodstats_file)
def test_poly_indexing(): # Some indexing tests for a polynomial up to order 3 N = 3 interp = piff.Polynomial(orders=[N]) interp._setup_indices(1) # We expect there to be these coefficients: # x^0 y^0 1 # x^0 y^1 2 # x^1 y^0 3 # x^0 y^2 4 # x^1 y^1 5 # x^2 y^0 6 # x^0 y^3 7 # x^1 y^2 8 # x^2 y^1 9 # x^3 y^0 10 # Check that we have the indices we expect assert interp.indices[0] == [(0, 0), (0, 1), (1, 0), (0, 2), (1, 1), (2, 0), (0, 3), (1, 2), (2, 1), (3, 0)] assert interp.nvariables[0] == 10 # check the packing then unpacking a np_rng = np.random.RandomState(1234) packed = np_rng.uniform(size=interp.nvariables[0]) unpacked = interp._unpack_coefficients(0, packed) packed_test = interp._pack_coefficients(0, unpacked) # Check that the shape is 4*4 in the unpacked (because we # want space for all the terms), and that we can unpack and # repack successfully. np.testing.assert_array_equal(packed, packed_test) assert unpacked.shape == (N + 1, N + 1) unpacked_test = np.zeros_like(unpacked) # check that we have zeros for the terms that should be zero in the matrix. # We don't want any terms with total exponent > N. # The variabled "unpacked" was created above by unpacking a random vector. # it should be zero where i+j>3 and have the random valus below that. for i in range(N + 1): for j in range(N + 1): if i + j > N: #Note we have two arrays, unpacked and unpacked_test assert unpacked[i, j] == 0.0 unpacked_test[i, j] = 0.0 # Now do the test the other way around, checking that # we can pack and then unpack packed_test_2 = interp._pack_coefficients(0, unpacked_test) unpacked_test_2 = interp._unpack_coefficients(0, packed_test_2) np.testing.assert_array_equal(unpacked_test_2, unpacked_test)
def sub_poly_linear(type1): # Now lets do something more interesting - test a linear model. # with no noise this should fit really well, though again not # numerically perfectly. np_rng = np.random.RandomState(1234) nparam = 3 N = 1 nstars = 50 orders = [N for i in range(nparam)] interp = piff.Polynomial(orders=orders, poly_type=type1) X = 10.0 # size of the field Y = 10.0 pos = [(np_rng.random_sample() * X, np_rng.random_sample() * Y) for i in range(nstars)] # Let's make a function that is linear just as a function of one parameter # These are the linear fit parameters for each parameter in turn m1 = np_rng.uniform(size=nparam) m2 = np_rng.uniform(size=nparam) c = np_rng.uniform(size=nparam) def linear_func(pos): u = pos[0] v = pos[1] r = m1 * u + m2 * v + c return r # Simulate the vectors under this model vectors = [linear_func(p) for p in pos] # Fit them. Linear fitting is quite easy so this should be okay data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos] fit = [piff.StarFit(v) for v in vectors] stars = [piff.Star(d, f) for d, f in zip(data, fit)] interp.solve(stars) # Check that the interpolation recovers the desired function for i in range(30): p = (np_rng.random_sample() * X, np_rng.random_sample() * Y) target = piff.Star.makeTarget(u=p[0], v=p[1]) target = interp.interpolate(target) np.testing.assert_almost_equal(linear_func(p), target.fit.params) # Now test running it via the config parser config = { 'interp': { 'type': 'Polynomial', 'order': 1, } } logger = piff.config.setup_logger() interp = piff.Interp.process(config['interp'], logger) interp.solve(stars) np.testing.assert_almost_equal(linear_func(p), target.fit.params)
def sub_poly_quadratic(type1): # This is basically the same as linear but with # quadratic variation np_rng = np.random.RandomState(1234) nparam = 3 N = 2 nstars = 50 orders = [N for i in range(nparam)] interp = piff.Polynomial(N, poly_type=type1) X = 10.0 # size of the field Y = 10.0 pos = [(np_rng.random_sample() * X, np_rng.random_sample() * Y) for i in range(nstars)] # Let's make a function that is linear just as a function of one parameter # These are the linear fit parameters for each parameter in turn m1 = np_rng.uniform(size=nparam) m2 = np_rng.uniform(size=nparam) q1 = np_rng.uniform(size=nparam) c = np_rng.uniform(size=nparam) def quadratic_func(pos): u = pos[0] v = pos[1] r = q1 * u * v + m1 * u + m2 * v + c return r # Simulate the vectors under this model vectors = [quadratic_func(p) for p in pos] # Fit them. data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos] fit = [piff.StarFit(v) for v in vectors] stars = [piff.Star(d, f) for d, f in zip(data, fit)] interp.solve(stars) # Check that the interpolation recovers the desired function for i in range(30): p = (np_rng.random_sample() * X, np_rng.random_sample() * Y) target = piff.Star.makeTarget(u=p[0], v=p[1]) target = interp.interpolate(target) np.testing.assert_almost_equal(quadratic_func(p), target.fit.params) # Now test running it via the config parser config = { 'interp': { 'type': 'Polynomial', 'order': 2, } } logger = piff.config.setup_logger() interp = piff.Interp.process(config['interp'], logger) interp.solve(stars) np.testing.assert_almost_equal(quadratic_func(p), target.fit.params)
def test_poly_raise(): # Test that we can serialize and deserialize a polynomial # interpolator correctly. Copying all this stuff from above: np_rng = np.random.RandomState(1234) nparam = 3 nstars = 50 # Use three different sizes to test everything orders = [1, 2, 3] interp = piff.Polynomial(orders=orders) pos = [(np_rng.random_sample() * 10, np_rng.random_sample() * 10) for i in range(nstars)] #use the wrong number of parameters here so that we raise an error vectors = [np_rng.random_sample(size=nparam + 1) for i in range(nstars)] data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos] fit = [piff.StarFit(v) for v in vectors] stars = [piff.Star(d, f) for d, f in zip(data, fit)] try: np.testing.assert_raises(ValueError, interp.solve, stars) except ImportError: pass
def test_poly_guess(): # test that our initial guess gives us a flat function given # by the mean np_rng = np.random.RandomState(1234) N = 2 X = 10.0 Y = 10.0 nstars = 50 nparam = 10 interp = piff.Polynomial(N) pos = [(np_rng.random_sample() * X, np_rng.random_sample() * Y) for i in range(nstars)] interp._setup_indices(nparam) for i in range(nparam): param = np_rng.random_sample(size=nstars) p0 = interp._initialGuess(pos, param, i) mu = param.mean() assert np.isclose(p0[0, 0], mu) np.testing.assert_array_equal(p0[0, 1:], 0.0) np.testing.assert_array_equal(p0[1, 0], 0.0) np.testing.assert_array_equal(p0[1:, 1:], 0.0) np.testing.assert_almost_equal(interp._interpolationModel(pos, p0), mu)
def test_poly_raise(): # Test that we can serialize and deserialize a polynomial # interpolator correctly. Copying all this stuff from above: np_rng = np.random.RandomState(1234) nparam = 3 nstars = 50 # Use three different sizes to test everything orders = [1, 2, 3] interp = piff.Polynomial(orders=orders) pos = [(np_rng.random_sample() * 10, np_rng.random_sample() * 10) for i in range(nstars)] #use the wrong number of parameters here so that we raise an error vectors = [np_rng.random_sample(size=nparam + 1) for i in range(nstars)] data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos] fit = [piff.StarFit(v) for v in vectors] stars = [piff.Star(d, f) for d, f in zip(data, fit)] np.testing.assert_raises(ValueError, interp.solve, stars) # Invalid construction np.testing.assert_raises(TypeError, piff.Polynomial) np.testing.assert_raises(TypeError, piff.Polynomial, order=3, orders=[1, 2, 3]) np.testing.assert_raises(ValueError, piff.Polynomial, order=3, poly_type='invalid') # Cannot write before running fit. filename = 'output/test_invalid.fits' with fitsio.FITS(filename, 'rw', clobber=True) as f: with np.testing.assert_raises(RuntimeError): interp.write(f, extname='junk')
def test_missing(): """Next: fit mean PSF to multiple images, with missing pixels. """ if __name__ == '__main__': fiducial_list = [ fiducial_gaussian, fiducial_kolmogorov, fiducial_moffat ] else: fiducial_list = [fiducial_moffat] for fiducial in fiducial_list: print() print("fiducial = ", fiducial) print() mod = piff.GSObjectModel(fiducial, include_pixel=False) g1 = g2 = u0 = v0 = 0.0 # Draw stars on a 2d grid of "focal plane" with 0<=u,v<=1 positions = np.linspace(0., 1., 4) influx = 150. stars = [] np_rng = np.random.RandomState(1234) rng = galsim.BaseDeviate(1234) for u in positions: for v in positions: # Draw stars in focal plane positions around a unit ring s = make_data(fiducial, 1.0, g1, g2, u0, v0, influx, noise=0.1, pix_scale=0.5, fpu=u, fpv=v, rng=rng, include_pixel=False) s = mod.initialize(s) # Kill 10% of each star's pixels bad = np_rng.rand(*s.image.array.shape) < 0.1 s.weight.array[bad] = 0. s.image.array[bad] = -999. s = mod.reflux(s, fit_center=False) # Start with a sensible flux stars.append(s) # Also store away a noiseless copy of the PSF, origin of focal plane s0 = make_data(fiducial, 1.0, g1, g2, u0, v0, influx, pix_scale=0.5, include_pixel=False) s0 = mod.initialize(s0) interp = piff.Polynomial(order=0) interp.initialize(stars) oldchisq = 0. # Iterate solution using interpolator for iteration in range(40): # Refit PSFs star by star: for i, s in enumerate(stars): stars[i] = mod.fit(s) # Run the interpolator interp.solve(stars) # Install interpolator solution into each # star, recalculate flux, report chisq chisq = 0. dof = 0 for i, s in enumerate(stars): s = interp.interpolate(s) s = mod.reflux(s) chisq += s.fit.chisq dof += s.fit.dof stars[i] = s ###print(' chisq=',s.fit.chisq, 'dof=',s.fit.dof) print('iteration', iteration, 'chisq=', chisq, 'dof=', dof) if oldchisq > 0 and chisq < oldchisq and oldchisq - chisq < dof / 10.: break else: oldchisq = chisq # Now use the interpolator to produce a noiseless rendering s1 = interp.interpolate(s0) s1 = mod.reflux(s1) print('Flux, ctr after interpolation: ', s1.fit.flux, s1.fit.center, s1.fit.chisq) # Less than 2 dp of accuracy here! np.testing.assert_almost_equal(s1.fit.flux / influx, 1.0, decimal=3) s1 = mod.draw(s1) print('max image abs diff = ', np.max(np.abs(s1.image.array - s0.image.array))) print('max image abs value = ', np.max(np.abs(s0.image.array))) peak = np.max(np.abs(s0.image.array)) np.testing.assert_almost_equal(s1.image.array / peak, s0.image.array / peak, decimal=3)
def test_gradient_center(): """Next: fit spatially-varying PSF, with spatially-varying centers to multiple images. """ if __name__ == '__main__': fiducial_list = [ fiducial_gaussian, fiducial_kolmogorov, fiducial_moffat ] else: fiducial_list = [fiducial_moffat] for fiducial in fiducial_list: print() print("fiducial = ", fiducial) print() mod = piff.GSObjectModel(fiducial, include_pixel=False) # Interpolator will be linear interp = piff.Polynomial(order=1) # Draw stars on a 2d grid of "focal plane" with 0<=u,v<=1 positions = np.linspace(0., 1., 4) influx = 150. stars = [] rng = galsim.BaseDeviate(1234) for u in positions: # Put gradient in pixel size for v in positions: # Draw stars in focal plane positions around a unit ring # spatially-varying fwhm, g1, g2. s = make_data(fiducial, 1.0 + u * 0.1 + 0.1 * v, 0.1 * u, 0.1 * v, 0.5 * u, 0.5 * v, influx, noise=0.1, pix_scale=0.5, fpu=u, fpv=v, rng=rng, include_pixel=False) s = mod.initialize(s) stars.append(s) # import matplotlib.pyplot as plt # fig, axes = plt.subplots(4, 4) # for star, ax in zip(stars, axes.ravel()): # ax.imshow(star.data.image.array) # plt.show() # Also store away a noiseless copy of the PSF, origin of focal plane s0 = make_data(fiducial, 1.0, 0., 0., 0., 0., influx, pix_scale=0.5, include_pixel=False) s0 = mod.initialize(s0) # Polynomial doesn't need this, but it should work nonetheless. interp.initialize(stars) oldchisq = 0. # Iterate solution using interpolator for iteration in range(40): # Refit PSFs star by star: for i, s in enumerate(stars): stars[i] = mod.fit(s) # Run the interpolator interp.solve(stars) # Install interpolator solution into each # star, recalculate flux, report chisq chisq = 0. dof = 0 for i, s in enumerate(stars): s = interp.interpolate(s) s = mod.reflux(s) chisq += s.fit.chisq dof += s.fit.dof stars[i] = s ###print(' chisq=',s.fit.chisq, 'dof=',s.fit.dof) print('iteration', iteration, 'chisq=', chisq, 'dof=', dof) if oldchisq > 0 and np.abs(oldchisq - chisq) < dof / 10.: break else: oldchisq = chisq for i, s in enumerate(stars): print(i, s.fit.center, s.fit.params[0:2]) # Now use the interpolator to produce a noiseless rendering s1 = interp.interpolate(s0) s1 = mod.reflux(s1) print('Flux, ctr, chisq after interpolation: ', s1.fit.flux, s1.fit.center, s1.fit.chisq) # Less than 2 dp of accuracy here! np.testing.assert_almost_equal(s1.fit.flux / influx, 1.0, decimal=2) s1 = mod.draw(s1) print('max image abs diff = ', np.max(np.abs(s1.image.array - s0.image.array))) print('max image abs value = ', np.max(np.abs(s0.image.array))) peak = np.max(np.abs(s0.image.array)) np.testing.assert_almost_equal(s1.image.array / peak, s0.image.array / peak, decimal=2)
def test_twodstats(): """Make sure we can execute and print a readout of the plot """ if __name__ == '__main__': logger = piff.config.setup_logger(2) else: logger = None model = piff.Gaussian(fastfit=True) interp = piff.Polynomial(order=1) # should find that order=1 is better # create background model stars, true_model = generate_starlist(100) psf = piff.SimplePSF(model, interp) psf.fit(stars, None, None) stars = psf.stars # These have the right fit parameters # check the coeffs of sigma and g2, which are actually linear fits # skip g1 since it is actually a 2d parabola # factor of 0.263 is to account for going from pixel xy to wcs uv np.testing.assert_almost_equal(psf.interp.coeffs[0].flatten(), np.array([0.4, 0, 1. / (0.263 * 2048), 0]), decimal=4) np.testing.assert_almost_equal( psf.interp.coeffs[2].flatten(), np.array([-0.1 * 1000 / 2048, 0, 0.1 / (0.263 * 2048), 0]), decimal=4) stats = piff.TwoDHistStats(nbins_u=5, nbins_v=5) # implicitly np.median stats.compute(psf, stars, logger=logger) # check the twodhists # get the average value in the bin u_i = 3 v_i = 3 icen = stats.twodhists['u'][v_i, u_i] / 0.263 jcen = stats.twodhists['v'][v_i, u_i] / 0.263 print('icen = ', icen) print('jcen = ', jcen) icenter = 1000 jcenter = 2000 # the average value in the bin should match up with the model for the average coordinates sigma, g1, g2 = psf_model(icen, jcen, icenter, jcenter) sigma_average = stats.twodhists['T'][v_i, u_i] g1_average = stats.twodhists['g1'][v_i, u_i] g2_average = stats.twodhists['g2'][v_i, u_i] # assert equal to 4th decimal print('sigma, g1, g2 = ', [sigma, g1, g2]) print('av sigma, g1, g2 = ', [sigma_average, g1_average, g2_average]) np.testing.assert_almost_equal([sigma, g1, g2], [sigma_average, g1_average, g2_average], decimal=2) # Test the plotting and writing twodstats_file = os.path.join('output', 'twodstats.pdf') stats.write(twodstats_file) with np.testing.assert_raises(ValueError): stats.write() # If not given in constructor, must give file name here. # repeat for whisker stats = piff.WhiskerStats(nbins_u=21, nbins_v=21, reducing_function='np.mean') stats.compute(psf, stars) # Test the plotting and writing whisker_file = os.path.join('output', 'whiskerstats.pdf') stats.write(whisker_file) with np.testing.assert_raises(ValueError): stats.write() # With large number of bins, many will have no objects. This is ok. # Also, can use other np functions like max, std, instead to get different stats # Not sure when these would be useful, but they are allowed. # And, check usage where file_name is given in init. twodstats_file2 = os.path.join('output', 'twodstats.pdf') stats2 = piff.TwoDHistStats(nbins_u=50, nbins_v=50, reducing_function='np.std', file_name=twodstats_file2) with np.testing.assert_raises(RuntimeError): stats2.write() # Cannot write before compute stats2.compute(psf, stars, logger=logger) stats2.write() whisker_file2 = os.path.join('output', 'whiskerstats.pdf') stats2 = piff.WhiskerStats(nbins_u=100, nbins_v=100, reducing_function='np.max', file_name=whisker_file2) with np.testing.assert_raises(RuntimeError): stats2.write() # Cannot write before compute stats2.compute(psf, stars) stats2.write()
def test_interp(): """First test of use with interpolator. Make a bunch of noisy versions of the same PSF, interpolate them with constant interp to get an average PSF """ influx = 150. if __name__ == '__main__': fiducial_list = [ fiducial_gaussian, fiducial_kolmogorov, fiducial_moffat ] niter = 3 npos = 10 else: fiducial_list = [fiducial_moffat] niter = 1 # Not actually any need for interating in this case. npos = 4 for fiducial in fiducial_list: print() print("fiducial = ", fiducial) print() mod = piff.GSObjectModel(fiducial, include_pixel=False) g1 = g2 = u0 = v0 = 0.0 # Interpolator will be simple mean interp = piff.Polynomial(order=0) # Draw stars on a 2d grid of "focal plane" with 0<=u,v<=1 positions = np.linspace(0., 1., npos) stars = [] rng = galsim.BaseDeviate(1234) for u in positions: for v in positions: s = make_data(fiducial, 1.0, g1, g2, u0, v0, influx, noise=0.1, pix_scale=0.5, fpu=u, fpv=v, rng=rng, include_pixel=False) s = mod.initialize(s) stars.append(s) # Also store away a noiseless copy of the PSF, origin of focal plane s0 = make_data(fiducial, 1.0, g1, g2, u0, v0, influx, pix_scale=0.5, include_pixel=False) s0 = mod.initialize(s0) # Polynomial doesn't need this, but it should work nonetheless. interp.initialize(stars) # Iterate solution using interpolator for iteration in range(niter): # Refit PSFs star by star: for i, s in enumerate(stars): stars[i] = mod.fit(s) # Run the interpolator interp.solve(stars) # Install interpolator solution into each # star, recalculate flux, report chisq chisq = 0. dof = 0 for i, s in enumerate(stars): s = interp.interpolate(s) s = mod.reflux(s) chisq += s.fit.chisq dof += s.fit.dof stars[i] = s print('iteration', iteration, 'chisq=', chisq, 'dof=', dof) # Now use the interpolator to produce a noiseless rendering s1 = interp.interpolate(s0) s1 = mod.reflux(s1) print('Flux, ctr, chisq after interpolation: ', s1.fit.flux, s1.fit.center, s1.fit.chisq) np.testing.assert_almost_equal(s1.fit.flux / influx, 1.0, decimal=3) s1 = mod.draw(s1) print('max image abs diff = ', np.max(np.abs(s1.image.array - s0.image.array))) print('max image abs value = ', np.max(np.abs(s0.image.array))) peak = np.max(np.abs(s0.image.array)) np.testing.assert_almost_equal(s1.image.array / peak, s0.image.array / peak, decimal=3)
def test_missing(): """Next: fit mean PSF to multiple images, with missing pixels. """ # Pixelized model with Lanczos 3 interpolation, slightly smaller than data # than the data pixinterp = piff.Lanczos(3) mod = piff.PixelGrid(0.5, 25, pixinterp, start_sigma=1.5, force_model_center=False) # Draw stars on a 2d grid of "focal plane" with 0<=u,v<=1 positions = np.linspace(0., 1., 4) influx = 150. stars = [] np_rng = np.random.RandomState(1234) rng = galsim.BaseDeviate(1234) for u in positions: for v in positions: # Draw stars in focal plane positions around a unit ring s = make_gaussian_data(1.0, 0., 0., influx, noise=0.1, du=0.5, fpu=u, fpv=v, rng=rng) s = mod.initialize(s) # Kill 10% of each star's pixels bad = np_rng.rand(*s.image.array.shape) < 0.1 s.weight.array[bad] = 0. s.image.array[bad] = -999. s = mod.reflux(s, fit_center=False) # Start with a sensible flux stars.append(s) # Also store away a noiseless copy of the PSF, origin of focal plane s0 = make_gaussian_data(1.0, 0., 0., influx, du=0.5) s0 = mod.initialize(s0) if __name__ == "__main__": interps = [piff.Polynomial(order=0), piff.BasisPolynomial(order=0)] else: # The Polynomial interpolator works, but it's slow. For the nosetests runs, skip it. interps = [piff.BasisPolynomial(order=0)] for interp in interps: # Interpolator will be simple mean interp = piff.Polynomial(order=0) interp.initialize(stars) oldchisq = 0. # Iterate solution using interpolator for iteration in range(40): # Refit PSFs star by star: for i, s in enumerate(stars): stars[i] = mod.fit(s) # Run the interpolator interp.solve(stars) # Install interpolator solution into each # star, recalculate flux, report chisq chisq = 0. dof = 0 for i, s in enumerate(stars): s = interp.interpolate(s) s = mod.reflux(s) chisq += s.fit.chisq dof += s.fit.dof stars[i] = s ###print(' chisq=',s.fit.chisq, 'dof=',s.fit.dof) print('iteration', iteration, 'chisq=', chisq, 'dof=', dof) if oldchisq > 0 and chisq < oldchisq and oldchisq - chisq < dof / 10.: break else: oldchisq = chisq # Now use the interpolator to produce a noiseless rendering s1 = interp.interpolate(s0) s1 = mod.reflux(s1) print('Flux, ctr after interpolation: ', s1.fit.flux, s1.fit.center, s1.fit.chisq) # Less than 2 dp of accuracy here! np.testing.assert_almost_equal(s1.fit.flux / influx, 1.0, decimal=1) s1 = mod.draw(s1) print('max image abs diff = ', np.max(np.abs(s1.image.array - s0.image.array))) print('max image abs value = ', np.max(np.abs(s0.image.array))) peak = np.max(np.abs(s0.image.array)) np.testing.assert_almost_equal(s1.image.array / peak, s0.image.array / peak, decimal=1)
def test_gradient(): """Next: fit spatially-varying PSF to multiple images. """ # Pixelized model with Lanczos 3 interpolation, slightly smaller than data # than the data pixinterp = piff.Lanczos(3) mod = piff.PixelGrid(0.5, 25, pixinterp, start_sigma=1.5, degenerate=False, force_model_center=False) # Interpolator will be linear interp = piff.Polynomial(order=1) # Draw stars on a 2d grid of "focal plane" with 0<=u,v<=1 positions = np.linspace(0., 1., 4) influx = 150. stars = [] rng = galsim.BaseDeviate(1234) for u in positions: # Put gradient in pixel size for v in positions: # Draw stars in focal plane positions around a unit ring s = make_gaussian_data(1.0 + u * 0.1, 0., 0., influx, noise=0.1, du=0.5, fpu=u, fpv=v, rng=rng) s = mod.initialize(s) stars.append(s) # Also store away a noiseless copy of the PSF, origin of focal plane s0 = make_gaussian_data(1.0, 0., 0., influx, du=0.5) s0 = mod.initialize(s0) # Polynomial doesn't need this, but it should work nonetheless. interp.initialize(stars) oldchisq = 0. # Iterate solution using interpolator for iteration in range(40): # Refit PSFs star by star: for i, s in enumerate(stars): stars[i] = mod.fit(s) # Run the interpolator interp.solve(stars) # Install interpolator solution into each # star, recalculate flux, report chisq chisq = 0. dof = 0 for i, s in enumerate(stars): s = interp.interpolate(s) s = mod.reflux(s) chisq += s.fit.chisq dof += s.fit.dof stars[i] = s ###print(' chisq=',s.fit.chisq, 'dof=',s.fit.dof) print('iteration', iteration, 'chisq=', chisq, 'dof=', dof) if oldchisq > 0 and np.abs(oldchisq - chisq) < dof / 10.: break else: oldchisq = chisq # Now use the interpolator to produce a noiseless rendering s1 = interp.interpolate(s0) s1 = mod.reflux(s1) print('Flux, ctr after interpolation: ', s1.fit.flux, s1.fit.center, s1.fit.chisq) # Less than 2 dp of accuracy here! np.testing.assert_almost_equal(s1.fit.flux / influx, 1.0, decimal=1) s1 = mod.draw(s1) print('max image abs diff = ', np.max(np.abs(s1.image.array - s0.image.array))) print('max image abs value = ', np.max(np.abs(s0.image.array))) peak = np.max(np.abs(s0.image.array)) np.testing.assert_almost_equal(s1.image.array / peak, s0.image.array / peak, decimal=1)
def poly_load_save_sub(type1, type2, fname): # Test that we can serialize and deserialize a polynomial # interpolator correctly. Copying all this stuff from above: np_rng = np.random.RandomState(1234) nparam = 3 nstars = 50 # Use three different sizes to test everything orders = [1, 2, 3] interp = piff.Polynomial(orders=orders, poly_type=type1) X = 10.0 # size of the field Y = 10.0 pos = [(np_rng.random_sample() * X, np_rng.random_sample() * Y) for i in range(nstars)] # Let's make a function that is linear just as a function of one parameter # These are the linear fit parameters for each parameter in turn m1 = np_rng.uniform(size=nparam) m2 = np_rng.uniform(size=nparam) q1 = np_rng.uniform(size=nparam) c = np_rng.uniform(size=nparam) def quadratic_func(pos): u = pos[0] v = pos[1] r = q1 * u * v + m1 * u + m2 * v + c return r # Simulate the vectors under this model vectors = [quadratic_func(p) for p in pos] # Fit them! data = [piff.Star.makeTarget(u=p[0], v=p[1]).data for p in pos] fit = [piff.StarFit(v) for v in vectors] stars = [piff.Star(d, f) for d, f in zip(data, fit)] interp.solve(stars) import tempfile import os import fitsio extname = "interp" dirname = 'output' filename = os.path.join(dirname, fname) with fitsio.FITS(filename, 'rw', clobber=True) as f: interp.write(f, extname=extname) with fitsio.FITS(filename, "r") as f2: interp2 = piff.Polynomial.read(f2, extname=extname) # The type and other parameters should now have been overwritten and updated assert interp2.poly_type == interp.poly_type assert interp2.order == interp.order np.testing.assert_array_equal(interp2.orders, interp.orders) assert interp2.nvariables == interp.nvariables np.testing.assert_array_equal(interp2.indices, interp.indices) # Check that the old and new interpolators generate the same # value for i in range(30): p = (np_rng.random_sample() * X, np_rng.random_sample() * Y) target = piff.Star.makeTarget(u=p[0], v=p[1]) target1 = interp.interpolate(target) target2 = interp.interpolate(target) np.testing.assert_almost_equal(target1.fit.params, target2.fit.params)
def test_interp(): """First test of use with interpolator. Make a bunch of noisy versions of the same PSF, interpolate them with constant interp to get an average PSF """ # Pixelized model with Lanczos 3 interpolation, slightly smaller than data # than the data pixinterp = piff.Lanczos(3) mod = piff.PixelGrid(0.5, 25, pixinterp, start_sigma=1.5, degenerate=False) # Interpolator will be simple mean interp = piff.Polynomial(order=0) # Draw stars on a 2d grid of "focal plane" with 0<=u,v<=1 positions = np.linspace(0., 1., 10.) influx = 150. stars = [] rng = galsim.BaseDeviate(1234) for u in positions: for v in positions: # Draw stars in focal plane positions around a unit ring s = make_gaussian_data(1.0, 0., 0., influx, noise=0.1, du=0.5, fpu=u, fpv=v, rng=rng) s = mod.initialize(s) stars.append(s) # Also store away a noiseless copy of the PSF, origin of focal plane s0 = make_gaussian_data(1.0, 0., 0., influx, du=0.5) s0 = mod.initialize(s0) # Polynomial doesn't need this, but it should work nonetheless. interp.initialize(stars) # Iterate solution using interpolator for iteration in range(3): # Refit PSFs star by star: for i, s in enumerate(stars): stars[i] = mod.fit(s) # Run the interpolator interp.solve(stars) # Install interpolator solution into each # star, recalculate flux, report chisq chisq = 0. dof = 0 for i, s in enumerate(stars): s = interp.interpolate(s) s = mod.reflux(s) chisq += s.fit.chisq dof += s.fit.dof stars[i] = s print('iteration', iteration, 'chisq=', chisq, 'dof=', dof) # Now use the interpolator to produce a noiseless rendering s1 = interp.interpolate(s0) s1 = mod.reflux(s1) print('Flux, ctr after interpolation: ', s1.fit.flux, s1.fit.center, s1.fit.chisq) np.testing.assert_almost_equal(s1.fit.flux / influx, 1.0, decimal=2) s1 = mod.draw(s1) print('max image abs diff = ', np.max(np.abs(s1.image.array - s0.image.array))) print('max image abs value = ', np.max(np.abs(s0.image.array))) peak = np.max(np.abs(s0.image.array)) np.testing.assert_almost_equal(s1.image.array / peak, s0.image.array / peak, decimal=2)
def test_undersamp(): """Next: fit PSF to undersampled, dithered data with fixed centroids ***Doesn't work well! Need to work on the SV pruning*** """ # Pixelized model with Lanczos 3 interpolation, slightly smaller than data # than the data pixinterp = piff.Lanczos(3) du = 0.5 mod = piff.PixelGrid(0.25, 25, pixinterp, start_sigma=1.01) ##,force_model_center=True) # Interpolator will be constant interp = piff.Polynomial(order=0) # Draw stars on a 2d grid of "focal plane" with 0<=u,v<=1 positions = np.linspace(0., 1., 4) influx = 150. stars = [] np_rng = np.random.RandomState(1234) rng = galsim.BaseDeviate(1234) for u in positions: for v in positions: # Dither centers by 1 pixel phase = (0.5 - np_rng.rand(2)) * du if u == 0. and v == 0.: phase = (0., 0.) s = make_gaussian_data(1.0, 0., 0., influx, noise=0.1, du=du, fpu=u, fpv=v, nom_u0=phase[0], nom_v0=phase[1], rng=rng) s = mod.initialize(s) print("phase:", phase, 'flux', s.fit.flux) stars.append(s) # Also store away a noiseless copy of the PSF, origin of focal plane s0 = make_gaussian_data(1.0, 0., 0., influx, du=0.5) s0 = mod.initialize(s0) # Polynomial doesn't need this, but it should work nonetheless. interp.initialize(stars) oldchisq = 0. # Iterate solution using interpolator for iteration in range(1): ### # Refit PSFs star by star: stars = [mod.fit(s) for s in stars] # Run the interpolator interp.solve(stars) # Install interpolator solution into each # star, recalculate flux, report chisq chisq = 0. dof = 0 for i, s in enumerate(stars): s = interp.interpolate(s) s = mod.reflux(s) chisq += s.fit.chisq dof += s.fit.dof stars[i] = s print(' chisq=', s.fit.chisq, 'dof=', s.fit.dof, 'flux=', s.fit.flux) print('iteration', iteration, 'chisq=', chisq, 'dof=', dof) if oldchisq > 0 and np.abs(oldchisq - chisq) < dof / 10.: break else: oldchisq = chisq # Now use the interpolator to produce a noiseless rendering s1 = interp.interpolate(s0) s1 = mod.reflux(s1) print('Flux, ctr after interpolation: ', s1.fit.flux, s1.fit.center, s1.fit.chisq) # Less than 2 dp of accuracy here! np.testing.assert_almost_equal(s1.fit.flux / influx, 1.0, decimal=1) s1 = mod.draw(s1) print('max image abs diff = ', np.max(np.abs(s1.image.array - s0.image.array))) print('max image abs value = ', np.max(np.abs(s0.image.array))) peak = np.max(np.abs(s0.image.array)) np.testing.assert_almost_equal(s1.image.array / peak, s0.image.array / peak, decimal=1)