Beispiel #1
0
    def _set_wcs_choose(self, jacobian, **kw):
        """
        create a galsim JacobianWCS from the input ngmix.Jacobian, as
        well as pixel objects
        """

        self.jacobian=jacobian
        wcs_convention=kw.get("wcs_convention",None)
        logger.debug("        wcs convention: %s" % wcs_convention)

        if wcs_convention==1:
            self.gs_wcs = galsim.JacobianWCS(jacobian.dudrow,
                                             jacobian.dudcol,
                                             jacobian.dvdrow,
                                             jacobian.dvdcol)
        elif wcs_convention==2:
            self.gs_wcs = galsim.JacobianWCS(jacobian.dudcol,
                                             jacobian.dudrow,
                                             jacobian.dvdcol,
                                             jacobian.dvdrow)

        elif wcs_convention==3:
            self.gs_wcs = galsim.JacobianWCS(jacobian.dvdcol,
                                             jacobian.dvdrow,
                                             jacobian.dudcol,
                                             jacobian.dudrow)
        else:
            raise ValueError("bad wcs_convention: %s" % wcs_convention)
Beispiel #2
0
def exposures():
	# Obtain observation list, psf list, weight from wfirst_simple_sim.py
	gals_array=[fio.FITS('mcal_gal_0.fits')[-1].read(), fio.FITS('mcal_gal_1.fits')[-1].read()]
	psfs_array=[fio.FITS('mcal_psf_0.fits')[-1].read(), fio.FITS('mcal_psf_1.fits')[-1].read()]
	offsets=[galsim.PositionD(-0.5,-0.5), galsim.PositionD(0.48010974293083564,0.24526554339263384)]
	skys_array=[fio.FITS('mcal_sky_0.fits')[-1].read(), fio.FITS('mcal_sky_1.fits')[-1].read()]
	gal_true=[galsim.PositionD(31.5,31.5), galsim.PositionD(31.5,31.5)]
	gal_jacobs=[galsim.JacobianWCS(0.10379201786865774, -0.037313406917181026, 0.03741492083530528, 0.1017841347351108), 
				galsim.JacobianWCS(0.04693577579580337, -0.09835662875798407, 0.09984826919988712, 0.045587756760917426)]

	obs_list, psf_list, w = get_exp_list(gals_array, psfs_array, offsets, skys_array, gal_true, gal_jacobs, psf2=None)
	return obs_list,psf_list,np.array(w)
Beispiel #3
0
 def construct_image(self, band_index, uniform_deviate):
     world_origin = self.image_parameters.world_origin.as_galsim_position()
     degrees_per_pixel = self.image_parameters.degrees_per_pixel()
     wcs = (
         # Here we implement the confusing mapping X <-> Dec, Y <-> RA
         galsim.JacobianWCS(0, degrees_per_pixel, degrees_per_pixel,
                            0).withOrigin(galsim.PositionI(0, 0),
                                          world_origin=world_origin))
     image = galsim.ImageF(
         self.image_parameters.width_px,
         self.image_parameters.height_px,
         wcs=wcs,
     )
     for index, light_source in enumerate(self._light_sources):
         sys.stdout.write('Band {} source {}\r'.format(
             band_index + 1, index + 1))
         sys.stdout.flush()
         galsim_light_source = light_source.get_galsim_light_source(
             band_index,
             self.psf_sigma_pixels *
             self.image_parameters.degrees_per_pixel(),
             self.image_parameters,
         )
         galsim_light_source.drawImage(
             image,
             add_to_image=True,
             method='phot',
             max_extra_noise=self.band_sky_level_nmgy[band_index] *
             self.image_parameters.band_nelec_per_nmgy[band_index] / 1000.0,
             rng=uniform_deviate,
         )
     self._add_sky_background(image, band_index, uniform_deviate)
     return image
Beispiel #4
0
def test_wcs():
    """Reproduce an error Erin found and reported in #834.  This was never an error in a released
    version, just temporarily on master, but the mistake hadn't been caught by any of our unit
    tests, so this test catches the error.
    """
    wcs = galsim.JacobianWCS(0.01, -0.26, -0.28, -0.03)
    gal = galsim.Exponential(half_light_radius=1.1, flux=237)
    psf = galsim.Moffat(beta=3.5, half_light_radius=0.9)
    obs = galsim.Convolve(gal, psf)

    obs_im = obs.drawImage(nx=32, ny=32, offset=(0.3, -0.2), wcs=wcs)
    psf_im = psf.drawImage(nx=32, ny=32, wcs=wcs)

    ii = galsim.InterpolatedImage(obs_im)
    psf_ii = galsim.InterpolatedImage(psf_im)
    psf_inv = galsim.Deconvolve(psf_ii)

    ii_nopsf = galsim.Convolve(ii, psf_inv)

    newpsf = galsim.Moffat(beta=3.5, half_light_radius=0.95)
    newpsf = newpsf.dilate(1.02)

    new_ii = ii_nopsf.shear(g1=0.01, g2=0.0)
    new_ii = galsim.Convolve(new_ii, newpsf)

    new_im = new_ii.drawImage(image=obs_im.copy(), method='no_pixel')
    np.testing.assert_almost_equal(new_im.array.sum() / 237,
                                   obs_im.array.sum() / 237,
                                   decimal=1)
Beispiel #5
0
 def __str__(self):
     s = str(self.original)
     dudx, dudy, dvdx, dvdy = self.jac.flatten()
     if dudx != 1 or dudy != 0 or dvdx != 0 or dvdy != 1:
         # Figure out the shear/rotate/dilate calls that are equivalent.
         jac = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)
         scale, shear, theta, flip = jac.getDecomposition()
         single = None
         if flip:
             single = 0  # Special value indicating to just use transform.
         if abs(theta.rad()) > 1.e-12:
             if single is None:
                 single = '.rotate(%s)' % theta
             else:
                 single = 0
         if shear.getG() > 1.e-12:
             if single is None:
                 single = '.shear(%s)' % shear
             else:
                 single = 0
         if abs(scale - 1.0) > 1.e-12:
             if single is None:
                 single = '.expand(%s)' % scale
             else:
                 single = 0
         if single == 0:
             # If flip or there are two components, then revert to transform as simpler.
             single = '.transform(%s,%s,%s,%s)' % (dudx, dudy, dvdx, dvdy)
         s += single
     if self.offset.x != 0 or self.offset.y != 0:
         s += '.shift(%s,%s)' % (self.offset.x, self.offset.y)
     if self.flux_ratio != 1.:
         #s += '.withScaledFlux(%s)'%self.flux_ratio
         s += ' * %s' % self.flux_ratio
     return s
Beispiel #6
0
def test_decam_wavefront():
    file_name = 'input/Science-20121120s1-v20i2.fits'
    extname = 'Science-20121120s1-v20i2'

    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_decam.log')
    knn = piff.des.DECamWavefront(file_name, extname, logger=logger)

    n_samples = 2000
    np_rng = np.random.RandomState(1234)
    ccdnums = np_rng.randint(1, 63, n_samples)

    star_list = []
    for ccdnum in ccdnums:
        # make some basic images, pass Xi as properties
        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64,64, wcs=wcs)
        # set icen and jcen
        icen = np_rng.randint(100, 2048)
        jcen = np_rng.randint(100, 4096)
        image.setCenter(icen, jcen)
        image_pos = image.center

        stardata = piff.StarData(image, image_pos, properties={'chipnum': ccdnum})

        star = piff.Star(stardata, None)
        star_list.append(star)

    # get the focal positions
    star_list = piff.des.DECamInfo().pixel_to_focalList(star_list)

    star_list_predicted = knn.interpolateList(star_list)

    # test misalignment
    misalignment = {'z04d': 10, 'z10x': 10, 'z09y': -10}
    knn.misalign_wavefront(misalignment)
    star_list_misaligned = knn.interpolateList(star_list)

    # test the prediction algorithm
    y_predicted = np.array([s.fit.params for s in star_list_predicted])
    y_misaligned = np.array([s.fit.params for s in star_list_misaligned])
    X = np.array([knn.getProperties(s) for s in star_list])

    # check the misalignments work
    np.testing.assert_array_almost_equal(y_predicted[:,0], y_misaligned[:,0] - misalignment['z04d'])
    np.testing.assert_array_almost_equal(y_predicted[:,5], y_misaligned[:,5] - misalignment['z09y'] * X[:,0])
    np.testing.assert_array_almost_equal(y_predicted[:,6], y_misaligned[:,6] - misalignment['z10x'] * X[:,1])

    # Check shape of misalignment if array
    np.testing.assert_raises(ValueError, knn.misalign_wavefront, knn.misalignment[:,:2])
    np.testing.assert_raises(ValueError, knn.misalign_wavefront, knn.misalignment[:-1,:])

    # empty dict is equivalent to no misalignment
    knn.misalign_wavefront({})
    np.testing.assert_equal(knn.misalignment, 0.)
Beispiel #7
0
def test_Gaussian():
    """This is about the simplest possible model I could think of.  It just uses the
    HSM adaptive moments routine to measure the moments, and then it models the
    PSF as a Gaussian.
    """

    # Here is the true PSF
    sigma = 1.3
    g1 = 0.23
    g2 = -0.17
    psf = galsim.Gaussian(sigma=sigma).shear(g1=g1, g2=g2)

    # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
    wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
    image = galsim.Image(64,64, wcs=wcs)
    # This is only going to come out right if we (unphysically) don't convolve by the pixel.
    psf.drawImage(image, method='no_pixel')

    # Make a StarData instance for this image
    stardata = piff.StarData(image, image.true_center)
    star = piff.Star(stardata, None)

    # Fit the model from the image
    model = piff.Gaussian(include_pixel=False)
    star = model.initialize(star)
    fit = model.fit(star).fit

    print('True sigma = ',sigma,', model sigma = ',fit.params[0])
    print('True g1 = ',g1,', model g1 = ',fit.params[1])
    print('True g2 = ',g2,', model g2 = ',fit.params[2])

    # This test is pretty accurate, since we didn't add any noise and didn't convolve by
    # the pixel, so the image is very accurately a sheared Gaussian.
    true_params = [ sigma, g1, g2 ]
    np.testing.assert_almost_equal(fit.params[0], sigma, decimal=7)
    np.testing.assert_almost_equal(fit.params[1], g1, decimal=7)
    np.testing.assert_almost_equal(fit.params[2], g2, decimal=7)
    np.testing.assert_almost_equal(fit.params, true_params, decimal=7)

    # Now test running it via the config parser
    config = {
        'model' : {
            'type' : 'Gaussian',
            'include_pixel': False
        }
    }
    if __name__ == '__main__':
        logger = piff.config.setup_logger(verbose=2)
    else:
        logger = piff.config.setup_logger(log_file='output/test_Gaussian.log')
    model = piff.Model.process(config['model'], logger)
    fit = model.fit(star).fit

    # Same tests.
    np.testing.assert_almost_equal(fit.params[0], sigma, decimal=7)
    np.testing.assert_almost_equal(fit.params[1], g1, decimal=7)
    np.testing.assert_almost_equal(fit.params[2], g2, decimal=7)
    np.testing.assert_almost_equal(fit.params, true_params, decimal=7)
Beispiel #8
0
    def get_galsim_wcs(self):
        """
        get a galsim.JacobianWCS object with the same contents as self
        """
        import galsim

        dudx = self.dudcol
        dudy = self.dudrow
        dvdx = self.dvdcol
        dvdy = self.dvdrow

        return galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)
Beispiel #9
0
def test_table_GSInterp():
    def f(x_):
        return x_ + 2 * x_ * x_ + 3 * np.sin(2 * x_)

    x = np.linspace(0.1, 3.3, 25)
    y = np.arange(
        20
    )  # Need something big enough to avoid having the interpolant fall off the edge
    yy, xx = np.meshgrid(y, x)

    interpolants = ['lanczos3', 'lanczos3F', 'lanczos7', 'sinc', 'quintic']

    for interpolant in interpolants:
        z = f(xx)

        tab = galsim.LookupTable(x, z[:, 0], interpolant=interpolant)
        do_pickle(tab)

        # Use InterpolatedImage to validate
        wcs = galsim.JacobianWCS(
            (max(x) - min(x)) / (len(x) - 1),
            0,
            0,
            (max(y) - min(y)) / (len(y) - 1),
        )
        img = galsim.Image(z.T, wcs=wcs)
        ii = galsim.InterpolatedImage(
            img,
            use_true_center=True,
            offset=(galsim.PositionD(img.xmin, img.ymin) - img.true_center),
            x_interpolant=interpolant,
            normalization='sb',
            calculate_maxk=False,
            calculate_stepk=False).shift(min(x), min(y))

        # Check single value functionality.
        x1 = 2.3
        np.testing.assert_allclose(tab(x1),
                                   ii.xValue(x1, 10),
                                   atol=1e-10,
                                   rtol=0)

        # Check vectorized output
        newx = np.linspace(0.2, 3.1, 15)
        np.testing.assert_allclose(tab(newx),
                                   np.array([ii.xValue(x_, 10)
                                             for x_ in newx]),
                                   atol=1e-10,
                                   rtol=0)
Beispiel #10
0
def test_extra_interp():
    # Test that specifying extra_interp_properties works properly
    # TODO: This is a very bare bones test of the interface.  There is basically no test of
    #       this functionality at all yet.  TBD!

    sigma = 1.3
    g1 = 0.23
    g2 = -0.17
    psf = galsim.Gaussian(sigma=sigma).shear(g1=g1, g2=g2)
    wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
    image = galsim.Image(64, 64, wcs=wcs)
    psf.drawImage(image, method='no_pixel')

    # use g-i color as an extra property for interpolation.
    props = dict(gi_color=0.3)
    print('props = ', props)
    star = piff.Star(piff.StarData(image, image.true_center, properties=props),
                     None)

    model = piff.Gaussian(fastfit=True, include_pixel=False)
    interp = piff.Mean()
    psf = piff.SimplePSF(model, interp, extra_interp_properties=['gi_color'])
    assert psf.extra_interp_properties == ['gi_color']

    # Note: Mean doesn't actually do anything useful with the extra properties, so this
    #       isn't really testing anything other than that the code doesn't completely break.
    pointing = galsim.CelestialCoord(-5 * galsim.arcmin, -25 * galsim.degrees)
    psf.fit([star], wcs={0: wcs}, pointing=pointing)

    # Not much of a check here.  Just check that it actually draws something with flux ~= 1
    im = psf.draw(x=5, y=7, gi_color=0.3)
    np.testing.assert_allclose(im.array.sum(), 1.0, rtol=1.e-3)

    # Check missing or extra properties
    with np.testing.assert_raises(TypeError):
        psf.draw(x=5, y=7)
    with np.testing.assert_raises(TypeError):
        psf.draw(x=5, y=7, gi_color=0.3, ri_color=3)

    # No stars raises an error.  (This can happen in practice if all stars are excluded on input.)
    with np.testing.assert_raises(RuntimeError):
        psf.fit([], wcs={0: wcs}, pointing=pointing)

    # Also for SingleChipPSf
    psf2 = piff.SingleChipPSF(psf, extra_interp_properties=['gi_color'])
    assert psf2.extra_interp_properties == ['gi_color']

    with np.testing.assert_raises(TypeError):
        psf2.draw(x=5, y=7, chipnum=0)
