Example #1
0
def test_decam_psf():
    # Just testing that doesn't crash for the moment
    fn = os.path.join(batoid.datadir, "DECam", "DECam.yaml")
    config = yaml.load(open(fn))
    telescope = batoid.parse.parse_optic(config['opticalSystem'])

    stampSize = 1.0  # arcsec
    nx = 64
    focalLength = 10.0  # guess

    if __name__ == '__main__':
        thetas = [0.0, 1800.0, 3960.0]  # arcsec
    else:
        thetas = [3960.0]
    for theta in thetas:
        print(theta / 3600.0)
        dirCos = batoid.utils.gnomicToDirCos(0.0, theta / 206265)
        rays = batoid.circularGrid(10.0, 1.95, 0.5, dirCos[0], dirCos[1],
                                   -dirCos[2], 10, 100, 620e-9, 1.0,
                                   batoid.Air())
        telescope.traceInPlace(rays)
        rays.trimVignettedInPlace()
        xs = rays.x - np.mean(rays.x)
        ys = rays.y - np.mean(rays.y)

        xs *= 206265 / focalLength  # meters to arcsec
        ys *= 206265 / focalLength

        # Need to add half-pixel offset
        xs += stampSize / nx / 2
        ys += stampSize / nx / 2

        dx = stampSize / nx * focalLength / 206265  # meters

        psf = batoid.huygensPSF(telescope,
                                0.0,
                                theta / 206265,
                                620e-9,
                                nx=nx,
                                dx=dx,
                                dy=dx)

        if __name__ == '__main__':
            import matplotlib.pyplot as plt
            fig = plt.figure(figsize=(12, 8))
            ax = fig.add_subplot(111)
            ax.imshow(psf.array, extent=np.r_[-1, 1, -1, 1] * stampSize / 2)
            ax.scatter(xs, ys, s=5, c='r', alpha=0.5)
            ax.set_title("DECam PSF field={:5.2f}".format(theta / 3600.0))
            ax.set_xlabel("arcsec")
            ax.set_ylabel("arcsec")

            fig.tight_layout()
            plt.show()
Example #2
0
def test_hsc_psf():
    # Just testing that doesn't crash for the moment
    telescope = batoid.Optic.fromYaml("HSC.yaml")

    stampSize = 0.75  # arcsec
    nx = 64
    focalLength = 15.0  # guess

    if __name__ == '__main__':
        thetas = [0.0, 1350.0, 2700.0]  # arcsec
    else:
        thetas = [2700.0]
    for theta in thetas:
        print(theta / 3600.0)
        dirCos = batoid.utils.gnomonicToDirCos(0.0, theta / 206265)
        rays = batoid.circularGrid(20.0, 4.1, 0.9, dirCos[0], dirCos[1],
                                   dirCos[2], 10, 100, 620e-9, 1.0,
                                   batoid.ConstMedium(1.0))
        telescope.traceInPlace(rays)
        rays.trimVignettedInPlace()
        xs = rays.x - np.mean(rays.x)
        ys = rays.y - np.mean(rays.y)

        xs *= 206265 / focalLength  # meters to arcsec
        ys *= 206265 / focalLength

        # Need to add half-pixel offset
        xs += stampSize / nx / 2
        ys += stampSize / nx / 2

        dx = stampSize / nx * focalLength / 206265  # meters

        psf = batoid.huygensPSF(telescope,
                                0.0,
                                theta / 206265,
                                620e-9,
                                nx=nx,
                                dx=dx,
                                dy=dx)

        if __name__ == '__main__':
            import matplotlib.pyplot as plt
            fig = plt.figure(figsize=(12, 8))
            ax = fig.add_subplot(111)
            ax.imshow(psf.array, extent=np.r_[-1, 1, -1, 1] * stampSize / 2)
            ax.scatter(xs, ys, s=5, c='r', alpha=0.5)
            ax.set_title("HSC PSF field={:5.2f}".format(theta / 3600.0))
            ax.set_xlabel("arcsec")
            ax.set_ylabel("arcsec")

            fig.tight_layout()
            plt.show()
