def test_ObscAnnulus(): rng = np.random.default_rng(57) size = 10_000 for i in range(100): cx = rng.normal(0.0, 1.0) cy = rng.normal(0.0, 1.0) inner = rng.uniform(0.5, 1.5) outer = rng.uniform(1.6, 1.9) obsc = batoid.ObscAnnulus(inner, outer, cx, cy) for i in range(100): x = rng.normal(0.0, 1.0) y = rng.normal(0.0, 1.0) assert obsc.contains( x, y) == (inner <= np.hypot(x - cx, y - cy) < outer) x = rng.normal(0.0, 1.0, size=size) y = rng.normal(0.0, 1.0, size=size) r = np.hypot(x - cx, y - cy) np.testing.assert_array_equal(obsc.contains(x, y), (inner <= r) & (r < outer)) do_pickle(obsc) rv = batoid.RayVector(x, y, 0.0, 0.0, 0.0, 0.0) batoid.obscure(obsc, rv) np.testing.assert_array_equal(obsc.contains(x, y), rv.vignetted)
def test_ne(): objs = [ batoid.ObscCircle(1.0), batoid.ObscCircle(2.0), batoid.ObscCircle(1.0, 0.1, 0.1), batoid.ObscAnnulus(0.0, 1.0), batoid.ObscAnnulus(0.1, 1.0), batoid.ObscAnnulus(0.1, 1.0, 0.1, 0.1), batoid.ObscRectangle(1.0, 2.0), batoid.ObscRectangle(1.0, 2.0, 0.1, 0.1), batoid.ObscRectangle(1.0, 2.0, 0.1, 0.1, 1.0), batoid.ObscRay(1.0, 2.0), batoid.ObscRay(1.0, 2.0, 0.1, 0.1), batoid.ObscNegation(batoid.ObscCircle(1.0)), batoid.ObscPolygon([0,1,1,0],[0,0,1,1]), batoid.ObscUnion([batoid.ObscCircle(1.0)]), batoid.ObscUnion([ batoid.ObscCircle(1.0), batoid.ObscCircle(2.0) ]), batoid.ObscUnion([ batoid.ObscCircle(1.0), batoid.ObscCircle(2.2) ]), batoid.ObscUnion([ batoid.ObscCircle(1.0), batoid.ObscCircle(2.2), batoid.ObscAnnulus(1.0, 2.0) ]), batoid.ObscIntersection([batoid.ObscCircle(1.0)]), batoid.ObscIntersection([ batoid.ObscCircle(1.0), batoid.ObscCircle(2.0) ]), batoid.ObscIntersection([ batoid.ObscCircle(1.0), batoid.ObscCircle(2.2) ]), batoid.ObscIntersection([ batoid.ObscCircle(1.0), batoid.ObscCircle(2.2), batoid.ObscAnnulus(1.0, 2.0) ]), ] all_obj_diff(objs)
def test_ObscAnnulus(): import random random.seed(57) for i in range(100): cx = random.gauss(0.0, 1.0) cy = random.gauss(0.0, 1.0) inner = random.uniform(0.5, 1.5) outer = random.uniform(1.6, 1.9) obsc = batoid.ObscAnnulus(inner, outer, cx, cy) for i in range(100): x = random.gauss(0.0, 1.0) y = random.gauss(0.0, 1.0) assert obsc.contains( x, y) == (inner <= np.hypot(x - cx, y - cy) < outer) do_pickle(obsc)
def test_zernikeGQ(): if __name__ == '__main__': nx = 1024 rings = 10 tol = 1e-4 else: nx = 128 rings = 5 tol = 1e-3 telescope = batoid.Optic.fromYaml("LSST_r.yaml") telescope.clearObscuration() telescope['LSST.M1'].obscuration = batoid.ObscNegation( batoid.ObscCircle(4.18)) zSquare = batoid.analysis.zernike(telescope, 0.0, 0.0, 625e-9, nx=nx, jmax=28, reference='chief') zGQ = batoid.analysis.zernikeGQ(telescope, 0.0, 0.0, 625e-9, rings=rings, jmax=28, reference='chief') np.testing.assert_allclose(zSquare, zGQ, rtol=0, atol=tol) # Repeat with annular Zernikes telescope['LSST.M1'].obscuration = batoid.ObscNegation( batoid.ObscAnnulus(0.61 * 4.18, 4.18)) zSquare = batoid.analysis.zernike(telescope, 0.0, 0.0, 625e-9, nx=nx, jmax=28, reference='chief', eps=0.61) zGQ = batoid.analysis.zernikeGQ(telescope, 0.0, 0.0, 625e-9, rings=rings, jmax=28, reference='chief', eps=0.61) np.testing.assert_allclose(zSquare, zGQ, rtol=0, atol=tol) # Try off-axis zSquare = batoid.analysis.zernike(telescope, np.deg2rad(0.2), np.deg2rad(0.1), 625e-9, nx=nx, jmax=28, reference='chief', eps=0.61) zGQ = batoid.analysis.zernikeGQ(telescope, np.deg2rad(0.2), np.deg2rad(0.1), 625e-9, rings=rings, jmax=28, reference='chief', eps=0.61) np.testing.assert_allclose(zSquare, zGQ, rtol=0, atol=tol)
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()