Beispiel #11
0
    def wcs_approx(self, gal_stamp, psf_stamp):
        #self.make_stamp()
        # set a simple jacobian to the stamps before sending them to ngmix
        # old center of the stamp
        origin_x = gal_stamp.origin.x
        origin_y = gal_stamp.origin.y
        gal_stamp.setOrigin(0, 0)
        psf_stamp.setOrigin(0, 0)
        new_pos = galsim.PositionD(self.xy.x - origin_x, self.xy.y - origin_y)
        wcs_transf = gal_stamp.wcs.affine(image_pos=new_pos)
        new_wcs = galsim.JacobianWCS(wcs_transf.dudx, wcs_transf.dudy,
                                     wcs_transf.dvdx, wcs_transf.dvdy)
        gal_stamp.wcs = new_wcs
        psf_stamp.wcs = new_wcs

        return gal_stamp, psf_stamp
Beispiel #12
0
    def constructModelImage(self,
                            params=None,
                            pixelScale=None,
                            jacobian=None,
                            shape=None):
        """Construct model image from parameters

        @param params      lmfit.Parameters object or python dictionary with
                           param values to use, or None to use self.params
        @param pixelScale  pixel scale in arcseconds to use for model image,
                           or None to use self.pixelScale.
        @param jacobian    An optional 2x2 Jacobian distortion matrix to apply
                           to the forward model.  Note that this is relative to
                           the pixelScale above.  Use self.jacobian if this is
                           None.
        @param shape       (nx, ny) shape for model image, or None to use
                           the shape of self.maskedImage
        @returns       numpy array image
        """
        if params is None:
            params = self.params
        if shape is None:
            shape = self.maskedImage.getImage().getArray().shape
        if pixelScale is None:
            pixelScale = self.pixelScale
        if jacobian is None:
            jacobian = self.jacobian
        try:
            v = params.valuesdict()
        except AttributeError:
            v = params

        optPsf = self._getOptPsf(v)
        if 'r0' in v:
            atmPsf = galsim.Kolmogorov(lam=self.wavelength, r0=v['r0'])
            psf = galsim.Convolve(optPsf, atmPsf)
        else:
            psf = optPsf
        psf = psf.shift(v['dx'], v['dy']) * v['flux']

        wcs = galsim.JacobianWCS(*list(pixelScale * jacobian.ravel()))
        modelImg = psf.drawImage(nx=shape[0], ny=shape[1], wcs=wcs)
        return modelImg.array
Beispiel #13
0
def generate_data(n_samples=100):
    # generate as Norm(0, 1) for all parameters
    np_rng = np.random.RandomState(1234)
    X = np_rng.normal(0, 1, size=(n_samples, len(keys)))
    y = np_rng.normal(0, 1, size=(n_samples, ntarget))

    star_list = []
    for Xi, yi in zip(X, y):
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64,64, wcs=wcs)
        properties = {k:v for k,v in zip(keys, Xi)}
        stardata = piff.StarData(image, image.true_center, properties=properties)

        # params = np.array([yi[ith] for ith in attr_target])
        params = yi
        starfit = piff.StarFit(params)
        star = piff.Star(stardata, starfit)
        star_list.append(star)

    return star_list
Beispiel #14
0
    def read(cls, fits, extname):
        """Read stars from a FITS file.

        :param fits:        An open fitsio.FITS object
        :param extname:     The name of the extension to read from

        :returns: a list of Star instances
        """
        assert extname in fits
        colnames = fits[extname].get_colnames()

        for key in [
                'x', 'y', 'u', 'v', 'dudx', 'dudy', 'dvdx', 'dvdy', 'xmin',
                'xmax', 'ymin', 'ymax', 'flux', 'center', 'chisq'
        ]:
            assert key in colnames
            colnames.remove(key)

        data = fits[extname].read()
        x_list = data['x']
        y_list = data['y']
        u_list = data['u']
        v_list = data['v']
        dudx = data['dudx']
        dudy = data['dudy']
        dvdx = data['dvdx']
        dvdy = data['dvdy']
        xmin = data['xmin']
        xmax = data['xmax']
        ymin = data['ymin']
        ymax = data['ymax']
        flux = data['flux']
        center = data['center']
        chisq = data['chisq']

        if 'params' in colnames:
            params = data['params']
            colnames.remove('params')
        else:
            params = [None] * len(data)

        if 'params_var' in colnames:
            params_var = data['params_var']
            colnames.remove('params_var')
        else:
            params_var = [None] * len(data)

        if 'point_ra' in colnames:
            pointing_list = [
                galsim.CelestialCoord(row['point_ra'] * galsim.degrees,
                                      row['point_dec'] * galsim.degrees)
                for row in data
            ]
            colnames.remove('point_ra')
            colnames.remove('point_dec')
        else:
            pointing_list = [None] * len(data)

        fit_list = [
            StarFit(p, flux=f, center=c, chisq=x, params_var=pv)
            for (p, f, c, x,
                 pv) in zip(params, flux, center, chisq, params_var)
        ]

        # The rest of the columns are the data properties
        prop_list = [{c: row[c] for c in colnames} for row in data]

        wcs_list = [
            galsim.JacobianWCS(*jac) for jac in zip(dudx, dudy, dvdx, dvdy)
        ]
        pos_list = [galsim.PositionD(*pos) for pos in zip(x_list, y_list)]
        wpos_list = [galsim.PositionD(*pos) for pos in zip(u_list, v_list)]
        wcs_list = [
            w.withOrigin(p, wp)
            for w, p, wp in zip(wcs_list, pos_list, wpos_list)
        ]
        bounds_list = [galsim.BoundsI(*b) for b in zip(xmin, xmax, ymin, ymax)]
        image_list = [
            galsim.Image(bounds=b, wcs=w)
            for b, w in zip(bounds_list, wcs_list)
        ]
        weight_list = [
            galsim.Image(init_value=1.0, bounds=b, wcs=w)
            for b, w in zip(bounds_list, wcs_list)
        ]
        data_list = [
            StarData(im, pos, weight=w, properties=prop, pointing=point)
            for im, pos, w, prop, point in zip(
                image_list, pos_list, weight_list, prop_list, pointing_list)
        ]

        stars = [Star(d, f) for (d, f) in zip(data_list, fit_list)]
        return stars
Beispiel #15
0
def test_table2d_GSInterp():
    def f(x_, y_):
        return 2 * y_ * y_ + 3 * x_ * x_ + 4 * x_ * y_ - np.cos(x_)

    x = np.linspace(0.1, 3.3, 25)
    y = np.linspace(0.2, 10.4, 75)
    yy, xx = np.meshgrid(y,
                         x)  # Note the ordering of both input and output here!

    interpolants = ['lanczos3', 'lanczos3F', 'lanczos7', 'sinc', 'quintic']

    for interpolant in interpolants:
        z = f(xx, yy)
        tab2d = galsim.LookupTable2D(x, y, z, interpolant=interpolant)
        do_pickle(tab2d)
        # Make sure precomputed-hash gets covered
        hash(tab2d)

        # Use InterpolatedImage to validate
        wcs = galsim.JacobianWCS(
            (max(x) - min(x)) / (len(x) - 1),
            0,
            0,
            (max(y) - min(y)) / (len(y) - 1),
        )
        img = galsim.Image(z.T, wcs=wcs)
        ii = galsim.InterpolatedImage(
            img,
            use_true_center=True,
            offset=(galsim.PositionD(img.xmin, img.ymin) - img.true_center),
            x_interpolant=interpolant,
            normalization='sb',
            calculate_maxk=False,
            calculate_stepk=False).shift(min(x), min(y))

        # Check single value functionality.
        x1, y1 = 2.3, 3.2
        np.testing.assert_allclose(tab2d(x1, y1),
                                   ii.xValue(x1, y1),
                                   atol=1e-10,
                                   rtol=0)

        # Check vectorized output
        newx = np.linspace(0.2, 3.1, 15)
        newy = np.linspace(0.3, 10.1, 25)
        newyy, newxx = np.meshgrid(newy, newx)
        np.testing.assert_allclose(
            tab2d(newxx, newyy).ravel(),
            np.array([
                ii.xValue(x_, y_)
                for x_, y_ in zip(newxx.ravel(), newyy.ravel())
            ]).ravel(),
            atol=1e-10,
            rtol=0)
        np.testing.assert_array_almost_equal(tab2d(newxx, newyy),
                                             tab2d(newx, newy, grid=True))

        # Check that edge_mode='wrap' works
        tab2d = galsim.LookupTable2D(x, y, z, edge_mode='wrap')

        ref_dfdx, ref_dfdy = tab2d.gradient(newxx, newyy)
        test_dfdx, test_dfdy = tab2d.gradient(newxx + 3 * tab2d.xperiod, newyy)
        np.testing.assert_array_almost_equal(ref_dfdx, test_dfdx)
        np.testing.assert_array_almost_equal(ref_dfdy, test_dfdy)

        test_dfdx, test_dfdy = tab2d.gradient(newxx,
                                              newyy + 13 * tab2d.yperiod)
        np.testing.assert_array_almost_equal(ref_dfdx, test_dfdx)
        np.testing.assert_array_almost_equal(ref_dfdy, test_dfdy)

        test_dfdx, test_dfdy = tab2d.gradient(newx,
                                              newy + 13 * tab2d.yperiod,
                                              grid=True)
        np.testing.assert_array_almost_equal(ref_dfdx, test_dfdx)
        np.testing.assert_array_almost_equal(ref_dfdy, test_dfdy)

        # Test mix of inside and outside original boundary
        test_dfdx, test_dfdy = tab2d.gradient(
            np.dstack([newxx, newxx + 3 * tab2d.xperiod]),
            np.dstack([newyy, newyy]))

        np.testing.assert_array_almost_equal(ref_dfdx, test_dfdx[:, :, 0])
        np.testing.assert_array_almost_equal(ref_dfdy, test_dfdy[:, :, 0])
        np.testing.assert_array_almost_equal(ref_dfdx, test_dfdx[:, :, 1])
        np.testing.assert_array_almost_equal(ref_dfdy, test_dfdy[:, :, 1])
 def make_jacobian(dudx, dudy, dvdx, dvdy, x, y):
     j = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)
     return j.withOrigin(galsim.PositionD(x, y))