Example #3
0
def test_HSC_huygensPSF():
    fn = os.path.join(directory, "testdata", "HSC_huygensPSF.txt")
    with open(fn) as f:
        Zarr = np.loadtxt(f, skiprows=21)
    Zarr = Zarr[::-1]  # Need to invert, probably just a Zemax convention...

    telescope = batoid.Optic.fromYaml("HSC_no_obsc.yaml")

    thx = np.deg2rad(0.0)
    thy = np.deg2rad(0.75)
    wavelength = 750e-9
    nx = 512
    dx = 0.25e-6
    print("computing Huygens PSF")
    hPSF = batoid.huygensPSF(telescope,
                             thx,
                             thy,
                             wavelength,
                             nx=nx,
                             projection='zemax',
                             dx=dx,
                             nxOut=256)
    print("Done")

    # Normalize images
    Zarr /= np.sum(Zarr)
    hPSF.array /= np.sum(hPSF.array)
    Zmax = np.max(Zarr)
    Zarr /= Zmax
    hPSF.array /= Zmax

    # Use GalSim InterpolateImage to align and subtract
    ii = galsim.InterpolatedImage(galsim.Image(hPSF.array, scale=0.25),
                                  normalization='sb')

    # Now setup an optimizer to fit for x/y shift
    def resid(params):
        p = params.valuesdict()
        model = ii.shift(p['dx'], p['dy']) * np.exp(p['dlogflux'])
        img = model.drawImage(method='sb', scale=0.25, nx=256, ny=256)
        r = (img.array - Zarr).ravel()
        return r

    params = lmfit.Parameters()
    params.add('dx', value=0.0)
    params.add('dy', value=0.0)
    params.add('dlogflux', value=0.0)
    print("Aligning")
    opt = lmfit.minimize(resid, params)
    print("Done")

    p = opt.params.valuesdict()
    model = ii.shift(p['dx'], p['dy']) * np.exp(p['dlogflux'])
    optImg = model.drawImage(method='sb', scale=0.25, nx=256, ny=256)

    np.testing.assert_allclose(Zarr, optImg.array, rtol=0, atol=3e-2)
    Zmom = galsim.hsm.FindAdaptiveMom(galsim.Image(Zarr, scale=0.25))
    bmom = galsim.hsm.FindAdaptiveMom(optImg)
    np.testing.assert_allclose(Zmom.observed_shape.g1,
                               bmom.observed_shape.g1,
                               rtol=0,
                               atol=0.01)
    np.testing.assert_allclose(Zmom.observed_shape.g2,
                               bmom.observed_shape.g2,
                               rtol=0,
                               atol=1e-7)
    np.testing.assert_allclose(Zmom.moments_sigma,
                               bmom.moments_sigma,
                               rtol=0,
                               atol=0.1)
Example #4
0
def test_HSC_huygensPSF():
    fn = os.path.join(directory, "testdata", "HSC_huygensPSF.txt")
    with open(fn) as f:
        Zarr = np.loadtxt(f, skiprows=21)
    Zarr = Zarr[::-1]  # Need to invert, probably just a Zemax convention...

    telescope = batoid.Optic.fromYaml("HSC_no_obsc.yaml")

    thx = np.deg2rad(0.0)
    thy = np.deg2rad(0.75)
    wavelength = 750e-9
    nx = 128
    dx = 0.25e-6
    print("computing Huygens PSF")
    hPSF = batoid.huygensPSF(
        telescope,
        thx, thy, projection='zemax',
        wavelength=wavelength,
        nx=nx, dx=dx, nxOut=256,
        reference='mean'
    )
    print("Done")

    # Normalize images
    Zarr /= np.sum(Zarr)
    hPSF.array /= np.sum(hPSF.array)
    Zmax = np.max(Zarr)
    Zarr /= Zmax
    hPSF.array /= Zmax

    # Use GalSim InterpolateImage to align and subtract
    ii = galsim.InterpolatedImage(
        galsim.Image(hPSF.array, scale=0.25),
        normalization='sb'
    )

    # Now setup an optimizer to fit for x/y shift
    def modelimg(params, ii=ii):
        dx, dy, dlogflux = params
        model = ii.shift(dx, dy)*np.exp(dlogflux)
        return model.drawImage(method='sb', scale=0.25, nx=256, ny=256)

    def resid(params, ii=ii, Zarr=Zarr):
        img = modelimg(params, ii=ii)
        r = (img.array - Zarr).ravel()
        return r

    kwargs = dict(ii=ii, Zarr=Zarr)
    print("Aligning")
    result = least_squares(resid, np.array([0.0, 0.0, 0.0]), kwargs=kwargs)
    optImg = modelimg(result.x, ii=ii)
    print("Done")

    np.testing.assert_allclose(Zarr, optImg.array, rtol=0, atol=3e-2)
    Zmom = galsim.hsm.FindAdaptiveMom(galsim.Image(Zarr, scale=0.25))
    bmom = galsim.hsm.FindAdaptiveMom(optImg)
    np.testing.assert_allclose(
        Zmom.observed_shape.g1,
        bmom.observed_shape.g1,
        rtol=0, atol=0.01
    )
    np.testing.assert_allclose(
        Zmom.observed_shape.g2,
        bmom.observed_shape.g2,
        rtol=0, atol=1e-7
    )
    np.testing.assert_allclose(
        Zmom.moments_sigma,
        bmom.moments_sigma,
        rtol=0, atol=0.1
    )