Beispiel #17
0
def test_meds():
    """
    Create two objects, each with three exposures. Save them to a MEDS file.
    Load the MEDS file. Compare the created objects with the one read by MEDS.
    """
    # initialise empty MultiExposureObject list
    objlist = []

    # we will be using 2 objects for testing, each with 3 cutouts
    n_obj_test = 2
    n_cut_test = 3

    # set the image size
    box_size = 32

    # first obj
    img11 = galsim.Image(box_size, box_size, init_value=111)
    img12 = galsim.Image(box_size, box_size, init_value=112)
    img13 = galsim.Image(box_size, box_size, init_value=113)
    seg11 = galsim.Image(box_size, box_size, init_value=121)
    seg12 = galsim.Image(box_size, box_size, init_value=122)
    seg13 = galsim.Image(box_size, box_size, init_value=123)
    wth11 = galsim.Image(box_size, box_size, init_value=131)
    wth12 = galsim.Image(box_size, box_size, init_value=132)
    wth13 = galsim.Image(box_size, box_size, init_value=133)
    psf11 = galsim.Image(box_size, box_size, init_value=141)
    psf12 = galsim.Image(box_size, box_size, init_value=142)
    psf13 = galsim.Image(box_size, box_size, init_value=143)
    dudx = 11.1
    dudy = 11.2
    dvdx = 11.3
    dvdy = 11.4
    x0 = 11.5
    y0 = 11.6
    wcs11 = galsim.AffineTransform(dudx, dudy, dvdx, dvdy,
                                   galsim.PositionD(x0, y0))
    dudx = 12.1
    dudy = 12.2
    dvdx = 12.3
    dvdy = 12.4
    wcs12 = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)
    wcs13 = galsim.PixelScale(13)

    # create lists
    images = [img11, img12, img13]
    weight = [wth11, wth12, wth13]
    seg = [seg11, seg12, seg13]
    psf = [psf11, psf12, psf13]
    wcs = [wcs11, wcs12, wcs13]

    # create object
    obj1 = galsim.des.MultiExposureObject(images=images,
                                          weight=weight,
                                          seg=seg,
                                          psf=psf,
                                          wcs=wcs,
                                          id=1)

    # second obj
    img21 = galsim.Image(box_size, box_size, init_value=211)
    img22 = galsim.Image(box_size, box_size, init_value=212)
    img23 = galsim.Image(box_size, box_size, init_value=213)
    seg21 = galsim.Image(box_size, box_size, init_value=221)
    seg22 = galsim.Image(box_size, box_size, init_value=222)
    seg23 = galsim.Image(box_size, box_size, init_value=223)
    wth21 = galsim.Image(box_size, box_size, init_value=231)
    wth22 = galsim.Image(box_size, box_size, init_value=332)
    wth23 = galsim.Image(box_size, box_size, init_value=333)
    psf21 = galsim.Image(box_size, box_size, init_value=241)
    psf22 = galsim.Image(box_size, box_size, init_value=342)
    psf23 = galsim.Image(box_size, box_size, init_value=343)

    dudx = 21.1
    dudy = 21.2
    dvdx = 21.3
    dvdy = 21.4
    x0 = 21.5
    y0 = 21.6
    wcs21 = galsim.AffineTransform(dudx, dudy, dvdx, dvdy,
                                   galsim.PositionD(x0, y0))
    dudx = 22.1
    dudy = 22.2
    dvdx = 22.3
    dvdy = 22.4
    wcs22 = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)
    wcs23 = galsim.PixelScale(23)

    # create lists
    images = [img21, img22, img23]
    weight = [wth21, wth22, wth23]
    seg = [seg21, seg22, seg23]
    psf = [psf21, psf22, psf23]
    wcs = [wcs21, wcs22, wcs23]

    # create object
    # This time put the wcs in the image and get it there.
    img21.wcs = wcs21
    img22.wcs = wcs22
    img23.wcs = wcs23
    obj2 = galsim.des.MultiExposureObject(images=images,
                                          weight=weight,
                                          seg=seg,
                                          psf=psf,
                                          id=2)

    obj3 = galsim.des.MultiExposureObject(images=images, id=3)

    # create an object list
    objlist = [obj1, obj2]

    # save objects to MEDS file
    filename_meds = 'output/test_meds.fits'
    galsim.des.WriteMEDS(objlist, filename_meds, clobber=True)

    bad1 = galsim.Image(32, 48, init_value=0)
    bad2 = galsim.Image(35, 35, init_value=0)
    bad3 = galsim.Image(48, 48, init_value=0)

    with assert_raises(TypeError):
        galsim.des.MultiExposureObject(images=img11)
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[])
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[bad1])
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[bad2])
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[img11, bad3])
    with assert_raises(TypeError):
        galsim.des.MultiExposureObject(images=images, weight=wth11)
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=images, weight=[])
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[img11], weight=[bad3])
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[img11], psf=[bad1])
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[img11], psf=[bad2])
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[img11, img12],
                                       psf=[bad2, psf12])
    with assert_raises(TypeError):
        galsim.des.MultiExposureObject(images=images, wcs=wcs11)
    celestial_wcs = galsim.FitsWCS("DECam_00154912_12_header.fits",
                                   dir='des_data')
    with assert_raises(galsim.GalSimValueError):
        galsim.des.MultiExposureObject(images=[img11], wcs=[celestial_wcs])

    # Check the one with no psf, weight, etc.
    filename_meds2 = 'output/test_meds_image_only.fits'
    galsim.des.WriteMEDS([obj3], filename_meds2, clobber=True)

    # Note that while there are no tests prior to this, the above still checks for
    # syntax errors in the meds creation software, so it's still worth running as part
    # of the normal unit tests.
    # But for the rest of the tests, we'll use the meds module to make sure our code
    # stays in sync with any changes there.
    try:
        import meds
        # Meds will import this, so check for this too.
        import fitsio
    except ImportError:
        print(
            'Failed to import either meds or fitsio.  Unable to do tests of meds file.'
        )
        return

    # Run meds module's validate function
    try:
        meds.util.validate_meds(filename_meds)
        meds.util.validate_meds(filename_meds2)
    except AttributeError:
        print(
            'Seems to be the wrong meds package.  Unable to do tests of meds file.'
        )
        return

    m = meds.MEDS(filename_meds)

    # Check the image_info extension:
    ref_info = meds.util.get_image_info_dtype(1)
    info = m.get_image_info()
    print('info = ', info)
    for name, dt in ref_info:
        dt = numpy.dtype(dt)
        print(name, dt, info.dtype[name], dt.char, info.dtype[name].char)
        assert name in info.dtype.names, "column %s not present in image_info extension" % name
        # I think S and U for this purpose are equivalent.
        # But I'm finding S in the reference, and U in info.
        c = info.dtype[name].char
        c = 'S' if c == 'U' else c
        assert dt.char == c, "column %s is the wrong type" % name

    # Check the basic structure of the object_data extension
    cat = m.get_cat()
    ref_data = meds.util.get_meds_output_dtype(1)
    for tup in ref_data:
        # Some of these tuples have 3 items, not 2.  The last two are the full dtype tuple.
        name = tup[0]
        if len(tup) == 2:
            dt = tup[1]
        else:
            dt = tup[1:]
        dt = numpy.dtype(dt)
        print(name, dt, cat.dtype[name], dt.char, cat.dtype[name].char)
        assert name in cat.dtype.names, "column %s not present in object_data extension" % name
        assert dt.char == cat.dtype[
            name].char, "column %s is the wrong type" % name

    # Check that we have the right number of objects.
    n_obj = len(cat)
    print('number of objects is %d' % n_obj)
    numpy.testing.assert_equal(n_obj,
                               n_obj_test,
                               err_msg="MEDS file has wrong number of objects")

    # loop over objects and exposures - test get_cutout
    for iobj in range(n_obj):

        # check ID is correct
        numpy.testing.assert_equal(
            cat['id'][iobj],
            iobj + 1,
            err_msg="MEDS file has wrong id for object %d" % iobj)

        # get number of cutouts and check if it's right
        n_cut = cat['ncutout'][iobj]
        numpy.testing.assert_equal(
            n_cut,
            n_cut_test,
            err_msg="MEDS file has wrong ncutout for object %d" % iobj)

        # loop over cutouts
        for icut in range(n_cut):

            # get the images etc to compare with originals
            img = m.get_cutout(iobj, icut, type='image')
            wth = m.get_cutout(iobj, icut, type='weight')
            seg = m.get_cutout(iobj, icut, type='seg')
            psf = m.get_psf(iobj, icut)
            wcs_meds = m.get_jacobian(iobj, icut)
            # Note: col == x, row == y.
            wcs_array_meds = numpy.array([
                wcs_meds['dudcol'], wcs_meds['dudrow'], wcs_meds['dvdcol'],
                wcs_meds['dvdrow'], wcs_meds['col0'], wcs_meds['row0']
            ])

            # compare
            numpy.testing.assert_array_equal(
                img,
                objlist[iobj].images[icut].array,
                err_msg="MEDS cutout has wrong img for object %d" % iobj)
            numpy.testing.assert_array_equal(
                wth,
                objlist[iobj].weight[icut].array,
                err_msg="MEDS cutout has wrong wth for object %d" % iobj)
            numpy.testing.assert_array_equal(
                seg,
                objlist[iobj].seg[icut].array,
                err_msg="MEDS cutout has wrong seg for object %d" % iobj)
            numpy.testing.assert_array_equal(
                psf,
                objlist[iobj].psf[icut].array,
                err_msg="MEDS cutout has wrong psf for object %d" % iobj)
            wcs_orig = objlist[iobj].wcs[icut]
            wcs_array_orig = numpy.array([
                wcs_orig.dudx, wcs_orig.dudy, wcs_orig.dvdx, wcs_orig.dvdy,
                wcs_orig.origin.x, wcs_orig.origin.y
            ])
            numpy.testing.assert_array_equal(
                wcs_array_meds,
                wcs_array_orig,
                err_msg="MEDS cutout has wrong wcs for object %d" % iobj)

        # get the mosaic to compare with originals
        img = m.get_mosaic(iobj, type='image')
        wth = m.get_mosaic(iobj, type='weight')
        seg = m.get_mosaic(iobj, type='seg')
        # There is currently no get_mosaic option for the psfs.
        #psf = m.get_mosaic( iobj, type='psf')
        psf = numpy.concatenate(
            [m.get_psf(iobj, icut) for icut in range(n_cut)], axis=0)

        # get the concatenated images - create the true mosaic
        true_mosaic_img = numpy.concatenate(
            [x.array for x in objlist[iobj].images], axis=0)
        true_mosaic_wth = numpy.concatenate(
            [x.array for x in objlist[iobj].weight], axis=0)
        true_mosaic_seg = numpy.concatenate(
            [x.array for x in objlist[iobj].seg], axis=0)
        true_mosaic_psf = numpy.concatenate(
            [x.array for x in objlist[iobj].psf], axis=0)

        # compare
        numpy.testing.assert_array_equal(
            true_mosaic_img,
            img,
            err_msg="MEDS mosaic has wrong img for object %d" % iobj)
        numpy.testing.assert_array_equal(
            true_mosaic_wth,
            wth,
            err_msg="MEDS mosaic has wrong wth for object %d" % iobj)
        numpy.testing.assert_array_equal(
            true_mosaic_seg,
            seg,
            err_msg="MEDS mosaic has wrong seg for object %d" % iobj)
        numpy.testing.assert_array_equal(
            true_mosaic_psf,
            psf,
            err_msg="MEDS mosaic has wrong psf for object %d" % iobj)
Beispiel #18
0
def test_interleaveImages():
    # 1a) With galsim Gaussian
    g = galsim.Gaussian(sigma=3.7, flux=1000.)
    gal = galsim.Convolve([g, galsim.Pixel(1.0)])
    im_list = []
    offset_list = []
    n = 2
    for j in range(n):
        for i in range(n):
            im = galsim.Image(16 * n, 16 * n)
            offset = galsim.PositionD(-(i + 0.5) / n + 0.5,
                                      -(j + 0.5) / n + 0.5)
            offset_list.append(offset)
            gal.drawImage(image=im,
                          method='no_pixel',
                          offset=offset,
                          scale=0.5)
            im_list.append(im)

    scale = im.scale

    # Input to N as an int
    img = galsim.utilities.interleaveImages(im_list, n, offsets=offset_list)
    im = galsim.Image(16 * n * n, 16 * n * n)
    g = galsim.Gaussian(sigma=3.7, flux=1000. * n * n)
    gal = galsim.Convolve([g, galsim.Pixel(1.0)])
    gal.drawImage(image=im,
                  method='no_pixel',
                  offset=galsim.PositionD(0.0, 0.0),
                  scale=1. * scale / n)
    np.testing.assert_almost_equal(
        img.array,
        im.array,
        6,
        err_msg="Interleaved Gaussian images do not match")

    assert im.wcs == img.wcs

    # 1b) With im_list and offsets permuted
    offset_list = []
    # An elegant way of generating the default offsets
    DX = np.arange(0.0, -1.0, -1.0 / n)
    DX -= DX.mean()
    DY = DX
    for dy in DY:
        for dx in DX:
            offset = galsim.PositionD(dx, dy)
            offset_list.append(offset)

    np.random.seed(42)  # for generating the same random permutation everytime
    rand_idx = np.random.permutation(len(offset_list))
    im_list_randperm = [im_list[idx] for idx in rand_idx]
    offset_list_randperm = [offset_list[idx] for idx in rand_idx]
    # Input to N as a tuple
    img_randperm = galsim.utilities.interleaveImages(
        im_list_randperm, (n, n), offsets=offset_list_randperm)

    np.testing.assert_array_equal(
        img_randperm.array,
        img.array,
        err_msg="Interleaved images do not match when 'offsets' is supplied")
    assert img_randperm.scale == img.scale

    # 1c) Catching errors in offsets
    offset_list = []
    im_list = []
    n = 5
    # Generate approximate offsets
    DX = np.array([-0.67, -0.33, 0., 0.33, 0.67])
    DY = DX
    for dy in DY:
        for dx in DX:
            offset = galsim.PositionD(dx, dy)
            offset_list.append(offset)
            im = galsim.Image(16, 16)
            gal.drawImage(image=im, offset=offset, method='no_pixel')
            im_list.append(im)

    try:
        N = (n, n)
        np.testing.assert_raises(ValueError, galsim.utilities.interleaveImages,
                                 im_list, N, offset_list)
    except ImportError:
        print("The assert_raises tests require nose")

    offset_list = []
    im_list = []
    n = 5
    DX = np.arange(0., 1., 1. / n)
    DY = DX
    for dy in DY:
        for dx in DX:
            offset = galsim.PositionD(dx, dy)
            offset_list.append(offset)
            im = galsim.Image(16, 16)
            gal.drawImage(image=im, offset=offset, method='no_pixel')
            im_list.append(im)

    try:
        N = (n, n)
        np.testing.assert_raises(ValueError, galsim.utilities.interleaveImages,
                                 im_list, N, offset_list)
    except ImportError:
        print("The assert_raises tests require nose")

    # 2a) Increase resolution along one direction - square to rectangular images
    n = 2
    g = galsim.Gaussian(sigma=3.7, flux=100.)
    gal1 = g.shear(g=1. * (n**2 - 1) / (n**2 + 1), beta=0.0 * galsim.radians)
    im_list = []
    offset_list = []

    # Generating offsets in a natural way
    DY = np.arange(0.0, 1.0, 1.0 / (n * n))
    DY -= DY.mean()
    for dy in DY:
        im = galsim.Image(16, 16)
        offset = galsim.PositionD(0.0, dy)
        offset_list.append(offset)
        gal1.drawImage(im, offset=offset, method='no_pixel', scale=2.0)
        im_list.append(im)

    img = galsim.utilities.interleaveImages(im_list,
                                            N=[1, n**2],
                                            offsets=offset_list,
                                            add_flux=False,
                                            suppress_warnings=True)
    im = galsim.Image(16, 16 * n * n)
    # The interleaved image has the total flux averaged out since `add_flux = False'
    gal = galsim.Gaussian(sigma=3.7 * n, flux=100.)
    gal.drawImage(image=im, method='no_pixel', scale=2.0)

    np.testing.assert_array_equal(
        im.array,
        img.array,
        err_msg="Sheared gaussian not interleaved correctly")
    assert img.wcs == galsim.JacobianWCS(2.0, 0.0, 0.0, 2. / (n**2))

    # 2b) Increase resolution along one direction - rectangular to square images
    n = 2
    g = galsim.Gaussian(sigma=3.7, flux=100.)
    gal2 = g.shear(g=1. * (n**2 - 1) / (n**2 + 1), beta=90. * galsim.degrees)
    im_list = []
    offset_list = []

    # Generating offsets in a natural way
    DX = np.arange(0.0, 1.0, 1.0 / n**2)
    DX -= DX.mean()
    for dx in DX:
        offset = galsim.PositionD(dx, 0.0)
        offset_list.append(offset)
        im = galsim.Image(16, 16 * n * n)
        gal2.drawImage(im, offset=offset, method='no_pixel', scale=3.0)
        im_list.append(im)

    img = galsim.utilities.interleaveImages(im_list,
                                            N=np.array([n**2, 1]),
                                            offsets=offset_list,
                                            suppress_warnings=True)
    im = galsim.Image(16 * n * n, 16 * n * n)
    gal = galsim.Gaussian(sigma=3.7, flux=100. * n * n)
    scale = im_list[0].scale
    gal.drawImage(image=im, scale=1. * scale / n, method='no_pixel')

    np.testing.assert_almost_equal(
        im.array,
        img.array,
        12,
        err_msg="Sheared gaussian not interleaved correctly")
    assert img.wcs == galsim.JacobianWCS(1. * scale / n**2, 0.0, 0.0, scale)

    # 3) Check compatability with deInterleaveImage
    n = 3
    g = galsim.Gaussian(sigma=3.7, flux=100.)
    # break symmetry to detect possible bugs in deInterleaveImage
    gal = g.shear(g=0.2, beta=0. * galsim.degrees)
    im_list = []
    offset_list = []

    # Generating offsets in the order they would be returned by deInterleaveImage, for convenience
    for i in range(n):
        for j in range(n):
            im = galsim.Image(16 * n, 16 * n)
            offset = galsim.PositionD(-(i + 0.5) / n + 0.5,
                                      -(j + 0.5) / n + 0.5)
            offset_list.append(offset)
            gal.drawImage(image=im,
                          method='no_pixel',
                          offset=offset,
                          scale=0.5)
            im.setOrigin(3, 3)  # for non-trivial bounds
            im_list.append(im)

    img = galsim.utilities.interleaveImages(im_list, N=n, offsets=offset_list)
    im_list_1, offset_list_1 = galsim.utilities.deInterleaveImage(img, N=n)

    for k in range(n**2):
        assert offset_list_1[k] == offset_list[k]
        np.testing.assert_array_equal(im_list_1[k].array, im_list[k].array)
        assert im_list_1[k].wcs == im_list[k].wcs

        assert im_list[k].origin == img.origin
        assert im_list[k].bounds == im_list_1[k].bounds

    # Checking for non-default flux option
    img = galsim.utilities.interleaveImages(im_list,
                                            N=n,
                                            offsets=offset_list,
                                            add_flux=False)
    im_list_2, offset_list_2 = galsim.utilities.deInterleaveImage(
        img, N=n, conserve_flux=True)

    for k in range(n**2):
        assert offset_list_2[k] == offset_list[k]
        np.testing.assert_array_equal(im_list_2[k].array, im_list[k].array)
        assert im_list_2[k].wcs == im_list[k].wcs
Beispiel #19
0
def test_simple():
    """Initial simple test of Gaussian, Kolmogorov, and Moffat PSFs.
    """
    # Here is the true PSF
    scale = 1.3
    g1 = 0.23
    g2 = -0.17
    du = 0.1
    dv = 0.4
    for fiducial in [fiducial_gaussian, fiducial_kolmogorov, fiducial_moffat]:
        print()
        print("fiducial = ", fiducial)
        print()
        psf = fiducial.dilate(scale).shear(g1=g1, g2=g2).shift(du, dv)

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        # This is only going to come out right if we (unphysically) don't convolve by the pixel.
        psf.drawImage(image, method='no_pixel')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        fiducial_star = piff.Star(stardata, None)

        # First try fastfit.
        print('Fast fit')
        model = piff.GSObjectModel(fiducial, fastfit=True, include_pixel=False)
        fit = model.fit(model.initialize(fiducial_star)).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # This test is fairly accurate, since we didn't add any noise and didn't convolve by
        # the pixel, so the image is very accurately a sheared GSObject.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-4)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-7)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-7)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-7)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-7)

        # Now try fastfit=False.
        print('Slow fit')
        model = piff.GSObjectModel(fiducial,
                                   fastfit=False,
                                   include_pixel=False)
        fit = model.fit(model.initialize(fiducial_star)).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-6)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-6)

        # Now test running it via the config parser
        config = {
            'model': {
                'type': 'GSObjectModel',
                'gsobj': repr(fiducial),
                'include_pixel': False
            }
        }
        if __name__ == '__main__':
            logger = piff.config.setup_logger(verbose=3)
        else:
            logger = piff.config.setup_logger(verbose=1)
        model = piff.Model.process(config['model'], logger)
        fit = model.fit(model.initialize(fiducial_star)).fit

        # Same tests.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-6)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-6)

        # Also need to test ability to serialize
        outfile = os.path.join('output', 'gsobject_test.fits')
        with fitsio.FITS(outfile, 'rw', clobber=True) as f:
            model.write(f, 'psf_model')
        with fitsio.FITS(outfile, 'r') as f:
            roundtrip_model = piff.GSObjectModel.read(f, 'psf_model')
        assert model.__dict__ == roundtrip_model.__dict__

        # Finally, we should also test with pixel convolution included.  This really only makes
        # sense for fastfit=False, since HSM FindAdaptiveMom doesn't account for the pixel shape
        # in its measurements.

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        psf.drawImage(image, method='auto')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        fiducial_star = piff.Star(stardata, None)

        print('Slow fit, pixel convolution included.')
        model = piff.GSObjectModel(fiducial, fastfit=False, include_pixel=True)
        star = model.initialize(fiducial_star)
        star = model.fit(
            star,
            fastfit=True)  # Get better results with one round of fastfit.
        # Use a no op convert_func, just to touch that branch in the code.
        convert_func = lambda prof: prof
        fit = model.fit(star, convert_func=convert_func).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # Accuracy goals are a bit looser here since it's harder to fit with the pixel involved.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-6)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-6)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-5)
Beispiel #20
0
def test_direct():
    """ Simple test for directly instantiated Gaussian, Kolmogorov, and Moffat without going through
    GSObjectModel explicitly.
    """
    # Here is the true PSF
    scale = 1.3
    g1 = 0.23
    g2 = -0.17
    du = 0.1
    dv = 0.4

    gsobjs = [
        galsim.Gaussian(sigma=1.0),
        galsim.Kolmogorov(half_light_radius=1.0),
        galsim.Moffat(half_light_radius=1.0, beta=3.0),
        galsim.Moffat(half_light_radius=1.0, beta=2.5, trunc=3.0)
    ]

    models = [
        piff.Gaussian(fastfit=True, include_pixel=False),
        piff.Kolmogorov(fastfit=True, include_pixel=False),
        piff.Moffat(fastfit=True, beta=3.0, include_pixel=False),
        piff.Moffat(fastfit=True, beta=2.5, trunc=3.0, include_pixel=False)
    ]

    for gsobj, model in zip(gsobjs, models):
        print()
        print("gsobj = ", gsobj)
        print()
        psf = gsobj.dilate(scale).shear(g1=g1, g2=g2).shift(du, dv)

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        # This is only going to come out right if we (unphysically) don't convolve by the pixel.
        psf.drawImage(image, method='no_pixel')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        star = piff.Star(stardata, None)
        star = model.initialize(star)

        # First try fastfit.
        print('Fast fit')
        fit = model.fit(star).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # This test is fairly accurate, since we didn't add any noise and didn't convolve by
        # the pixel, so the image is very accurately a sheared GSObject.
        # These tests are more strict above.  The truncated Moffat included here but not there
        # doesn't work quite as well.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-4)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-5)

        # Also need to test ability to serialize
        outfile = os.path.join('output', 'gsobject_direct_test.fits')
        with fitsio.FITS(outfile, 'rw', clobber=True) as f:
            model.write(f, 'psf_model')
        with fitsio.FITS(outfile, 'r') as f:
            roundtrip_model = piff.GSObjectModel.read(f, 'psf_model')
        assert model.__dict__ == roundtrip_model.__dict__

    # repeat with fastfit=False

    models = [
        piff.Gaussian(fastfit=False, include_pixel=False),
        piff.Kolmogorov(fastfit=False, include_pixel=False),
        piff.Moffat(fastfit=False, beta=3.0, include_pixel=False),
        piff.Moffat(fastfit=False, beta=2.5, trunc=3.0, include_pixel=False)
    ]

    for gsobj, model in zip(gsobjs, models):
        print()
        print("gsobj = ", gsobj)
        print()
        psf = gsobj.dilate(scale).shear(g1=g1, g2=g2).shift(du, dv)

        # Draw the PSF onto an image.  Let's go ahead and give it a non-trivial WCS.
        wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
        image = galsim.Image(64, 64, wcs=wcs)

        # This is only going to come out right if we (unphysically) don't convolve by the pixel.
        psf.drawImage(image, method='no_pixel')

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center)
        star = piff.Star(stardata, None)
        star = model.initialize(star)

        print('Slow fit')
        fit = model.fit(star).fit

        print('True scale = ', scale, ', model scale = ', fit.params[0])
        print('True g1 = ', g1, ', model g1 = ', fit.params[1])
        print('True g2 = ', g2, ', model g2 = ', fit.params[2])
        print('True du = ', du, ', model du = ', fit.center[0])
        print('True dv = ', dv, ', model dv = ', fit.center[1])

        # This test is fairly accurate, since we didn't add any noise and didn't convolve by
        # the pixel, so the image is very accurately a sheared GSObject.
        np.testing.assert_allclose(fit.params[0], scale, rtol=1e-5)
        np.testing.assert_allclose(fit.params[1], g1, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.params[2], g2, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[0], du, rtol=0, atol=1e-5)
        np.testing.assert_allclose(fit.center[1], dv, rtol=0, atol=1e-5)

        # Also need to test ability to serialize
        outfile = os.path.join('output', 'gsobject_direct_test.fits')
        with fitsio.FITS(outfile, 'rw', clobber=True) as f:
            model.write(f, 'psf_model')
        with fitsio.FITS(outfile, 'r') as f:
            roundtrip_model = piff.GSObjectModel.read(f, 'psf_model')
        assert model.__dict__ == roundtrip_model.__dict__
Beispiel #21
0
def test_interleaveImages():
    import time
    t1 = time.time()

    # 1a) With galsim Gaussian
    g = galsim.Gaussian(sigma=3.7, flux=1000.)
    gal = galsim.Convolve([g, galsim.Pixel(1.0)])
    im_list = []
    offset_list = []
    n = 2
    for j in xrange(n):
        for i in xrange(n):
            im = galsim.Image(16 * n, 16 * n)
            offset = galsim.PositionD(-(i + 0.5) / n + 0.5,
                                      -(j + 0.5) / n + 0.5)
            offset_list.append(offset)
            gal.drawImage(image=im,
                          method='no_pixel',
                          offset=offset,
                          scale=0.5)
            im_list.append(im)

    scale = im.scale

    # Input to N as an int
    img = galsim.utilities.interleaveImages(im_list, n, offsets=offset_list)
    im = galsim.Image(16 * n * n, 16 * n * n)
    g = galsim.Gaussian(sigma=3.7, flux=1000. * n * n)
    gal = galsim.Convolve([g, galsim.Pixel(1.0)])
    gal.drawImage(image=im,
                  method='no_pixel',
                  offset=galsim.PositionD(0.0, 0.0),
                  scale=1. * scale / n)
    np.testing.assert_array_equal(img.array,im.array,\
        err_msg="Interleaved Gaussian images do not match")

    assert im.wcs == img.wcs

    # 1b) With im_list and offsets permuted
    offset_list = []
    # An elegant way of generating the default offsets
    DX = np.arange(0.0, -1.0, -1.0 / n)
    DX -= DX.mean()
    DY = DX
    for dy in DY:
        for dx in DX:
            offset = galsim.PositionD(dx, dy)
            offset_list.append(offset)

    np.random.seed(42)  # for generating the same random permutation everytime
    rand_idx = np.random.permutation(len(offset_list))
    im_list_randperm = [im_list[idx] for idx in rand_idx]
    offset_list_randperm = [offset_list[idx] for idx in rand_idx]
    # Input to N as a tuple
    img_randperm = galsim.utilities.interleaveImages(
        im_list_randperm, (n, n), offsets=offset_list_randperm)

    np.testing.assert_array_equal(img_randperm.array,img.array,\
        err_msg="Interleaved images do not match when 'offsets' is supplied")
    assert img_randperm.scale == img.scale

    # 1c) Catching errors in offsets
    offset_list = []
    im_list = []
    n = 5
    # Generate approximate offsets
    DX = np.array([-0.67, -0.33, 0., 0.33, 0.67])
    DY = DX
    for dy in DY:
        for dx in DX:
            offset = galsim.PositionD(dx, dy)
            offset_list.append(offset)
            im = galsim.Image(16, 16)
            gal.drawImage(image=im, offset=offset, method='no_pixel')
            im_list.append(im)

    try:
        N = (n, n)
        np.testing.assert_raises(ValueError, galsim.utilities.interleaveImages,
                                 im_list, N, offset_list)
    except ImportError:
        print "The assert_raises tests require nose"

    offset_list = []
    im_list = []
    n = 5
    DX = np.arange(0., 1., 1. / n)
    DY = DX
    for dy in DY:
        for dx in DX:
            offset = galsim.PositionD(dx, dy)
            offset_list.append(offset)
            im = galsim.Image(16, 16)
            gal.drawImage(image=im, offset=offset, method='no_pixel')
            im_list.append(im)

    try:
        N = (n, n)
        np.testing.assert_raises(ValueError, galsim.utilities.interleaveImages,
                                 im_list, N, offset_list)
    except ImportError:
        print "The assert_raises tests require nose"

    # 2a) Increase resolution along one direction - square to rectangular images
    n = 2
    g = galsim.Gaussian(sigma=3.7, flux=100.)
    gal1 = g.shear(g=1. * (n**2 - 1) / (n**2 + 1), beta=0.0 * galsim.radians)
    im_list = []
    offset_list = []

    # Generating offsets in a natural way
    DY = np.arange(0.0, 1.0, 1.0 / (n * n))
    DY -= DY.mean()
    for dy in DY:
        im = galsim.Image(16, 16)
        offset = galsim.PositionD(0.0, dy)
        offset_list.append(offset)
        gal1.drawImage(im, offset=offset, method='no_pixel', scale=2.0)
        im_list.append(im)

    img = galsim.utilities.interleaveImages(im_list,
                                            N=[1, n**2],
                                            offsets=offset_list,
                                            add_flux=False,
                                            suppress_warnings=True)
    im = galsim.Image(16, 16 * n * n)
    # The interleaved image has the total flux averaged out since `add_flux = False'
    gal = galsim.Gaussian(sigma=3.7 * n, flux=100.)
    gal.drawImage(image=im, method='no_pixel', scale=2.0)

    np.testing.assert_array_equal(
        im.array,
        img.array,
        err_msg="Sheared gaussian not interleaved correctly")
    assert img.wcs == galsim.JacobianWCS(2.0, 0.0, 0.0, 2. / (n**2))

    # 2b) Increase resolution along one direction - rectangular to square images
    n = 2
    g = galsim.Gaussian(sigma=3.7, flux=100.)
    gal2 = g.shear(g=1. * (n**2 - 1) / (n**2 + 1), beta=90. * galsim.degrees)
    im_list = []
    offset_list = []

    # Generating offsets in a natural way
    DX = np.arange(0.0, 1.0, 1.0 / n**2)
    DX -= DX.mean()
    for dx in DX:
        offset = galsim.PositionD(dx, 0.0)
        offset_list.append(offset)
        im = galsim.Image(16, 16 * n * n)
        gal2.drawImage(im, offset=offset, method='no_pixel', scale=3.0)
        im_list.append(im)

    img = galsim.utilities.interleaveImages(im_list,
                                            N=np.array([n**2, 1]),
                                            offsets=offset_list,
                                            suppress_warnings=True)
    im = galsim.Image(16 * n * n, 16 * n * n)
    gal = galsim.Gaussian(sigma=3.7, flux=100. * n * n)
    scale = im_list[0].scale
    gal.drawImage(image=im, scale=1. * scale / n, method='no_pixel')

    np.testing.assert_array_equal(
        im.array,
        img.array,
        err_msg="Sheared gaussian not interleaved correctly")
    assert img.wcs == galsim.JacobianWCS(1. * scale / n**2, 0.0, 0.0, scale)

    t2 = time.time()
    print 'time for %s = %.2f' % (funcname(), t2 - t1)