Example #5
0
def test_LSST_huygensPSF(plot=False):
    thxs = [0.0, 0.0, 0.0, 1.176]
    thys = [0.0, 1.225, 1.75, 1.176]
    fns = ["LSST_hpsf_0.0_0.0.txt",
           "LSST_hpsf_0.0_1.225.txt",
           "LSST_hpsf_0.0_1.75.txt",
           "LSST_hpsf_1.176_1.176.txt"]
    if __name__ != "__main__":
        thxs = thxs[2:3]
        thys = thys[2:3]
        fns = fns[2:3]
    for thx, thy, fn in zip(thxs, thys, fns):
        fn = os.path.join(directory, "testdata", fn)
        with open(fn, encoding='utf-16-le') as f:
            Zpsf = np.loadtxt(f, skiprows=21)
        Zpsf = Zpsf[::-1]  # Need to invert, probably just a Zemax convention...
        Zpsf /= np.max(Zpsf)

        telescope = batoid.Optic.fromYaml("LSST_g_500.yaml")

        thx = np.deg2rad(thx)
        thy = np.deg2rad(thy)
        wavelength = 500e-9

        bpsf = batoid.huygensPSF(
            telescope, thx, thy, wavelength, nx=128,
            # telescope, thx, thy, wavelength, nx=1024,
            reference='chief', projection='zemax',
            dx=0.289e-6, nxOut=64
        )
        bpsf.array /= np.max(bpsf.array)

        # Use GalSim InterpolateImage to align and subtract
        ii = galsim.InterpolatedImage(
            galsim.Image(bpsf.array, scale=1.0),
            normalization='sb'
        )

        # Now setup an optimizer to fit for x/y shift
        def modelimg(params, ii=ii):
            dx, dy, dlogflux = params
            model = ii.shift(dx, dy)*np.exp(dlogflux)
            return model.drawImage(method='sb', scale=1.0, nx=64, ny=64)

        def resid(params, ii=ii, Zpsf=Zpsf):
            img = modelimg(params, ii=ii)
            r = (img.array - Zpsf).ravel()
            return r

        kwargs = dict(ii=ii, Zpsf=Zpsf)
        print("Aligning")
        result = least_squares(resid, np.array([0.0, 0.0, 0.0]), kwargs=kwargs)
        optImg = modelimg(result.x, ii=ii)
        print("Done")

        if plot:
            import matplotlib.pyplot as plt
            fig, axes = plt.subplots(ncols=3, figsize=(10,3))
            i0 = axes[0].imshow(optImg.array)
            i1 = axes[1].imshow(Zpsf)
            i2 = axes[2].imshow(optImg.array-Zpsf)
            plt.colorbar(i0, ax=axes[0])
            plt.colorbar(i1, ax=axes[1])
            plt.colorbar(i2, ax=axes[2])
            plt.tight_layout()
            plt.show()

            if thy not in [0.0, 1.176]:
                fig, ax = plt.subplots(figsize=(6, 4))
                ax.plot(optImg.array[:,32], c='g')
                ax.plot(Zpsf[:,32], c='b')
                ax.plot((optImg.array-Zpsf)[:,32], c='r')
                plt.show()