Beispiel #22
0
def deInterleaveImage(image, N, conserve_flux=False,suppress_warnings=False):
    """
    The routine to do the opposite of what 'interleaveImages' routine does. It generates a
    (uniform) dither sequence of low resolution images from a high resolution image.

    Many pixel level detector effects, such as interpixel capacitance, persistence, charge
    diffusion etc. can be included only on images drawn at the native pixel scale, which happen to
    be undersampled in most cases. Nyquist-sampled images that also include the effects of detector
    non-idealities can be obtained by drawing multiple undersampled images (with the detector
    effects included) that are offset from each other by a fraction of a pixel. If the offsets are
    uniformly spaced, then images can be combined using 'interleaveImages' into a Nyquist-sampled
    image.

    Drawing multiple low resolution images of a light profile can be a lot slower than drawing a
    high resolution image of the same profile, even if the total number of pixels is the same. A
    uniformly offset dither sequence can be extracted from a well-resolved image that is drawn by
    convolving the surface brightness profile explicitly with the native pixel response and setting
    a lower sampling scale (or higher sampling rate) using the `pixel_scale' argument in drawImage()
    routine and setting the `method' parameter to `no_pixel'.

    Here is an example script using this routine:

    Interleaving four Gaussian images
    ---------------------------------

        >>> n = 2
        >>> gal = galsim.Gaussian(sigma=2.8)
        >>> gal_pix = galsim.Convolve([gal,galsim.Pixel(scale=1.0)])
        >>> img = gal_pix.drawImage(gal_pix,scale=1.0/n,method='no_pixel')
        >>> im_list, offsets = galsim.utilities.deInterleaveImage(img,N=n)
        >>> for im in im_list:
        >>>     im.applyNonlinearity(lambda x: x-0.01*x**2) #detector effects
        >>> img_new = galsim.utilities.interleaveImages(im_list,N=n,offsets)

    @param image             Input image from which lower resolution images are extracted.
    @param N                 Number of images extracted in either directions. It can be of type
                             'int' if equal number of images are extracted in both directions or a
                             list or tuple of two integers, containing the number of images in x
                             and y directions respectively.
    @param conserve_flux     Should the routine output images that have, on average, same total
                             pixel values as the input image (True) or should the pixel values
                             summed over all the images equal the sum of pixel values of the input
                             image (False)? [default: False]
    @param suppress_warnings Suppresses the warnings about the pixel scale of the output, if True.
                             [default: False]

    @returns a list of images and offsets to reconstruct the input image using 'interleaveImages'.
    """
    if isinstance(N,int):
        n1,n2 = N,N
    elif hasattr(N,'__iter__'):
        if len(N)==2:
            n1,n2 = N
        else:
            raise TypeError("'N' has to be a list or a tuple of two integers")
        if not (n1 == int(n1) and n2 == int(n2)):
            raise TypeError("'N' has to be of type int or a list or a tuple of two integers")
        n1 = int(n1)
        n2 = int(n2)
    else:
        raise TypeError("'N' has to be of type int or a list or a tuple of two integers")

    if not isinstance(image,galsim.Image):
        raise TypeError("'image' has to be an instance of galsim.Image")

    y_size,x_size = image.array.shape
    if x_size%n1 or y_size%n2:
        raise ValueError("The value of 'N' is incompatible with the dimensions of the image to "+
                         +"be 'deinterleaved'")

    im_list, offsets = [], []
    for i in range(n1):
        for j in range(n2):
            # The tricky part - going from array indices to Image coordinates (x,y)
            # DX[i'] = -(i+0.5)/n+0.5 = -i/n + 0.5*(n-1)/n
            #    i  = -n DX[i'] + 0.5*(n-1)
            dx,dy = -(i+0.5)/n1+0.5,-(j+0.5)/n2+0.5
            offset = galsim.PositionD(dx,dy)
            img_arr = image.array[j::n2,i::n1].copy()
            img = galsim.Image(img_arr)
            if conserve_flux is True:
                img *= n1*n2
            im_list.append(img)
            offsets.append(offset)

    wcs = image.wcs
    if wcs is not None and wcs.isUniform():
        jac = wcs.jacobian()
        for img in im_list:
            img_wcs = galsim.JacobianWCS(jac.dudx*n1,jac.dudy*n2,jac.dvdx*n1,jac.dvdy*n2)
            ## Since pixel scale WCS is not equal to its jacobian, checking if img_wcs is a pixel
            ## scale
            img_wcs_decomp = img_wcs.getDecomposition()
            if img_wcs_decomp[1].g==0:
                img.wcs = galsim.PixelScale(img_wcs_decomp[0])
            else:
               img.wcs = img_wcs
            ## Preserve the origin so that the interleaved image has the same bounds as the image
            ## that is being deinterleaved.
            img.setOrigin(image.origin())

    elif suppress_warnings is False:
        import warnings
        warnings.warn("Individual images could not be assigned a WCS automatically.")

    return im_list, offsets
Beispiel #23
0
def test_var():
    """Check that the variance estimate in params_var is sane.
    """
    # Here is the true PSF
    scale = 1.3
    g1 = 0.23
    g2 = -0.17
    du = 0.1
    dv = 0.4
    flux = 500
    wcs = galsim.JacobianWCS(0.26, 0.05, -0.08, -0.29)
    noise = 0.2

    gsobjs = [
        galsim.Gaussian(sigma=1.0),
        galsim.Kolmogorov(half_light_radius=1.0),
        galsim.Moffat(half_light_radius=1.0, beta=3.0),
        galsim.Moffat(half_light_radius=1.0, beta=2.5, trunc=3.0)
    ]

    # Mix of centered = True/False,
    #        fastfit = True/False,
    #        include_pixel = True/False
    models = [
        piff.Gaussian(fastfit=False, include_pixel=False, centered=False),
        piff.Kolmogorov(fastfit=True, include_pixel=True, centered=False),
        piff.Moffat(fastfit=False, beta=4.8, include_pixel=True,
                    centered=True),
        piff.Moffat(fastfit=True,
                    beta=2.5,
                    trunc=3.0,
                    include_pixel=False,
                    centered=True)
    ]

    names = ['Gaussian', 'Kolmogorov', 'Moffat3', 'Moffat2.5']

    for gsobj, model, name in zip(gsobjs, models, names):
        print()
        print("gsobj = ", gsobj)
        print()
        psf = gsobj.dilate(scale).shear(g1=g1, g2=g2).shift(du,
                                                            dv).withFlux(flux)
        image = psf.drawImage(nx=64, ny=64, wcs=wcs, method='no_pixel')
        weight = image.copy()
        weight.fill(1 / noise**2)
        # Save this one without noise.

        image1 = image.copy()
        image1.addNoise(galsim.GaussianNoise(sigma=noise))

        # Make a StarData instance for this image
        stardata = piff.StarData(image, image.true_center, weight)
        star = piff.Star(stardata, None)
        star = model.initialize(star)
        fit = model.fit(star).fit

        file_name = 'input/test_%s_var.npz' % name
        print(file_name)

        if not os.path.isfile(file_name):
            num_runs = 1000
            all_params = []
            for i in range(num_runs):
                image1 = image.copy()
                image1.addNoise(galsim.GaussianNoise(sigma=noise))
                sd = piff.StarData(image1, image1.true_center, weight)
                s = piff.Star(sd, None)
                try:
                    s = model.initialize(s)
                    s = model.fit(s)
                except RuntimeError as e:  # Occasionally hsm fails.
                    print('Caught ', e)
                    continue
                print(s.fit.params)
                all_params.append(s.fit.params)
            var = np.var(all_params, axis=0)
            np.savez(file_name, var=var)
        var = np.load(file_name)['var']
        print('params = ', fit.params)
        print('empirical var = ', var)
        print('piff estimate = ', fit.params_var)
        print('ratio = ', fit.params_var / var)
        print('max ratio = ', np.max(fit.params_var / var))
        print('min ratio = ', np.min(fit.params_var / var))
        print('mean ratio = ', np.mean(fit.params_var / var))
        # Note: The fastfit=False estimates are better -- typically better than 10%
        #       The fastfit=True estimates are much rougher.  Especially size.  Need rtol=0.3.
        np.testing.assert_allclose(fit.params_var, var, rtol=0.3)
Beispiel #24
0
def test_jacobian_smoke(kind):
    dudcol = 0.25
    dudrow = 0.1
    dvdcol = -0.4
    dvdrow = 0.34
    col = 5.6
    row = -10.4

    if kind == 'row-col':
        jac = Jacobian(col=col,
                       row=row,
                       dudcol=dudcol,
                       dudrow=dudrow,
                       dvdcol=dvdcol,
                       dvdrow=dvdrow)
    elif kind == 'x-y':
        jac = Jacobian(x=col,
                       y=row,
                       dudx=dudcol,
                       dudy=dudrow,
                       dvdx=dvdcol,
                       dvdy=dvdrow)
    else:
        wcs = galsim.JacobianWCS(dudx=dudcol,
                                 dudy=dudrow,
                                 dvdx=dvdcol,
                                 dvdy=dvdrow)
        jac = Jacobian(x=col, y=row, wcs=wcs)

    assert np.allclose(jac.row0, row)
    assert np.allclose(jac.col0, col)
    assert np.allclose(jac.dudcol, dudcol)
    assert np.allclose(jac.dudrow, dudrow)
    assert np.allclose(jac.dvdcol, dvdcol)
    assert np.allclose(jac.dvdrow, dvdrow)

    assert np.allclose(jac.det, dudcol * dvdrow - dudrow * dvdcol)
    assert np.allclose(jac.sdet,
                       np.sqrt(np.abs(dudcol * dvdrow - dudrow * dvdcol)))
    assert np.allclose(jac.scale,
                       np.sqrt(np.abs(dudcol * dvdrow - dudrow * dvdcol)))

    r, c = 20.0, -44.5
    v, u = jac.get_vu(r, c)
    assert np.allclose(v, dvdrow * (r - row) + dvdcol * (c - col))
    assert np.allclose(u, dudrow * (r - row) + dudcol * (c - col))
    v, u = jac(r, c)
    assert np.allclose(v, dvdrow * (r - row) + dvdcol * (c - col))
    assert np.allclose(u, dudrow * (r - row) + dudcol * (c - col))

    v, u = 20.0, -44.5
    r, c = jac.get_rowcol(v, u)
    assert np.allclose(r, (dudcol * v - dvdcol * u) / jac.det + row)
    assert np.allclose(c, (-dudrow * v + dvdrow * u) / jac.det + col)

    gs_wcs = jac.get_galsim_wcs()
    assert np.allclose(gs_wcs.dudx, jac.dudcol)
    assert np.allclose(gs_wcs.dudy, jac.dudrow)
    assert np.allclose(gs_wcs.dvdx, jac.dvdcol)
    assert np.allclose(gs_wcs.dvdy, jac.dvdrow)

    cpy_jac = jac.copy()
    cpy_jac.set_cen(row=-11, col=-12)
    assert np.allclose(jac.row0, row)
    assert np.allclose(jac.col0, col)
    assert np.allclose(cpy_jac.row0, -11)
    assert np.allclose(cpy_jac.col0, -12)
Beispiel #25
0
def _run_moments(*, n_sims, rng, dudx, dudy, dvdx, dvdy):
    """Run metacal on an image composed of stamps w/ constant noise.

    Parameters
    ----------
    n_sims : int
        The number of objects to run.
    rng : np.random.RandomState
        An RNG to use.
    dudx : float
        The du/dx Jacobian component.
    dudy : float
        The du/dy Jacobian component.
    dydx : float
        The dv/dx Jacobian component.
    dvdy : float
        The dv/dy Jacobian component.

    Returns
    -------
    result : dict
        A dictionary with each of the metacal catalogs.
    """

    method = 'no_pixel'

    stamp_size = 33
    psf_stamp_size = 33

    cen = (stamp_size - 1) / 2
    psf_cen = (psf_stamp_size - 1) / 2

    s2n = 1e16
    flux = 1e6

    galsim_jac = galsim.JacobianWCS(dudx=dudx, dudy=dudy, dvdx=dvdx, dvdy=dvdy)

    gal = galsim.Exponential(half_light_radius=0.5).withFlux(flux)
    psf = galsim.Gaussian(fwhm=0.9).withFlux(1)
    obj = galsim.Convolve(gal, psf)
    obj_im = obj.drawImage(nx=111, ny=111).array
    noise = np.sqrt(np.sum(obj_im**2)) / s2n

    data = []
    for ind in tqdm.trange(n_sims):
        ################################
        # make the obs

        # psf
        psf_im = psf.drawImage(nx=psf_stamp_size,
                               ny=psf_stamp_size,
                               wcs=galsim_jac,
                               method=method).array
        psf_noise = np.sqrt(np.sum(psf_im**2)) / 10000
        wgt = np.ones_like(psf_im) / psf_noise**2
        psf_im += (rng.normal(size=psf_im.shape) * psf_noise)
        psf_jac = ngmix.Jacobian(x=psf_cen,
                                 y=psf_cen,
                                 dudx=dudx,
                                 dudy=dudy,
                                 dvdx=dvdx,
                                 dvdy=dvdy)
        psf_obs = ngmix.Observation(image=psf_im, weight=wgt, jacobian=psf_jac)

        # now render object
        scale = psf_jac.scale
        shift = rng.uniform(low=-scale / 2, high=scale / 2, size=2)
        _obj = obj.shift(dx=shift[0], dy=shift[1])
        xy = galsim_jac.toImage(galsim.PositionD(shift))
        im = _obj.drawImage(nx=stamp_size,
                            ny=stamp_size,
                            wcs=galsim_jac,
                            method=method).array
        jac = ngmix.Jacobian(x=cen + xy.x,
                             y=cen + xy.y,
                             dudx=dudx,
                             dudy=dudy,
                             dvdx=dvdx,
                             dvdy=dvdy)
        wgt = np.ones_like(im) / noise**2
        nse = rng.normal(size=im.shape) * noise
        im += (rng.normal(size=im.shape) * noise)
        obs = ngmix.Observation(image=im,
                                weight=wgt,
                                noise=nse,
                                bmask=np.zeros_like(im, dtype=np.int32),
                                ormask=np.zeros_like(im, dtype=np.int32),
                                jacobian=jac,
                                psf=psf_obs)

        # build the mbobs
        mbobs = ngmix.MultiBandObsList()
        obslist = ngmix.ObsList()
        obslist.append(obs)
        mbobs.append(obslist)

        mbobs.meta['id'] = ind + 1
        # these settings do not matter that much I think
        mbobs[0].meta['Tsky'] = 1
        mbobs[0].meta['magzp_ref'] = 26.5
        mbobs[0][0].meta['orig_col'] = ind + 1
        mbobs[0][0].meta['orig_row'] = ind + 1

        ################################
        # run the fitters
        try:
            res = _run_moments_fitter(mbobs, rng)
        except Exception as e:
            print(e)
            res = None

        if res is not None:
            data.append(res)

    if len(data) > 0:
        res = data
    else:
        res = None

    return res
Beispiel #26
0
import numpy as np
import galsim
import pytest

from ..gauss_pix_psf import GaussPixPSF


@pytest.mark.parametrize('wcs', [
    galsim.PixelScale(0.263),
    galsim.PixelScale(0.5),
    galsim.JacobianWCS(-0.2634420129421214, 0.0006503502840044033,
                       -0.0003966040125006026, -0.26354105026622404)
])
def test_gauss_pix_psf_smoke(wcs):
    psf_model = GaussPixPSF()
    psf = psf_model.getPSF(galsim.PositionD(x=1, y=2), wcs)
    psf_im = psf.drawImage(nx=53, ny=53, wcs=wcs).array

    seed = 4098
    rng = np.random.RandomState(seed=seed)
    g1 = rng.normal() * 0.01
    g2 = rng.normal() * 0.01
    fwhm = (rng.uniform(low=-0.1, high=0.1) + 1.0) * 0.9
    gs = galsim.Gaussian(fwhm=fwhm).shear(g1=g1, g2=g2).withFlux(1.0)
    test_im = gs.drawImage(nx=53, ny=53, wcs=wcs).array

    assert np.allclose(psf_im, test_im, atol=2e-5, rtol=0)


def test_gauss_pix_psf_reproducible():
    wcs = galsim.PixelScale(0.5)
Beispiel #27
0
def test_metacal_tracking():
    """Test that the noise tracking works for the metacal use case involving deconvolution and
    reconvolution by almost the same PSF.

    This test is similar to the above test_uncorrelated_noise_tracking, except the modifications
    are based on what is done for the metacal procedure.
    """
    import math

    def check_noise(noise_image, noise, msg):
        # A helper function to check that the current noise in the image is properly described
        # by the given CorrelatedNoise object
        noise2 = galsim.CorrelatedNoise(noise_image)
        print('noise = ', noise)
        print('noise2 = ', noise2)
        np.testing.assert_almost_equal(noise.getVariance(),
                                       noise2.getVariance(),
                                       decimal=CHECKNOISE_NDECIMAL,
                                       err_msg=msg +
                                       ': variance does not match.')
        cf_im1 = galsim.Image(8, 8, wcs=noise_image.wcs)
        cf_im2 = cf_im1.copy()
        noise.drawImage(image=cf_im1)
        noise2.drawImage(image=cf_im2)
        np.testing.assert_almost_equal(cf_im1.array,
                                       cf_im2.array,
                                       decimal=CHECKNOISE_NDECIMAL,
                                       err_msg=msg +
                                       ': image of cf does not match.')

    def check_symm_noise(noise_image, msg):
        # A helper funciton to see if a noise image has 4-fold symmetric noise.
        im2 = noise_image.copy()
        # Clear out any wcs to make the test simpler
        im2.wcs = galsim.PixelScale(1.)
        noise = galsim.CorrelatedNoise(im2)
        cf = noise.drawImage(
            galsim.Image(bounds=galsim.BoundsI(-1, 1, -1, 1), scale=1))
        # First check the variance
        print('variance: ', cf(0, 0), noise.getVariance())
        np.testing.assert_almost_equal(cf(0, 0) / noise.getVariance(),
                                       1.0,
                                       decimal=VAR_NDECIMAL,
                                       err_msg=msg +
                                       ':: noise variance is wrong.')
        cf_plus = np.array([cf(1, 0), cf(-1, 0), cf(0, 1), cf(0, -1)])
        cf_cross = np.array([cf(1, 1), cf(-1, -1), cf(-1, 1), cf(1, -1)])
        print('plus pattern: ', cf_plus)
        print('diff relative to dc: ', (cf_plus - np.mean(cf_plus)) / cf(0, 0))
        print('cross pattern: ', cf_cross)
        print('diff relative to dc: ',
              (cf_cross - np.mean(cf_cross)) / cf(0, 0))
        # For now, don't make these asserts.  Just print whether they will pass or fail.
        if True:
            if np.all(np.abs((cf_plus - np.mean(cf_plus)) / cf(0, 0)) < 0.01):
                print('plus test passes')
            else:
                print('*** FAIL ***')
                print(msg + ': plus pattern is not constant')
            if np.all(
                    np.abs((cf_cross - np.mean(cf_cross)) / cf(0, 0)) < 0.01):
                print('cross test passes')
            else:
                print('*** FAIL ***')
                print(msg + ': cross pattern is not constant')
        else:
            np.testing.assert_almost_equal(
                (cf_plus - np.mean(cf_plus)) / cf(0, 0),
                0.0,
                decimal=2,
                err_msg=msg + ': plus pattern is not constant')
            np.testing.assert_almost_equal(
                (cf_cross - np.mean(cf_cross)) / cf(0, 0),
                0.0,
                decimal=2,
                err_msg=msg + ': cross pattern is not constant')

    seed = 1234567  # For use as a unit test, we need a specific seed
    #seed = 0  # During testing, it's useful to see how numbers flop around to know if
    # something is systematic or random.
    rng = galsim.BaseDeviate(seed)

    noise_var = 1.3
    im_size = 1024
    dg = 0.1  # This is bigger than metacal would use, but it makes the test easier.

    # Use a non-trivial wcs...
    #wcs = galsim.JacobianWCS(0.26, 0.04, -0.04, -0.26)  # Rotation + flip.  No shear.
    wcs = galsim.JacobianWCS(0.26, 0.03, 0.08, -0.21)  # Fully complex
    #dudx =  0.12*0.26
    #dudy =  1.10*0.26
    #dvdx = -0.915*0.26
    #dvdy = -0.04*0.26
    #wcs = galsim.JacobianWCS(dudx, dudy, dvdx, dvdy)  # Even more extreme

    # And an asymmetric PSF
    #orig_psf = galsim.Gaussian(fwhm=0.9).shear(g1=0.05, g2=0.03)
    # This one is small enough not to be fully Nyquist sampled, which makes things harder.
    orig_psf = galsim.Gaussian(fwhm=0.7).shear(g1=0.05, g2=0.03)

    # pixel is the pixel in world coords
    pixel = wcs.toWorld(galsim.Pixel(scale=1))
    pixel_inv = galsim.Deconvolve(pixel)

    psf_image = orig_psf.drawImage(nx=im_size, ny=im_size, wcs=wcs)

    # Metacal only has access to the PSF as an image, so use this from here on.
    psf = galsim.InterpolatedImage(psf_image)
    psf_nopix = galsim.Convolve([psf, pixel_inv])
    psf_inv = galsim.Deconvolve(psf)

    # Not what is done currently, but using a smoother target PSF helps make sure the
    # zeros in the deconvolved PSF get adequately zeroed out.
    def get_target_psf(psf):
        dk = 0.1  # The resolution in k space for the KImage
        small_kval = 1.e-2  # Find the k where the given psf hits this kvalue
        smaller_kval = 3.e-3  # Target PSF will have this kvalue at the same k

        kim = psf.drawKImage(scale=dk)
        karr_r = kim.real.array
        # Find the smallest r where the kval < small_kval
        nk = karr_r.shape[0]
        kx, ky = np.meshgrid(np.arange(-nk / 2, nk / 2),
                             np.arange(-nk / 2, nk / 2))
        ksq = (kx**2 + ky**2) * dk**2
        ksq_max = np.min(ksq[karr_r < small_kval * psf.flux])

        # We take our target PSF to be the (round) Gaussian that is even smaller at this ksq
        # exp(-0.5 * ksq_max * sigma_sq) = smaller_kval
        sigma_sq = -2. * np.log(smaller_kval) / ksq_max
        return galsim.Gaussian(sigma=np.sqrt(sigma_sq))

    # The target PSF dilates the part without the pixel, but reconvolve by the real pixel.
    #psf_target_nopix = psf_nopix.dilate(1. + 2.*dg)
    #psf_target_nopix = orig_psf.dilate(1. + 4.*dg)
    psf_target_nopix = get_target_psf(psf_nopix.shear(g1=dg))
    print('PSF target HLR = ', psf_target_nopix.calculateHLR())
    print('PSF target FWHM = ', psf_target_nopix.calculateFWHM())
    psf_target = galsim.Convolve([psf_target_nopix, pixel])

    # Make an image of pure (white) Gaussian noise
    # Normally, there would be a galaxy in this image, but for the tests, we just have noise.
    obs_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
    obs_image.addNoise(
        galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))

    # The noise on this image should be describable as an UncorrelatedNoise object:
    noise = galsim.UncorrelatedNoise(variance=noise_var, wcs=wcs)
    check_noise(obs_image, noise, 'initial UncorrelatedNoise model is wrong')

    # Make an InterpolatedImage profile to use for manipulating this image
    # We can get away with no padding here, since our image is so large, but normally, you would
    # probably want to pad this with noise padding.
    ii = galsim.InterpolatedImage(obs_image, pad_factor=1)
    ii.noise = noise

    # If we draw it back, the attached noise attribute should still be correct
    check_noise(ii.drawImage(obs_image.copy(), method='no_pixel'), ii.noise,
                'noise model is wrong for InterpolatedImage')

    # Here is the metacal process for which we want to understand the noise.
    # We'll try a few different methods.
    shear = galsim.Shear(g1=dg)
    sheared_obj = galsim.Convolve(ii, psf_inv).shear(shear)
    final_obj = galsim.Convolve(psf_target, sheared_obj)
    final_image = final_obj.drawImage(obs_image.copy(), method='no_pixel')

    try:
        check_symm_noise(final_image, 'Initial image')
        #didnt_fail = True
        # This bit doesn't work while we are not actually raising exceptions in check_symm_noise
        # So we expect to see **FAIL** text at this point.
        print(
            'The above tests are expected to **FAIL**.  This is not a problem.'
        )
        didnt_fail = False
    except AssertionError as e:
        print('As expected initial image fails symmetric noise test:')
        print(e)
        didnt_fail = False
    if didnt_fail:
        assert False, 'Initial image was expected to fail symmetric noise test, but passed.'

    if True:
        print('\n\nStrategy 1:')
        # Strategy 1: Use the noise attribute attached to ii and use it to either whiten or
        #             symmetrize the noise in the final image.
        # Note: The check_noise tests fail.  I think because the convolve and deconvolve impose
        #       a maxk = that of the psf.  Which is too small for an accurate rendering of the
        #       correlation function (here just an autocorrelation of a Pixel.
        # The whiten tests kind of work, but they add a lot of extra noise.  Much more than
        # strategy 4 below.  So the level of correlation remaining is pretty well below the
        # dc variance.  Symmetrize doesn't add much noise, but the residual correlation is about
        # the same, which means it doesn't pass the test relative to the lower dc variance.

        # First, deconvolve and reconvolve by the same PSF:
        test_obj = galsim.Convolve([ii, psf, psf_inv])
        # This fails...
        if False:
            check_noise(
                test_obj.drawImage(obs_image.copy(),
                                   method='no_pixel'), test_obj.noise,
                'noise model is wrong after convolve/deconvolve by psf')

        # Now use a slightly dilated PSF for the reconvolution:
        test_obj = galsim.Convolve([ii, psf_target, psf_inv])
        if False:
            check_noise(
                test_obj.drawImage(obs_image.copy(), method='no_pixel'),
                test_obj.noise, 'noise model is wrong for dilated target psf')

        # Finally, include the shear step.  This was done above with sheared_obj, final_obj.
        if False:
            check_noise(final_image, final_obj.noise,
                        'noise model is wrong when including small shear')

        # If we whiten using this noise model, we should get back to white noise.
        t3 = time.time()
        final_image2 = final_image.copy()  # Don't clobber the original
        final_var = final_image2.whitenNoise(final_obj.noise)
        t4 = time.time()
        print('Noise tracking method with whiten: final_var = ', final_var)
        print('Check: direct variance = ', np.var(final_image2.array))
        check_symm_noise(final_image2, 'noise whitening does not work')
        print('Time for noise tracking with whiten = ', t4 - t3)

        # Using symmetrizeNoise should add less noise, but also work.
        t3 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.symmetrizeNoise(final_obj.noise)
        t4 = time.time()
        print('Noise tracking method with symmetrize: final_var = ', final_var)
        print('Check: direct variance = ', np.var(final_image2.array))
        check_symm_noise(final_image2, 'noise symmetrizing does not work')
        print('Time for noise tracking with symmetrize = ', t4 - t3)

    if True:
        print('\n\nStrategy 2:')
        # Strategy 2: Don't trust the noise tracking. Track a noise image through the same process
        #             and then measure the noise from that image.  Use it to either whiten or
        #             symmetrize the noise in the final image.
        # Note: This method doesn't work any better.  The added noise for whitening is even more
        # than strategy 1.  And the remaining correlations are still similarly significant for the
        # symmetrize version.  A little smaller than strategy 1, but not enough to pass our tests.

        # Make another noise image, since we don't actually have access to a pure noise image
        # for real objects.  But we should be able to estimate the variance in the image.
        t3 = time.time()
        noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        noise_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1)
        sheared_noise_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear)
        final_noise_obj = galsim.Convolve(psf_target, sheared_noise_obj)
        final_noise_image = final_noise_obj.drawImage(obs_image.copy(),
                                                      method='no_pixel')

        # Use this to construct an appropriate CorrelatedNoise object
        noise = galsim.CorrelatedNoise(final_noise_image)
        t4 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.whitenNoise(noise)
        t5 = time.time()

        check_noise(
            final_noise_image, noise,
            'noise model is wrong when direct measuring the final noise image')

        print('Direct noise method with whiten: final_var = ', final_var)
        # Neither of these work currently, so maybe a bug in the whitening code?
        # Or possibly in my logic here.
        check_symm_noise(
            final_image2,
            'whitening the noise using direct noise model failed')
        print('Time for direct noise with whitening = ', t5 - t3)

        t6 = time.time()
        final_image2 = final_image.copy()
        final_var = final_image2.symmetrizeNoise(noise)
        t7 = time.time()

        print('Direct noise method with symmetrize: final_var = ', final_var)
        check_symm_noise(
            final_image2,
            'symmetrizing the noise using direct noise model failed')
        print('Time for direct noise with symmetrizing = ', t7 - t6 + t4 - t3)

    if False:
        print('\n\nStrategy 3:')
        # Strategy 3: Make a noise field and do the same operations as we do to the main image
        #             except use the opposite shear value.  Add this noise field to the final
        #             image to get a symmetric noise field.
        # Note: This method works!  But only for square pixels.  However, they may be rotated
        # or flipped. Just not sheared.
        # Update: I think this method won't ever work for non-square pixels.  The reason it works
        # for square pixels is that in that case, it is equivalent to strategy 4.
        t3 = time.time()

        # Make another noise image
        rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        rev_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1)

        rev_sheared_obj = galsim.Convolve(rev_ii, psf_inv).shear(-shear)
        rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj)
        rev_final_image = rev_final_obj.drawImage(obs_image.copy(),
                                                  method='no_pixel')

        # Add the reverse-sheared noise image to the original image.
        final_image2 = final_image + rev_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Reverse shear method: final_var = ', final_var)
        check_symm_noise(final_image2, 'using reverse shear does not work')
        print('Time for reverse shear method = ', t4 - t3)

    if True:
        print('\n\nStrategy 4:')
        # Strategy 4: Make a noise field and do the same operations as we do to the main image,
        #             then rotate it by 90 degress and add it to the final image.
        # This method works!  Even for an arbitrarily sheared wcs.
        t3 = time.time()

        # Make another noise image
        noise_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        noise_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        noise_ii = galsim.InterpolatedImage(noise_image, pad_factor=1)

        noise_sheared_obj = galsim.Convolve(noise_ii, psf_inv).shear(shear)
        noise_final_obj = galsim.Convolve(psf_target, noise_sheared_obj)
        noise_final_image = noise_final_obj.drawImage(obs_image.copy(),
                                                      method='no_pixel')

        # Rotate the image by 90 degrees
        rot_noise_final_image = galsim.Image(
            np.ascontiguousarray(np.rot90(noise_final_image.array)))

        # Add the rotated noise image to the original image.
        final_image2 = final_image + rot_noise_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Rotate image method: final_var = ', final_var)
        check_symm_noise(final_image2,
                         'using rotated noise image does not work')
        print('Time for rotate image method = ', t4 - t3)

    if False:
        print('\n\nStrategy 5:')
        # Strategy 5: The same as strategy 3, except we target the effective net transformation
        #             done by strategy 4.
        # I think this strategy probably can't work for non-square pixels, because the shear
        # happens before the convolution by the PSF.  And if the wcs is non-square, then the
        # PSF is sheared relative to the pixels.  That shear isn't being accounted for here,
        # so the net result isn't equivalent to rotating by 90 degrees at the end.
        t3 = time.time()

        # Make another noise image
        rev_image = galsim.Image(im_size, im_size, init_value=0, wcs=wcs)
        rev_image.addNoise(
            galsim.GaussianNoise(rng=rng, sigma=math.sqrt(noise_var)))
        rev_ii = galsim.InterpolatedImage(rev_image, pad_factor=1)

        # Find the effective transformation to apply in sky coordinates that matches what
        # you would get by applying the shear in sky coords, going to image coords and then
        # rotating by 90 degrees.
        #
        # If J is the jacobian of the wcs, and S1 is the applied shear, then we want to find
        # S2 such that J^-1 S2 = R90 J^-1 S1
        jac = wcs.jacobian()
        J = jac.getMatrix()
        Jinv = jac.inverse().getMatrix()
        S1 = shear.getMatrix()
        R90 = np.array([[0, -1], [1, 0]])
        S2 = J.dot(R90).dot(Jinv).dot(S1)
        scale, rev_shear, rev_theta, flip = galsim.JacobianWCS(
            *S2.flatten()).getDecomposition()
        # Flip should be False, and scale should be essentially 1.0.
        assert flip == False
        assert abs(scale - 1.) < 1.e-8

        rev_sheared_obj = galsim.Convolve(
            rev_ii, psf_inv).rotate(rev_theta).shear(rev_shear)
        rev_final_obj = galsim.Convolve(psf_target, rev_sheared_obj)
        rev_final_image = rev_final_obj.drawImage(obs_image.copy(),
                                                  method='no_pixel')

        # Add the reverse-sheared noise image to the original image.
        final_image2 = final_image + rev_final_image
        t4 = time.time()

        # The noise variance in the end should be 2x as large as the original
        final_var = np.var(final_image2.array)
        print('Alternate reverse shear method: final_var = ', final_var)
        check_symm_noise(final_image2,
                         'using alternate reverse shear does not work')
        print('Time for alternate reverse shear method = ', t4 - t3)