Example #6
0
def test_huygens_paraboloid(plot=False):
    if __name__ == '__main__':
        obscurations = [0.0, 0.25, 0.5, 0.75]
    else:
        obscurations = [0.25]

    print("Testing HuygensPSF")
    # Just do a single parabolic mirror test
    focalLength = 1.5
    diam = 0.3
    R = 2*focalLength
    for obscuration in obscurations:
        telescope = batoid.CompoundOptic(
            items = [
                batoid.Mirror(
                    batoid.Paraboloid(R),
                    name="Mirror",
                    obscuration=batoid.ObscNegation(
                        batoid.ObscAnnulus(0.5*obscuration*diam, 0.5*diam)
                    )
                ),
                batoid.Detector(
                    batoid.Plane(),
                    name="detector",
                    coordSys=batoid.CoordSys(origin=[0, 0, focalLength])
                )
            ],
            pupilSize=diam,
            backDist=10.0,
            inMedium=batoid.ConstMedium(1.0)
        )

        airy_size = 1.22*500e-9/diam * 206265
        print()
        print("Airy radius: {:4.2f} arcsec".format(airy_size))

        # Start with the HuygensPSF
        npix = 96
        size = 3.0 # arcsec
        dsize = size/npix
        dsize_X = dsize*focalLength/206265  # meters

        psf = batoid.huygensPSF(
            telescope, 0.0, 0.0, 500e-9,
            nx=npix, dx=dsize_X, dy=dsize_X
        )
        psf.array /= np.max(psf.array)

        scale = np.sqrt(np.abs(np.linalg.det(psf.primitiveVectors)))  # meters
        scale *= 206265/focalLength  # arcsec
        obj = galsim.Airy(lam=500, diam=diam, obscuration=obscuration)
        # Need to shift by half a pixel.
        obj = obj.shift(scale/2, scale/2)
        im = obj.drawImage(nx=npix, ny=npix, scale=scale, method='no_pixel')
        arr = im.array/np.max(im.array)
        gs_mom = galsim.hsm.FindAdaptiveMom(im)

        psfim = galsim.Image(psf.array)
        jt_mom = galsim.hsm.FindAdaptiveMom(psfim)

        print("GalSim shape: ", gs_mom.observed_shape)
        print("batoid shape: ", jt_mom.observed_shape)
        print("GalSim centroid:  ", gs_mom.moments_centroid)
        print("batoid centroid:  ", jt_mom.moments_centroid)
        print("GalSim size: ", gs_mom.moments_sigma)
        print("batoid size: ", jt_mom.moments_sigma)
        print("GalSim rho4: ", gs_mom.moments_rho4)
        print("batoid rho4: ", jt_mom.moments_rho4)

        np.testing.assert_allclose(
            gs_mom.observed_shape.g1,
            jt_mom.observed_shape.g1,
            rtol=0.0, atol=3e-3
        )
        np.testing.assert_allclose(
            gs_mom.observed_shape.g2,
            jt_mom.observed_shape.g2,
            rtol=0.0, atol=3e-3
        )
        np.testing.assert_allclose(
            gs_mom.moments_centroid.x,
            jt_mom.moments_centroid.x,
            rtol=0.0, atol=1e-9
        )
        np.testing.assert_allclose(
            gs_mom.moments_centroid.y,
            jt_mom.moments_centroid.y,
            rtol=0.0, atol=1e-9
        )
        np.testing.assert_allclose(
            gs_mom.moments_sigma,
            jt_mom.moments_sigma,
            rtol=1e-2  # why not better?!
        )
        np.testing.assert_allclose(
            gs_mom.moments_rho4,
            jt_mom.moments_rho4,
            rtol=2e-2
        )

        if plot:
            size = scale*npix
            import matplotlib.pyplot as plt
            fig = plt.figure(figsize=(15, 4))
            ax1 = fig.add_subplot(131)
            im1 = ax1.imshow(
                np.log10(arr),
                extent=np.r_[-1,1,-1,1]*size/2,
                vmin=-7, vmax=0
            )
            plt.colorbar(im1, ax=ax1, label=r'$\log_{10}$ flux')
            ax1.set_title('GalSim')
            ax1.set_xlabel("arcsec")
            ax1.set_ylabel("arcsec")

            sizeX = dsize_X * npix * 1e6  # microns
            ax2 = fig.add_subplot(132)
            im2 = ax2.imshow(
                np.log10(psf.array),
                extent=np.r_[-1,1,-1,1]*sizeX/2,
                vmin=-7, vmax=0
            )
            plt.colorbar(im2, ax=ax2, label=r'$\log_{10}$ flux')
            ax2.set_title('batoid')
            ax2.set_xlabel(r"$\mu m$")
            ax2.set_ylabel(r"$\mu m$")

            ax3 = fig.add_subplot(133)
            im3 = ax3.imshow(
                (psf.array-arr)/np.max(arr),
                vmin=-0.01, vmax=0.01,
                cmap='seismic'
            )
            plt.colorbar(im3, ax=ax3, label="(batoid-GalSim)/max(GalSim)")
            ax3.set_title('resid')
            ax3.set_xlabel(r"$\mu m$")
            ax3.set_ylabel(r"$\mu m$")

            fig.tight_layout()

            plt.show()