Beispiel #28
0
def interleaveImages(im_list, N, offsets, add_flux=True, suppress_warnings=False,
    catch_offset_errors=True):
    """
    Interleaves the pixel values from two or more images and into a single larger image.

    This routine converts a list of images taken at a series of (uniform) dither offsets into a
    single higher resolution image, where the value in each final pixel is the observed pixel
    value from exactly one of the original images.  It can be used to build a Nyquist-sampled image
    from a set of images that were observed with pixels larger than the Nyquist scale.

    In the original observed images, the integration of the surface brightness over the pixels is
    equivalent to convolution by the pixel profile and then sampling at the centers of the pixels.
    This procedure simulates an observation sampled at a higher resolution than the original images,
    while retaining the original pixel convolution.

    Such an image can be obtained in a fairly simple manner in simulations of surface brightness
    profiles by convolving them explicitly with the native pixel response and setting a lower
    sampling scale (or higher sampling rate) using the `pixel_scale' argument in drawImage()
    routine and setting the `method' parameter to `no_pixel'.

    However, pixel level detector effects can be included only on images drawn at the native pixel
    scale, which happen to be undersampled in most cases. Nyquist-sampled images that also include
    the effects of detector non-idealities can be obtained by drawing multiple undersampled images
    (with the detector effects included) that are offset from each other by a fraction of a pixel.

    This is similar to other procedures that build a higher resolution image from a set of low
    resolution images, such as MultiDrizzle and IMCOM. A disadvantage of this routine compared to
    ther others is that the images must be offset in equal steps in each direction. This is
    difficult to acheive with real observations but can be precisely acheived in a series of
    simulated images.

    An advantage of this procedure is that the noise in the final image is not correlated as the
    pixel values are each taken from just a single input image. Thus, this routine preserves the
    noise properties of the pixels.

    Here's an example script using this routine:

    Interleaving two Gaussian images along the x-axis
    -------------------------------------------------

        >>> n = 2
        >>> gal = galsim.Gaussian(sigma=2.8)
        >>> DX = numpy.arange(0.0,1.0,1./n)
        >>> DX -= DX.mean()
        >>> im_list, offsets = [], []
        >>> for dx in DX:
            ... offset = galsim.PositionD(dx,0.0)
            ... offsets.append(offset)
            ... im = galsim.Image(16,16)
            ... gal.drawImage(image=im,offset=offset,scale=1.0)
            ... im.applyNonlinearity(lambda x: x - 0.01*x**2) # detector effects
            ... im_list.append(im)
        >>> img = galsim.utilities.interleaveImages(im_list=im_list,N=(n,1),offsets=offsets)

    @param im_list             A list containing the galsim.Image instances to be interleaved.
    @param N                   Number of images to interleave in either directions. It can be of
                               type `int' if equal number of images are interleaved in both
                               directions or a list or tuple of two integers, containing the number
                               of images in x and y directions respectively.
    @param offsets             A list containing the offsets as galsim.PositionD instances
                               corresponding to every image in `im_list'. The offsets must be spaced
                               equally and must span an entire pixel area. The offset values must
                               be symmetric around zero, hence taking positive and negative values,
                               with upper and lower limits of +0.5 and -0.5 (limit values excluded).
    @param add_flux            Should the routine add the fluxes of all the images (True) or average
                               them (False)? [default: True]
    @param suppress_warnings   Suppresses the warnings about the pixel scale of the output, if True.
                               [default: False]
    @param catch_offset_errors Checks for the consistency of `offsets` with `N` and raises Errors
                               if inconsistencies found (True). Recommended, but could slow down
                               the routine a little. [default: True]

    @returns the interleaved image
    """
    if isinstance(N,int):
        n1,n2 = N,N
    elif hasattr(N,'__iter__'):
        if len(N)==2:
            n1,n2 = N
        else:
            raise TypeError("'N' has to be a list or a tuple of two integers")
        if not (n1 == int(n1) and n2 == int(n2)):
            raise TypeError("'N' has to be of type int or a list or a tuple of two integers")
        n1 = int(n1)
        n2 = int(n2)
    else:
        raise TypeError("'N' has to be of type int or a list or a tuple of two integers")

    if len(im_list)<2:
        raise TypeError("'im_list' needs to have at least two instances of galsim.Image")

    if (n1*n2 != len(im_list)):
        raise ValueError("'N' is incompatible with the number of images in 'im_list'")

    if len(im_list)!=len(offsets):
        raise ValueError("'im_list' and 'offsets' must be lists of same length")

    for offset in offsets:
        if not isinstance(offset,galsim.PositionD):
            raise TypeError("'offsets' must be a list of galsim.PositionD instances")

    if not isinstance(im_list[0],galsim.Image):
        raise TypeError("'im_list' must be a list of galsim.Image instances")

    # These should be the same for all images in `im_list'.
    y_size, x_size = im_list[0].array.shape
    wcs = im_list[0].wcs

    for im in im_list[1:]:
        if not isinstance(im,galsim.Image):
            raise TypeError("'im_list' must be a list of galsim.Image instances")

        if im.array.shape != (y_size,x_size):
            raise ValueError("All galsim.Image instances in 'im_list' must be of the same size")

        if im.wcs != wcs:
            raise ValueError(
                "All galsim.Image instances in 'im_list' must have the same WCS")

    img_array = np.zeros((n2*y_size,n1*x_size))
    # The tricky part - going from (x,y) Image coordinates to array indices
    # DX[i'] = -(i+0.5)/n+0.5 = -i/n + 0.5*(n-1)/n
    #    i  = -n DX[i'] + 0.5*(n-1)
    for k in range(len(offsets)):
        dx, dy = offsets[k].x, offsets[k].y

        i = int(round((n1-1)*0.5-n1*dx))
        j = int(round((n2-1)*0.5-n2*dy))

        if catch_offset_errors is True:
            err_i = (n1-1)*0.5-n1*dx - round((n1-1)*0.5-n1*dx)
            err_j = (n2-1)*0.5-n2*dy - round((n2-1)*0.5-n2*dy)
            tol = 1.e-6
            if abs(err_i)>tol or abs(err_j)>tol:
                raise ValueError("'offsets' must be a list of galsim.PositionD instances with x "
                            +"values spaced by 1/{0} and y values by 1/{1} around 0 for N = ".format(n1,n2)+str(N))

            if i<0 or j<0 or i>=x_size or j>=y_size:
                raise ValueError("'offsets' must be a list of galsim.PositionD instances with x "
                            +"values spaced by 1/{0} and y values by 1/{1} around 0 for N = ".format(n1,n2)+str(N))

        img_array[j::n2,i::n1] = im_list[k].array[:,:]

    img = galsim.Image(img_array)
    if not add_flux:
        # Fix the flux normalization
        img /= 1.0*len(im_list)

    # Assign an appropriate WCS for the output
    if wcs is not None and wcs.isUniform():
        jac = wcs.jacobian()
        dudx, dudy, dvdx, dvdy = jac.dudx, jac.dudy, jac.dvdx, jac.dvdy
        img_wcs = galsim.JacobianWCS(1.*dudx/n1,1.*dudy/n2,1.*dvdx/n1,1.*dvdy/n2)
        ## Since pixel scale WCS is not equal to its jacobian, checking if img_wcs is a pixel scale
        img_wcs_decomp = img_wcs.getDecomposition()
        if img_wcs_decomp[1].g==0: ## getDecomposition returns scale,shear,angle,flip
            img.wcs = galsim.PixelScale(img_wcs_decomp[0])
        else:
            img.wcs = img_wcs

    elif suppress_warnings is False:
        import warnings
        warnings.warn("Interleaved image could not be assigned a WCS automatically.")

    # Assign a possibly non-trivial origin and warn if individual image have different origins.
    orig = im_list[0].origin()
    img.setOrigin(orig)
    for im in im_list[1:]:
        if not im.origin()==orig:
            import warnings
            warnings.warn("Images in `im_list' have multiple values for origin. Assigning the \
            origin of the first Image instance in 'im_list' to the interleaved image.")
            break

    return img