Example #7
0
def test_huygensPSF():
    telescope = batoid.Optic.fromYaml("LSST_r.yaml")

    # Test that we can infer dy from dx properly
    psf1 = batoid.huygensPSF(telescope,
                             np.deg2rad(0.1),
                             np.deg2rad(0.1),
                             620e-9,
                             nx=64,
                             nxOut=32,
                             dx=10e-6,
                             reference='mean')
    psf2 = batoid.huygensPSF(telescope,
                             np.deg2rad(0.1),
                             np.deg2rad(0.1),
                             620e-9,
                             nx=64,
                             nxOut=32,
                             dx=10e-6,
                             dy=10e-6,
                             reference='mean')
    assert np.array_equal(psf1.primitiveVectors, psf2.primitiveVectors)
    np.testing.assert_allclose(psf1.array, psf2.array, rtol=1e-14, atol=1e-15)

    # Test vector vs scalar dx,dy
    psf1 = batoid.huygensPSF(telescope,
                             np.deg2rad(0.1),
                             np.deg2rad(0.1),
                             620e-9,
                             nx=64,
                             nxOut=32,
                             dx=[10e-6, 0],
                             dy=[0, 11e-6],
                             reference='mean')
    psf2 = batoid.huygensPSF(telescope,
                             np.deg2rad(0.1),
                             np.deg2rad(0.1),
                             620e-9,
                             nx=64,
                             nxOut=32,
                             dx=10e-6,
                             dy=11e-6,
                             reference='mean')
    assert np.array_equal(psf1.primitiveVectors, psf2.primitiveVectors)
    np.testing.assert_allclose(psf1.array, psf2.array, rtol=1e-14, atol=1e-15)

    # Should still work with reference = 'chief'
    psf3 = batoid.huygensPSF(telescope,
                             np.deg2rad(0.1),
                             np.deg2rad(0.1),
                             620e-9,
                             nx=64,
                             nxOut=32,
                             dx=[10e-6, 0],
                             dy=[0, 11e-6],
                             reference='chief')
    psf4 = batoid.huygensPSF(telescope,
                             np.deg2rad(0.1),
                             np.deg2rad(0.1),
                             620e-9,
                             nx=64,
                             nxOut=32,
                             dx=10e-6,
                             dy=11e-6,
                             reference='chief')
    assert np.array_equal(psf1.primitiveVectors, psf3.primitiveVectors)
    assert not np.allclose(psf1.array, psf3.array, rtol=1e-14, atol=1e-15)

    assert np.array_equal(psf3.primitiveVectors, psf4.primitiveVectors)
    np.testing.assert_allclose(psf3.array, psf4.array, rtol=1e-14, atol=1e-15)

    # And just cover nx odd
    batoid.huygensPSF(
        telescope,
        np.deg2rad(0.1),
        np.deg2rad(0.1),
        620e-9,
        nx=63,
    )