Beispiel #29
0
def test_shapelet_fit():
    """Test fitting a Shapelet decomposition of an image
    """
    for method, norm in [('no_pixel','f'), ('sb','sb')]:
        # We fit a shapelet approximation of a distorted Moffat profile:
        flux = 20
        psf = galsim.Moffat(beta=3.4, half_light_radius=1.2, flux=flux)
        psf = psf.shear(g1=0.11,g2=0.07).shift(0.03,0.04)
        scale = 0.2
        pixel = galsim.Pixel(scale)
        conv = galsim.Convolve([psf,pixel])
        im1 = conv.drawImage(scale=scale, method=method)

        sigma = 1.2  # Match half-light-radius as a decent first approximation.
        shapelet = galsim.Shapelet.fit(sigma, 10, im1, normalization=norm)
        print('fitted shapelet coefficients = ',shapelet.bvec)

        # Check flux
        print('flux = ',shapelet.flux,'  cf. ',flux)
        np.testing.assert_almost_equal(shapelet.flux / flux, 1., 1,
                err_msg="Fitted shapelet has the wrong flux")

        # Test centroid
        print('centroid = ',shapelet.centroid,'  cf. ',conv.centroid)
        np.testing.assert_almost_equal(shapelet.centroid.x, conv.centroid.x, 2,
                err_msg="Fitted shapelet has the wrong centroid (x)")
        np.testing.assert_almost_equal(shapelet.centroid.y, conv.centroid.y, 2,
                err_msg="Fitted shapelet has the wrong centroid (y)")

        # Test drawing image from shapelet
        im2 = im1.copy()
        shapelet.drawImage(im2, method=method)
        # Check that images are close to the same:
        print('norm(diff) = ',np.sum((im1.array-im2.array)**2))
        print('norm(im) = ',np.sum(im1.array**2))
        print('max(diff) = ',np.max(np.abs(im1.array-im2.array)))
        print('max(im) = ',np.max(np.abs(im1.array)))
        peak_scale = np.max(np.abs(im1.array))*3  # Check agreement to within 3% of peak value.
        np.testing.assert_almost_equal(im2.array/peak_scale, im1.array/peak_scale, decimal=2,
                err_msg="Shapelet version not a good match to original")

        # Remeasure -- should now be very close to the same.
        shapelet2 = galsim.Shapelet.fit(sigma, 10, im2, normalization=norm)
        np.testing.assert_equal(shapelet.sigma, shapelet2.sigma,
                err_msg="Second fitted shapelet has the wrong sigma")
        np.testing.assert_equal(shapelet.order, shapelet2.order,
                err_msg="Second fitted shapelet has the wrong order")
        np.testing.assert_almost_equal(shapelet.bvec, shapelet2.bvec, 6,
                err_msg="Second fitted shapelet coefficients do not match original")

        # Test drawing off center
        im2 = im1.copy()
        offset = galsim.PositionD(0.3,1.4)
        shapelet.drawImage(im2, method=method, offset=offset)
        shapelet2 = galsim.Shapelet.fit(sigma, 10, im2, normalization=norm,
                                        center=im2.true_center + offset)
        np.testing.assert_equal(shapelet.sigma, shapelet2.sigma,
                err_msg="Second fitted shapelet has the wrong sigma")
        np.testing.assert_equal(shapelet.order, shapelet2.order,
                err_msg="Second fitted shapelet has the wrong order")
        np.testing.assert_almost_equal(shapelet.bvec, shapelet2.bvec, 6,
                err_msg="Second fitted shapelet coefficients do not match original")

    assert_raises(ValueError, galsim.Shapelet.fit, sigma, 10, im1, normalization='invalid')

    # Haven't gotten around to implementing this yet...
    im2.wcs = galsim.JacobianWCS(0.2,0.01,0.01,0.2)
    with assert_raises(NotImplementedError):
        galsim.Shapelet.fit(sigma, 10, im2)
Beispiel #30
0
def main(argv):

    ## fixed parameters
    random_seed = 314
    rng = galsim.BaseDeviate(random_seed)
    random_dir = galsim.UniformDeviate(rng)
    poisson_noise = galsim.PoissonNoise(rng)
    dither_i = 22535
    use_SCA = 1
    filter_ = 'H158'
    stamp_size = 32
    hlr = 1.0
    bpass = wfirst.getBandpasses(AB_zeropoint=True)[filter_]
    galaxy_sed_n = galsim.SED('Mrk_33_spec.dat',
                              wave_type='Ang',
                              flux_type='flambda')

    ## variable arguments
    gal_num = int(sys.argv[1])
    PA1 = int(sys.argv[2])
    PA2 = int(sys.argv[3])
    galaxy_model = sys.argv[4]
    PSF_model = sys.argv[5]
    shape = sys.argv[6]
    output_name = sys.argv[7]

    # when using more galaxies than the length of truth file.
    res_noshear = np.zeros(gal_num,
                           dtype=[('ind', int), ('flux', float), ('g1', float),
                                  ('g2', float), ('e1', float), ('e2', float),
                                  ('snr', float), ('hlr', float),
                                  ('flags', int)])
    res_1p = np.zeros(gal_num,
                      dtype=[('ind', int), ('flux', float), ('g1', float),
                             ('g2', float), ('e1', float), ('e2', float),
                             ('snr', float), ('hlr', float), ('flags', int)])
    res_1m = np.zeros(gal_num,
                      dtype=[('ind', int), ('flux', float), ('g1', float),
                             ('g2', float), ('e1', float), ('e2', float),
                             ('snr', float), ('hlr', float), ('flags', int)])
    res_2p = np.zeros(gal_num,
                      dtype=[('ind', int), ('flux', float), ('g1', float),
                             ('g2', float), ('e1', float), ('e2', float),
                             ('snr', float), ('hlr', float), ('flags', int)])
    res_2m = np.zeros(gal_num,
                      dtype=[('ind', int), ('flux', float), ('g1', float),
                             ('g2', float), ('e1', float), ('e2', float),
                             ('snr', float), ('hlr', float), ('flags', int)])
    if shape == 'metacal':
        res_tot = [res_noshear, res_1p, res_1m, res_2p, res_2m]
    elif shape == 'noboot':
        res_tot = [res_noshear, res_1p, res_1m, res_2p, res_2m]
    elif shape == 'ngmix':
        res_tot = [res_noshear]

    PSF = getPSF(PSF_model, use_SCA, filter_, bpass)
    position_angle1 = PA1  #degrees
    position_angle2 = PA2  #degrees
    wcs1, sky_level1 = get_wcs(dither_i, use_SCA, filter_, stamp_size,
                               position_angle1)
    wcs2, sky_level2 = get_wcs(dither_i, use_SCA, filter_, stamp_size,
                               position_angle2)
    wcs = [wcs1, wcs2]
    sky_level = [sky_level1, sky_level2]

    t0 = time.time()
    for i_gal in range(gal_num):
        if i_gal % size != rank:
            continue

        if i_gal % 100 == 0:
            print('rank', rank, 'object number, ', i_gal)

        gal_model = None
        st_model = None

        if galaxy_model == "Gaussian":
            tot_mag = np.random.choice(cat)
            sed = galsim.SED('CWW_E_ext.sed', 'A', 'flambda')
            sed = sed.withMagnitude(tot_mag, bpass)
            flux = sed.calculateFlux(bpass)
            gal_model = galsim.Gaussian(
                half_light_radius=hlr, flux=1.
            )  # needs to normalize the flux before multiplying by sed. For bdf, there are bulge, disk, knots fractions to sum to 1.
            ## making galaxy sed
            #knots = galsim.RandomKnots(10, half_light_radius=1.3, flux=100)
            #knots = make_sed_model(galsim.ChromaticObject(knots), galaxy_sed_n, filter_, bpass)
            #gal_model = galsim.Add([gal_model, knots])
            gal_model = sed * gal_model
            ## shearing
            if i_gal % 2 == 0:
                gal_model = gal_model.shear(g1=0.02, g2=0)
                g1 = 0.02
                g2 = 0
            else:
                gal_model = gal_model.shear(g1=-0.02, g2=0)
                g1 = -0.02
                g2 = 0
        elif galaxy_model == "exponential":
            tot_mag = np.random.choice(cat)
            sed = galsim.SED('CWW_E_ext.sed', 'A', 'flambda')
            sed = sed.withMagnitude(tot_mag, bpass)
            flux = sed.calculateFlux(bpass)
            gal_model = galsim.Exponential(half_light_radius=hlr, flux=1.)
            ## making galaxy sed ## random knots should be used for bdf model
            #knots = galsim.RandomKnots(10, half_light_radius=1.3, flux=1.)
            #knots = make_sed_model(galsim.ChromaticObject(knots), galaxy_sed_n, filter_, bpass)
            #gal_model = galsim.Add([gal_model, knots])
            gal_model = sed * gal_model
            ## shearing
            if i_gal % 2 == 0:
                gal_model = gal_model.shear(g1=0, g2=0.02)
                g1 = 0
                g2 = 0.02
            else:
                gal_model = gal_model.shear(g1=0, g2=-0.02)
                g1 = 0
                g2 = -0.02

        gal_model = gal_model * galsim.wfirst.collecting_area * galsim.wfirst.exptime

        flux_ = gal_model.calculateFlux(bpass)
        #mag_ = gal_model.calculateMagnitude(bpass)
        # This makes the object achromatic, which speeds up drawing and convolution
        gal_model = gal_model.evaluateAtWavelength(bpass.effective_wavelength)
        # Reassign correct flux
        gal_model = gal_model.withFlux(flux_)
        gal_model = galsim.Convolve(gal_model, PSF)

        st_model = galsim.DeltaFunction(flux=1.)
        st_model = st_model.evaluateAtWavelength(bpass.effective_wavelength)
        # reassign correct flux
        starflux = 1.
        st_model = st_model.withFlux(starflux)
        st_model = galsim.Convolve(st_model, PSF)

        stamp_size_factor = old_div(
            int(gal_model.getGoodImageSize(wfirst.pixel_scale)), stamp_size)
        if stamp_size_factor == 0:
            stamp_size_factor = 1

        # Galsim world coordinate object (ra,dec)
        """
        ra = cat[i_gal]['ra']
        dec = cat[i_gal]['dec']
        int_e1 = cat[i_gal]['int_e1']
        int_e2 = cat[i_gal]['int_e2']
        radec = galsim.CelestialCoord(ra*galsim.radians, dec*galsim.radians)
        # Galsim image coordinate object 
        xy = wcs.toImage(radec)
        # Galsim integer image coordinate object 
        xyI = galsim.PositionI(int(xy.x),int(xy.y))
        """
        #xyI = galsim.PositionI(int(stamp_size_factor*stamp_size), int(stamp_size_factor*stamp_size))
        #b = galsim.BoundsI( xmin=1,
        #                    xmax=xyI.x,
        #                    ymin=1,
        #                    ymax=xyI.y)
        #print(xyI.x, int(stamp_size_factor*stamp_size), xyI.x-old_div(int(stamp_size_factor*stamp_size),2)+1)
        #print(b)
        # Create postage stamp for galaxy
        #print("galaxy ", i_gal, ra, dec, int_e1, int_e2)

        ## translational dither check (multiple exposures)
        """
        position_angle1=20*random_dir() #degrees
        position_angle2=position_angle1 #degrees
        wcs1, sky_level1 = get_wcs(dither_i, use_SCA, filter_, stamp_size, position_angle1)
        wcs2, sky_level2 = get_wcs(dither_i, use_SCA, filter_, stamp_size, position_angle2)
        wcs=[wcs1, wcs2]
        sky_level=[sky_level1, sky_level2]
        """

        sca_center = [
            wcs[0].toWorld(
                galsim.PositionI(old_div(wfirst.n_pix, 2),
                                 old_div(wfirst.n_pix, 2))), wcs[1].toWorld(
                                     galsim.PositionI(old_div(wfirst.n_pix, 2),
                                                      old_div(wfirst.n_pix,
                                                              2)))
        ]
        gal_radec = sca_center[0]
        thetas = [position_angle1 * (np.pi / 180) * galsim.radians]
        offsets = []
        gals = []
        psfs = []
        skys = []
        for i in range(2):
            gal_stamp = None
            psf_stamp = None
            xy = wcs[i].toImage(gal_radec)  # galaxy position
            xyI = galsim.PositionI(int(xy.x), int(xy.y))
            b = galsim.BoundsI(
                xmin=xyI.x - old_div(int(stamp_size_factor * stamp_size), 2) +
                1,
                ymin=xyI.y - old_div(int(stamp_size_factor * stamp_size), 2) +
                1,
                xmax=xyI.x + old_div(int(stamp_size_factor * stamp_size), 2),
                ymax=xyI.y + old_div(int(stamp_size_factor * stamp_size), 2))
            #---------------------------------------#
            # if the image does not use a real wcs. #
            #---------------------------------------#
            #b = galsim.BoundsI( xmin=1,
            #                    xmax=int(stamp_size_factor*stamp_size),
            #                    ymin=1,
            #                    ymax=int(stamp_size_factor*stamp_size))
            gal_stamp = galsim.Image(b, wcs=wcs[i])  #scale=wfirst.pixel_scale)
            psf_stamp = galsim.Image(b, wcs=wcs[i])  #scale=wfirst.pixel_scale)

            ## translational dithering test
            #dx = 0 #random_dir() - 0.5
            #dy = 0 #random_dir() - 0.5
            #offset = np.array((dx,dy))

            offset = xy - gal_stamp.true_center  # original galaxy position - stamp center
            gal_model.drawImage(image=gal_stamp, offset=offset)
            st_model.drawImage(image=psf_stamp, offset=offset)

            sigma = wfirst.read_noise
            read_noise = galsim.GaussianNoise(rng, sigma=sigma)

            im, sky_image = add_background(gal_stamp,
                                           sky_level[i],
                                           b,
                                           thermal_backgrounds=None,
                                           filter_='H158',
                                           phot=False)
            #im.addNoise(read_noise)
            gal_stamp = add_poisson_noise(rng,
                                          im,
                                          sky_image=sky_image,
                                          phot=False)
            #sky_image = add_poisson_noise(rng, sky_image, sky_image=sky_image, phot=False)
            gal_stamp -= sky_image

            # set a simple jacobian to the stamps before sending them to ngmix
            # old center of the stamp
            origin_x = gal_stamp.origin.x
            origin_y = gal_stamp.origin.y
            gal_stamp.setOrigin(0, 0)
            psf_stamp.setOrigin(0, 0)
            new_pos = galsim.PositionD(xy.x - origin_x, xy.y - origin_y)
            wcs_transf = gal_stamp.wcs.affine(image_pos=new_pos)
            new_wcs = galsim.JacobianWCS(wcs_transf.dudx, wcs_transf.dudy,
                                         wcs_transf.dvdx, wcs_transf.dvdy)
            gal_stamp.wcs = new_wcs
            psf_stamp.wcs = new_wcs

            offsets.append(offset)
            gals.append(gal_stamp)
            psfs.append(psf_stamp)
            skys.append(sky_image)
        print(gals)
        res_tot = get_coadd_shape(cat, gals, psfs, offsets, skys, i_gal, hlr,
                                  res_tot, g1, g2, shape)
    print(res_tot)
    ## send and receive objects from one processor to others
    if rank != 0:
        # send res_tot to rank 0 processor
        comm.send(res_tot, dest=0)
    else:
        for i in range(comm.size):
            if i == 0:
                continue
            # for other processors, receive res_tot.
            res_ = comm.recv(source=i)
            for j in range(len(res_tot)):
                for col in res_tot[j].dtype.names:
                    res_tot[j][col] += res_[j][col]

    if rank == 0:
        dirr = output_name
        for i in range(len(res_tot)):
            fio.write(dirr + '_sim_' + str(i) + '.fits', res_tot[i])

    if rank == 0:
        bias = residual_bias(res_tot, shape)
        #final = residual_bias_correction(res_tot,R11,R22,R12,R21)
        print(time.time() - t0)

    return None